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.component.properties.PropertiesLookup; 022import org.apache.camel.component.properties.PropertiesParser; 023import org.apache.camel.spi.PropertiesSource; 024import org.springframework.beans.BeansException; 025import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; 026import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer; 027import org.springframework.core.Constants; 028import 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 */ 034public class BridgePropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer implements PropertiesParser, PropertiesSource { 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 PropertiesParser parser; 041 private PropertyPlaceholderHelper helper; 042 private int systemPropertiesMode = SYSTEM_PROPERTIES_MODE_FALLBACK; 043 044 @Override 045 protected void processProperties(ConfigurableListableBeanFactory beanFactoryToProcess, Properties props) throws BeansException { 046 super.processProperties(beanFactoryToProcess, props); 047 // store all the spring properties so we can refer to them later 048 properties.putAll(props); 049 // create helper 050 helper = new PropertyPlaceholderHelper(placeholderPrefix, placeholderSuffix, valueSeparator, ignoreUnresolvablePlaceholders); 051 } 052 053 public int getSystemPropertiesMode() { 054 return systemPropertiesMode; 055 } 056 057 @Override 058 public void setSystemPropertiesModeName(String constantName) throws IllegalArgumentException { 059 super.setSystemPropertiesModeName(constantName); 060 Constants constants = new Constants(PropertyPlaceholderConfigurer.class); 061 this.systemPropertiesMode = constants.asNumber(constantName).intValue(); 062 } 063 064 @Override 065 public void setSystemPropertiesMode(int systemPropertiesMode) { 066 super.setSystemPropertiesMode(systemPropertiesMode); 067 this.systemPropertiesMode = systemPropertiesMode; 068 } 069 070 @Override 071 protected String resolvePlaceholder(String placeholder, Properties props) { 072 String value = props.getProperty(placeholder); 073 if (parser != null) { 074 // Just apply the parser to the place holder value to avoid configuring the other placeholder configure twice for the inside and outside camel context 075 return parser.parseProperty(placeholder, value, props::getProperty); 076 } else { 077 return value; 078 } 079 } 080 081 @Override 082 public String parseUri(String text, PropertiesLookup properties, boolean fallback) throws IllegalArgumentException { 083 // first let Camel parse the text as it may contain Camel placeholders 084 String answer = parser.parseUri(text, properties, fallback); 085 086 // then let Spring parse it to resolve any Spring placeholders 087 if (answer != null) { 088 answer = springResolvePlaceholders(answer, properties); 089 } else { 090 answer = springResolvePlaceholders(text, properties); 091 } 092 return answer; 093 } 094 095 @Override 096 public String parseProperty(String key, String value, PropertiesLookup properties) { 097 String answer = parser.parseProperty(key, value, properties); 098 if (answer != null) { 099 answer = springResolvePlaceholders(answer, properties); 100 } else { 101 answer = springResolvePlaceholders(value, properties); 102 } 103 return answer; 104 } 105 106 /** 107 * Resolves the placeholders using Spring's property placeholder functionality. 108 * 109 * @param text the text which may contain spring placeholders 110 * @param properties the properties 111 * @return the parsed text with replaced placeholders, or the original text as is 112 */ 113 protected String springResolvePlaceholders(String text, PropertiesLookup properties) { 114 return helper.replacePlaceholders(text, new BridgePropertyPlaceholderResolver(properties)); 115 } 116 117 public void setParser(PropertiesParser parser) { 118 if (this.parser != null) { 119 // use a bridge if there is already a parser configured 120 this.parser = new BridgePropertiesParser(this.parser, parser); 121 } else { 122 this.parser = parser; 123 } 124 } 125 126 @Override 127 public String getName() { 128 return "BridgePropertyPlaceholderConfigurer"; 129 } 130 131 @Override 132 public String getProperty(String name) { 133 return properties.getProperty(name); 134 } 135 136 private class BridgePropertyPlaceholderResolver implements PropertyPlaceholderHelper.PlaceholderResolver { 137 138 private final PropertiesLookup properties; 139 140 BridgePropertyPlaceholderResolver(PropertiesLookup properties) { 141 this.properties = properties; 142 } 143 144 @Override 145 public String resolvePlaceholder(String placeholderName) { 146 String propVal = null; 147 if (systemPropertiesMode == SYSTEM_PROPERTIES_MODE_OVERRIDE) { 148 propVal = resolveSystemProperty(placeholderName); 149 } 150 if (propVal == null) { 151 propVal = properties.lookup(placeholderName); 152 } 153 if (propVal == null && systemPropertiesMode == SYSTEM_PROPERTIES_MODE_FALLBACK) { 154 propVal = resolveSystemProperty(placeholderName); 155 } 156 return propVal; 157 } 158 } 159 160 private final class BridgePropertiesParser implements PropertiesParser { 161 162 private final PropertiesParser delegate; 163 private final PropertiesParser parser; 164 165 private BridgePropertiesParser(PropertiesParser delegate, PropertiesParser parser) { 166 this.delegate = delegate; 167 this.parser = parser; 168 } 169 170 @Override 171 public String parseUri(String text, PropertiesLookup properties, boolean fallback) throws IllegalArgumentException { 172 String answer = null; 173 if (delegate != null) { 174 answer = delegate.parseUri(text, properties, fallback); 175 } 176 if (answer != null) { 177 text = answer; 178 } 179 return parser.parseUri(text, properties, fallback); 180 } 181 182 @Override 183 public String parseProperty(String key, String value, PropertiesLookup properties) { 184 String answer = null; 185 if (delegate != null) { 186 answer = delegate.parseProperty(key, value, properties); 187 } 188 if (answer != null) { 189 value = answer; 190 } 191 return parser.parseProperty(key, value, properties); 192 } 193 } 194 195}