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 */ 017 package org.apache.camel.spring.spi; 018 019 import java.util.Properties; 020 021 import org.apache.camel.CamelContext; 022 import org.apache.camel.component.properties.AugmentedPropertyNameAwarePropertiesParser; 023 import org.apache.camel.component.properties.PropertiesParser; 024 import org.apache.camel.component.properties.PropertiesResolver; 025 import org.springframework.beans.BeansException; 026 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 027 import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; 028 import org.springframework.util.PropertyPlaceholderHelper; 029 030 /** 031 * A {@link PropertyPlaceholderConfigurer} that bridges Camel's <a href="http://camel.apache.org/using-propertyplaceholder.html"> 032 * property placeholder</a> with the Spring property placeholder mechanism. 033 */ 034 public class BridgePropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer implements PropertiesResolver, AugmentedPropertyNameAwarePropertiesParser { 035 036 // NOTE: this class must be in the spi package as if its in the root package, then Spring fails to parse the XML 037 // files due some weird spring issue. But that is okay as having this class in the spi package is fine anyway. 038 039 private final Properties properties = new Properties(); 040 private PropertiesResolver resolver; 041 private PropertiesParser parser; 042 private String id; 043 private PropertyPlaceholderHelper helper; 044 045 // to support both Spring 3.0 / 3.1+ we need to keep track of these as they have private modified in Spring 3.0 046 private String configuredPlaceholderPrefix; 047 private String configuredPlaceholderSuffix; 048 private String configuredValueSeparator; 049 private Boolean configuredIgnoreUnresolvablePlaceholders; 050 051 @Override 052 protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException { 053 super.processProperties(beanFactoryToProcess, props); 054 // store all the spring properties so we can refer to them later 055 properties.putAll(props); 056 // create helper 057 helper = new PropertyPlaceholderHelper( 058 configuredPlaceholderPrefix != null ? configuredPlaceholderPrefix : DEFAULT_PLACEHOLDER_PREFIX, 059 configuredPlaceholderSuffix != null ? configuredPlaceholderSuffix : DEFAULT_PLACEHOLDER_SUFFIX, 060 configuredValueSeparator != null ? configuredValueSeparator : DEFAULT_VALUE_SEPARATOR, 061 configuredIgnoreUnresolvablePlaceholders != null ? configuredIgnoreUnresolvablePlaceholders : false); 062 } 063 064 @Override 065 public void setBeanName(String beanName) { 066 this.id = beanName; 067 super.setBeanName(beanName); 068 } 069 070 @Override 071 public void setPlaceholderPrefix(String placeholderPrefix) { 072 super.setPlaceholderPrefix(placeholderPrefix); 073 this.configuredPlaceholderPrefix = placeholderPrefix; 074 } 075 076 @Override 077 public void setPlaceholderSuffix(String placeholderSuffix) { 078 super.setPlaceholderSuffix(placeholderSuffix); 079 this.configuredPlaceholderSuffix = placeholderSuffix; 080 } 081 082 @Override 083 public void setValueSeparator(String valueSeparator) { 084 super.setValueSeparator(valueSeparator); 085 this.configuredValueSeparator = valueSeparator; 086 } 087 088 @Override 089 public void setIgnoreUnresolvablePlaceholders(boolean ignoreUnresolvablePlaceholders) { 090 super.setIgnoreUnresolvablePlaceholders(ignoreUnresolvablePlaceholders); 091 this.configuredIgnoreUnresolvablePlaceholders = ignoreUnresolvablePlaceholders; 092 } 093 094 @Override 095 public Properties resolveProperties(CamelContext context, boolean ignoreMissingLocation, String... uri) throws Exception { 096 // return the spring properties, if it 097 Properties answer = new Properties(); 098 for (String u : uri) { 099 String ref = "ref:" + id; 100 if (ref.equals(u)) { 101 answer.putAll(properties); 102 } else if (resolver != null) { 103 Properties p = resolver.resolveProperties(context, ignoreMissingLocation, u); 104 if (p != null) { 105 answer.putAll(p); 106 } 107 } 108 } 109 // must not return null 110 return answer; 111 } 112 113 @Override 114 public String parseUri(String text, Properties properties, String prefixToken, String suffixToken, 115 String propertyPrefix, String propertySuffix, boolean fallbackToUnaugmentedProperty) throws IllegalArgumentException { 116 117 // first let Camel parse the text as it may contain Camel placeholders 118 String answer; 119 if (parser instanceof AugmentedPropertyNameAwarePropertiesParser) { 120 answer = ((AugmentedPropertyNameAwarePropertiesParser) parser).parseUri(text, properties, prefixToken, suffixToken, 121 propertyPrefix, propertySuffix, fallbackToUnaugmentedProperty); 122 } else { 123 answer = parser.parseUri(text, properties, prefixToken, suffixToken); 124 } 125 126 // then let Spring parse it to resolve any Spring placeholders 127 if (answer != null) { 128 answer = springResolvePlaceholders(answer, properties); 129 } else { 130 answer = springResolvePlaceholders(text, properties); 131 } 132 return answer; 133 } 134 135 @Override 136 public String parseUri(String text, Properties properties, String prefixToken, String suffixToken) throws IllegalArgumentException { 137 String answer = parser.parseUri(text, properties, prefixToken, suffixToken); 138 if (answer != null) { 139 answer = springResolvePlaceholders(answer, properties); 140 } else { 141 answer = springResolvePlaceholders(text, properties); 142 } 143 return answer; 144 } 145 146 @Override 147 public String parseProperty(String key, String value, Properties properties) { 148 String answer = parser.parseProperty(key, value, properties); 149 if (answer != null) { 150 answer = springResolvePlaceholders(answer, properties); 151 } else { 152 answer = springResolvePlaceholders(value, properties); 153 } 154 return answer; 155 } 156 157 /** 158 * Resolves the placeholders using Spring's property placeholder functionality. 159 * 160 * @param text the text which may contain spring placeholders 161 * @param properties the properties 162 * @return the parsed text with replaced placeholders, or the original text as is 163 */ 164 protected String springResolvePlaceholders(String text, Properties properties) { 165 return helper.replacePlaceholders(text, properties); 166 } 167 168 public void setResolver(PropertiesResolver resolver) { 169 this.resolver = resolver; 170 } 171 172 public void setParser(PropertiesParser parser) { 173 this.parser = parser; 174 } 175 176 }