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.Collections; 020import java.util.List; 021import java.util.Properties; 022 023import org.apache.camel.CamelContext; 024import org.apache.camel.component.properties.AugmentedPropertyNameAwarePropertiesParser; 025import org.apache.camel.component.properties.PropertiesLocation; 026import org.apache.camel.component.properties.PropertiesParser; 027import org.apache.camel.component.properties.PropertiesResolver; 028import org.springframework.beans.BeansException; 029import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 030import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; 031import org.springframework.core.Constants; 032import org.springframework.util.PropertyPlaceholderHelper; 033 034/** 035 * A {@link PropertyPlaceholderConfigurer} that bridges Camel's <a href="http://camel.apache.org/using-propertyplaceholder.html"> 036 * property placeholder</a> with the Spring property placeholder mechanism. 037 */ 038public class BridgePropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer implements PropertiesResolver, AugmentedPropertyNameAwarePropertiesParser { 039 040 // NOTE: this class must be in the spi package as if its in the root package, then Spring fails to parse the XML 041 // files due some weird spring issue. But that is okay as having this class in the spi package is fine anyway. 042 043 private final Properties properties = new Properties(); 044 private PropertiesResolver resolver; 045 private PropertiesParser parser; 046 private String id; 047 private PropertyPlaceholderHelper helper; 048 049 // to support both Spring 3.0 / 3.1+ we need to keep track of these as they have private modified in Spring 3.0 050 private String configuredPlaceholderPrefix; 051 private String configuredPlaceholderSuffix; 052 private String configuredValueSeparator; 053 private Boolean configuredIgnoreUnresolvablePlaceholders; 054 private int systemPropertiesMode = SYSTEM_PROPERTIES_MODE_FALLBACK; 055 private Boolean ignoreResourceNotFound; 056 057 public int getSystemPropertiesMode() { 058 return systemPropertiesMode; 059 } 060 061 @Override 062 protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException { 063 super.processProperties(beanFactoryToProcess, props); 064 // store all the spring properties so we can refer to them later 065 properties.putAll(props); 066 // create helper 067 helper = new PropertyPlaceholderHelper( 068 configuredPlaceholderPrefix != null ? configuredPlaceholderPrefix : DEFAULT_PLACEHOLDER_PREFIX, 069 configuredPlaceholderSuffix != null ? configuredPlaceholderSuffix : DEFAULT_PLACEHOLDER_SUFFIX, 070 configuredValueSeparator != null ? configuredValueSeparator : DEFAULT_VALUE_SEPARATOR, 071 configuredIgnoreUnresolvablePlaceholders != null ? configuredIgnoreUnresolvablePlaceholders : false); 072 } 073 074 @Override 075 public void setBeanName(String beanName) { 076 this.id = beanName; 077 super.setBeanName(beanName); 078 } 079 080 @Override 081 public void setSystemPropertiesModeName(String constantName) throws IllegalArgumentException { 082 super.setSystemPropertiesModeName(constantName); 083 Constants constants = new Constants(PropertyPlaceholderConfigurer.class); 084 this.systemPropertiesMode = constants.asNumber(constantName).intValue(); 085 } 086 087 @Override 088 public void setSystemPropertiesMode(int systemPropertiesMode) { 089 super.setSystemPropertiesMode(systemPropertiesMode); 090 this.systemPropertiesMode = systemPropertiesMode; 091 } 092 093 @Override 094 public void setPlaceholderPrefix(String placeholderPrefix) { 095 super.setPlaceholderPrefix(placeholderPrefix); 096 this.configuredPlaceholderPrefix = placeholderPrefix; 097 } 098 099 @Override 100 public void setPlaceholderSuffix(String placeholderSuffix) { 101 super.setPlaceholderSuffix(placeholderSuffix); 102 this.configuredPlaceholderSuffix = placeholderSuffix; 103 } 104 105 @Override 106 public void setValueSeparator(String valueSeparator) { 107 super.setValueSeparator(valueSeparator); 108 this.configuredValueSeparator = valueSeparator; 109 } 110 111 @Override 112 public void setIgnoreUnresolvablePlaceholders(boolean ignoreUnresolvablePlaceholders) { 113 super.setIgnoreUnresolvablePlaceholders(ignoreUnresolvablePlaceholders); 114 this.configuredIgnoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders; 115 } 116 117 @Override 118 public void setIgnoreResourceNotFound(boolean ignoreResourceNotFound) { 119 super.setIgnoreResourceNotFound(ignoreResourceNotFound); 120 this.ignoreResourceNotFound = ignoreResourceNotFound; 121 } 122 123 @Override 124 protected String resolvePlaceholder(String placeholder, Properties props) { 125 String value = props.getProperty(placeholder); 126 if (parser != null) { 127 // Just apply the parser to the place holder value to avoid configuring the other placeholder configure twice for the inside and outside camel context 128 return parser.parseProperty(placeholder, value, props); 129 } else { 130 return value; 131 } 132 } 133 134 @Override 135 public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, List<PropertiesLocation> locations) throws Exception { 136 // return the spring properties, if it 137 Properties answer = new Properties(); 138 for (PropertiesLocation location : locations) { 139 if ("ref".equals(location.getResolver()) && id.equals(location.getPath())) { 140 answer.putAll(properties); 141 } else if (resolver != null) { 142 boolean flag = ignoreMissingLocation; 143 // Override the setting by using ignoreResourceNotFound 144 if (ignoreResourceNotFound != null) { 145 flag = ignoreResourceNotFound; 146 } 147 Properties p = resolver.resolveProperties(context, flag, Collections.singletonList(location)); 148 if (p != null) { 149 answer.putAll(p); 150 } 151 } 152 } 153 // must not return null 154 return answer; 155 } 156 157 @Override 158 public String parseUri(String text, Properties properties, String prefixToken, String suffixToken, 159 String propertyPrefix, String propertySuffix, boolean fallbackToUnaugmentedProperty, boolean defaultFallbackEnabled) throws IllegalArgumentException { 160 161 // first let Camel parse the text as it may contain Camel placeholders 162 String answer; 163 if (parser instanceof AugmentedPropertyNameAwarePropertiesParser) { 164 answer = ((AugmentedPropertyNameAwarePropertiesParser) parser).parseUri(text, properties, prefixToken, suffixToken, 165 propertyPrefix, propertySuffix, fallbackToUnaugmentedProperty, defaultFallbackEnabled); 166 } else { 167 answer = parser.parseUri(text, properties, prefixToken, suffixToken); 168 } 169 170 // then let Spring parse it to resolve any Spring placeholders 171 if (answer != null) { 172 answer = springResolvePlaceholders(answer, properties); 173 } else { 174 answer = springResolvePlaceholders(text, properties); 175 } 176 return answer; 177 } 178 179 @Override 180 public String parseUri(String text, Properties properties, String prefixToken, String suffixToken) throws IllegalArgumentException { 181 String answer = parser.parseUri(text, properties, prefixToken, suffixToken); 182 if (answer != null) { 183 answer = springResolvePlaceholders(answer, properties); 184 } else { 185 answer = springResolvePlaceholders(text, properties); 186 } 187 return answer; 188 } 189 190 @Override 191 public String parseProperty(String key, String value, Properties properties) { 192 String answer = parser.parseProperty(key, value, properties); 193 if (answer != null) { 194 answer = springResolvePlaceholders(answer, properties); 195 } else { 196 answer = springResolvePlaceholders(value, properties); 197 } 198 return answer; 199 } 200 201 /** 202 * Resolves the placeholders using Spring's property placeholder functionality. 203 * 204 * @param text the text which may contain spring placeholders 205 * @param properties the properties 206 * @return the parsed text with replaced placeholders, or the original text as is 207 */ 208 protected String springResolvePlaceholders(String text, Properties properties) { 209 return helper.replacePlaceholders(text, new BridgePropertyPlaceholderResolver(properties)); 210 } 211 212 public void setResolver(PropertiesResolver resolver) { 213 this.resolver = resolver; 214 } 215 216 public void setParser(PropertiesParser parser) { 217 if (this.parser != null) { 218 // use a bridge if there is already a parser configured 219 this.parser = new BridgePropertiesParser(this.parser, parser); 220 } else { 221 this.parser = parser; 222 } 223 } 224 225 private class BridgePropertyPlaceholderResolver implements PropertyPlaceholderHelper.PlaceholderResolver { 226 227 private final Properties properties; 228 229 BridgePropertyPlaceholderResolver(Properties properties) { 230 this.properties = properties; 231 } 232 233 public String resolvePlaceholder(String placeholderName) { 234 String propVal = null; 235 if (systemPropertiesMode == SYSTEM_PROPERTIES_MODE_OVERRIDE) { 236 propVal = resolveSystemProperty(placeholderName); 237 } 238 if (propVal == null) { 239 propVal = (String) properties.get(placeholderName); 240 } 241 if (propVal == null && systemPropertiesMode == SYSTEM_PROPERTIES_MODE_FALLBACK) { 242 propVal = resolveSystemProperty(placeholderName); 243 } 244 return propVal; 245 } 246 } 247 248 private final class BridgePropertiesParser implements PropertiesParser, AugmentedPropertyNameAwarePropertiesParser { 249 250 private final PropertiesParser delegate; 251 private final PropertiesParser parser; 252 253 private BridgePropertiesParser(PropertiesParser delegate, PropertiesParser parser) { 254 this.delegate = delegate; 255 this.parser = parser; 256 } 257 258 @Override 259 public String parseUri(String text, Properties properties, String prefixToken, String suffixToken, String propertyPrefix, String propertySuffix, 260 boolean fallbackToUnaugmentedProperty, boolean defaultFallbackEnabled) throws IllegalArgumentException { 261 String answer = null; 262 if (delegate != null) { 263 if (delegate instanceof AugmentedPropertyNameAwarePropertiesParser) { 264 answer = ((AugmentedPropertyNameAwarePropertiesParser)this.delegate).parseUri(text, properties, 265 prefixToken, suffixToken, propertyPrefix, propertySuffix, fallbackToUnaugmentedProperty, defaultFallbackEnabled); 266 } else { 267 answer = delegate.parseUri(text, properties, prefixToken, suffixToken); 268 } 269 } 270 if (answer != null) { 271 text = answer; 272 } 273 if (parser instanceof AugmentedPropertyNameAwarePropertiesParser) { 274 answer = ((AugmentedPropertyNameAwarePropertiesParser)this.parser).parseUri(text, properties, 275 prefixToken, suffixToken, propertyPrefix, propertySuffix, fallbackToUnaugmentedProperty, defaultFallbackEnabled); 276 } else { 277 answer = parser.parseUri(text, properties, prefixToken, suffixToken); 278 } 279 return answer; 280 } 281 282 @Override 283 public String parseUri(String text, Properties properties, String prefixToken, String suffixToken) throws IllegalArgumentException { 284 String answer = null; 285 if (delegate != null) { 286 answer = delegate.parseUri(text, properties, prefixToken, suffixToken); 287 } 288 if (answer != null) { 289 text = answer; 290 } 291 return parser.parseUri(text, properties, prefixToken, suffixToken); 292 } 293 294 @Override 295 public String parseProperty(String key, String value, Properties properties) { 296 String answer = null; 297 if (delegate != null) { 298 answer = delegate.parseProperty(key, value, properties); 299 } 300 if (answer != null) { 301 value = answer; 302 } 303 return parser.parseProperty(key, value, properties); 304 } 305 } 306 307}