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    }