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.core.Constants;
029    import 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     */
035    public 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    }