001/** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.apache.camel.spring.spi; 018 019import java.util.Properties; 020 021import org.apache.camel.CamelContext; 022import org.apache.camel.component.properties.AugmentedPropertyNameAwarePropertiesParser; 023import org.apache.camel.component.properties.PropertiesParser; 024import org.apache.camel.component.properties.PropertiesResolver; 025import org.springframework.beans.BeansException; 026import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 027import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; 028import org.springframework.core.Constants; 029import org.springframework.util.PropertyPlaceholderHelper; 030 031/** 032 * A {@link PropertyPlaceholderConfigurer} that bridges Camel's <a href="http://camel.apache.org/using-propertyplaceholder.html"> 033 * property placeholder</a> with the Spring property placeholder mechanism. 034 */ 035public class BridgePropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer implements PropertiesResolver, AugmentedPropertyNameAwarePropertiesParser { 036 037 // NOTE: this class must be in the spi package as if its in the root package, then Spring fails to parse the XML 038 // files due some weird spring issue. But that is okay as having this class in the spi package is fine anyway. 039 040 private final Properties properties = new Properties(); 041 private PropertiesResolver resolver; 042 private PropertiesParser parser; 043 private String id; 044 private PropertyPlaceholderHelper helper; 045 046 // to support both Spring 3.0 / 3.1+ we need to keep track of these as they have private modified in Spring 3.0 047 private String configuredPlaceholderPrefix; 048 private String configuredPlaceholderSuffix; 049 private String configuredValueSeparator; 050 private Boolean configuredIgnoreUnresolvablePlaceholders; 051 private int systemPropertiesMode = SYSTEM_PROPERTIES_MODE_FALLBACK; 052 053 @Override 054 protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException { 055 super.processProperties(beanFactoryToProcess, props); 056 // store all the spring properties so we can refer to them later 057 properties.putAll(props); 058 // create helper 059 helper = new PropertyPlaceholderHelper( 060 configuredPlaceholderPrefix != null ? configuredPlaceholderPrefix : DEFAULT_PLACEHOLDER_PREFIX, 061 configuredPlaceholderSuffix != null ? configuredPlaceholderSuffix : DEFAULT_PLACEHOLDER_SUFFIX, 062 configuredValueSeparator != null ? configuredValueSeparator : DEFAULT_VALUE_SEPARATOR, 063 configuredIgnoreUnresolvablePlaceholders != null ? configuredIgnoreUnresolvablePlaceholders : false); 064 } 065 066 @Override 067 public void setBeanName(String beanName) { 068 this.id = beanName; 069 super.setBeanName(beanName); 070 } 071 072 @Override 073 public void setSystemPropertiesModeName(String constantName) throws IllegalArgumentException { 074 super.setSystemPropertiesModeName(constantName); 075 Constants constants = new Constants(PropertyPlaceholderConfigurer.class); 076 this.systemPropertiesMode = constants.asNumber(constantName).intValue(); 077 } 078 079 @Override 080 public void setSystemPropertiesMode(int systemPropertiesMode) { 081 super.setSystemPropertiesMode(systemPropertiesMode); 082 this.systemPropertiesMode = systemPropertiesMode; 083 } 084 085 @Override 086 public void setPlaceholderPrefix(String placeholderPrefix) { 087 super.setPlaceholderPrefix(placeholderPrefix); 088 this.configuredPlaceholderPrefix = placeholderPrefix; 089 } 090 091 @Override 092 public void setPlaceholderSuffix(String placeholderSuffix) { 093 super.setPlaceholderSuffix(placeholderSuffix); 094 this.configuredPlaceholderSuffix = placeholderSuffix; 095 } 096 097 @Override 098 public void setValueSeparator(String valueSeparator) { 099 super.setValueSeparator(valueSeparator); 100 this.configuredValueSeparator = valueSeparator; 101 } 102 103 @Override 104 public void setIgnoreUnresolvablePlaceholders(boolean ignoreUnresolvablePlaceholders) { 105 super.setIgnoreUnresolvablePlaceholders(ignoreUnresolvablePlaceholders); 106 this.configuredIgnoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders; 107 } 108 109 @Override 110 public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, String... uri) throws Exception { 111 // return the spring properties, if it 112 Properties answer = new Properties(); 113 for (String u : uri) { 114 String ref = "ref:" + id; 115 if (ref.equals(u)) { 116 answer.putAll(properties); 117 } else if (resolver != null) { 118 Properties p = resolver.resolveProperties(context, ignoreMissingLocation, u); 119 if (p != null) { 120 answer.putAll(p); 121 } 122 } 123 } 124 // must not return null 125 return answer; 126 } 127 128 @Override 129 public String parseUri(String text, Properties properties, String prefixToken, String suffixToken, 130 String propertyPrefix, String propertySuffix, boolean fallbackToUnaugmentedProperty) throws IllegalArgumentException { 131 132 // first let Camel parse the text as it may contain Camel placeholders 133 String answer; 134 if (parser instanceof AugmentedPropertyNameAwarePropertiesParser) { 135 answer = ((AugmentedPropertyNameAwarePropertiesParser) parser).parseUri(text, properties, prefixToken, suffixToken, 136 propertyPrefix, propertySuffix, fallbackToUnaugmentedProperty); 137 } else { 138 answer = parser.parseUri(text, properties, prefixToken, suffixToken); 139 } 140 141 // then let Spring parse it to resolve any Spring placeholders 142 if (answer != null) { 143 answer = springResolvePlaceholders(answer, properties); 144 } else { 145 answer = springResolvePlaceholders(text, properties); 146 } 147 return answer; 148 } 149 150 @Override 151 public String parseUri(String text, Properties properties, String prefixToken, String suffixToken) throws IllegalArgumentException { 152 String answer = parser.parseUri(text, properties, prefixToken, suffixToken); 153 if (answer != null) { 154 answer = springResolvePlaceholders(answer, properties); 155 } else { 156 answer = springResolvePlaceholders(text, properties); 157 } 158 return answer; 159 } 160 161 @Override 162 public String parseProperty(String key, String value, Properties properties) { 163 String answer = parser.parseProperty(key, value, properties); 164 if (answer != null) { 165 answer = springResolvePlaceholders(answer, properties); 166 } else { 167 answer = springResolvePlaceholders(value, properties); 168 } 169 return answer; 170 } 171 172 /** 173 * Resolves the placeholders using Spring's property placeholder functionality. 174 * 175 * @param text the text which may contain spring placeholders 176 * @param properties the properties 177 * @return the parsed text with replaced placeholders, or the original text as is 178 */ 179 protected String springResolvePlaceholders(String text, Properties properties) { 180 return helper.replacePlaceholders(text, new BridgePropertyPlaceholderResolver(properties)); 181 } 182 183 public void setResolver(PropertiesResolver resolver) { 184 this.resolver = resolver; 185 } 186 187 public void setParser(PropertiesParser parser) { 188 this.parser = parser; 189 } 190 191 /** 192 * {@link PropertyPlaceholderHelper.PlaceholderResolver} to support using 193 */ 194 private class BridgePropertyPlaceholderResolver implements PropertyPlaceholderHelper.PlaceholderResolver { 195 196 private final Properties properties; 197 198 public BridgePropertyPlaceholderResolver(Properties properties) { 199 this.properties = properties; 200 } 201 202 public String resolvePlaceholder(String placeholderName) { 203 String propVal = null; 204 if (systemPropertiesMode == SYSTEM_PROPERTIES_MODE_OVERRIDE) { 205 propVal = resolveSystemProperty(placeholderName); 206 } 207 if (propVal == null) { 208 propVal = (String) properties.get(placeholderName); 209 } 210 if (propVal == null && systemPropertiesMode == SYSTEM_PROPERTIES_MODE_FALLBACK) { 211 propVal = resolveSystemProperty(placeholderName); 212 } 213 return propVal; 214 } 215 } 216 217 218}