View Javadoc

1   /*
2    * EL4J, the Extension Library for the J2EE, adds incremental enhancements to
3    * the spring framework, http://el4j.sf.net
4    * Copyright (C) 2008 by ELCA Informatique SA, Av. de la Harpe 22-24,
5    * 1000 Lausanne, Switzerland, http://www.elca.ch
6    *
7    * EL4J is published under the GNU Lesser General Public License (LGPL)
8    * Version 2.1. See http://www.gnu.org/licenses/
9    *
10   * This program is distributed in the hope that it will be useful,
11   * but WITHOUT ANY WARRANTY; without even the implied warranty of
12   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13   * GNU Lesser General Public License for more details.
14   *
15   * For alternative licensing, please contact info@elca.ch
16   */
17  package ch.elca.el4j.env.beans;
18  
19  import java.io.IOException;
20  import java.util.Properties;
21  
22  import org.slf4j.Logger;
23  import org.slf4j.LoggerFactory;
24  import org.springframework.beans.BeansException;
25  import org.springframework.beans.factory.BeanDefinitionStoreException;
26  import org.springframework.beans.factory.NoSuchBeanDefinitionException;
27  import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
28  import org.springframework.beans.factory.config.PropertyOverrideConfigurer;
29  import org.springframework.context.ApplicationContext;
30  import org.springframework.context.ApplicationContextAware;
31  import org.springframework.core.io.Resource;
32  
33  import ch.elca.el4j.core.context.ModuleApplicationContext;
34  import ch.elca.el4j.env.xml.EnvXml;
35  import ch.elca.el4j.services.monitoring.notification.CoreNotificationHelper;
36  import ch.elca.el4j.util.encryption.AbstractPropertyEncryptor;
37  import ch.elca.el4j.util.encryption.EncryptionException;
38  import ch.elca.el4j.util.encryption.PasswordSource;
39  import ch.elca.el4j.util.env.PropertyEncryptionUtil;
40  
41  /**
42   * Specific property override configurer for the EL4J environment.
43   *
44   * @svnLink $Revision: 3874 $;$Date: 2009-08-04 14:25:40 +0200 (Di, 04. Aug 2009) $;$Author: swismer $;$URL: https://el4j.svn.sourceforge.net/svnroot/el4j/branches/el4j_3_1/el4j/framework/modules/env/src/main/java/ch/elca/el4j/env/beans/EnvPropertyOverrideConfigurer.java $
45   *
46   * @author Martin Zeltner (MZE)
47   * @author Stefan Wismer (SWI)
48   */
49  public class EnvPropertyOverrideConfigurer extends PropertyOverrideConfigurer
50  	implements ApplicationContextAware {
51  
52  	/**
53  	 * The env bean property location.
54  	 */
55  	public static final String ENV_BEAN_PROPERTY_PROPERTIES_LOCATION
56  		= "classpath:env-bean-property.properties";
57  
58  	/**
59  	 * This logger is used to print out some global debugging info. Consult it
60  	 * for info what is going on.
61  	 */
62  	protected static final Logger s_logger
63  		= LoggerFactory.getLogger(ModuleApplicationContext.EL4J_DEBUGGING_LOGGER);
64  
65  	/**
66  	 * Is the used application context.
67  	 */
68  	protected ApplicationContext m_applicationContext;
69  
70  	/**
71  	 * Should invalid bean names be ignored?
72  	 */
73  	protected boolean m_ignoreBeanNameNotFound = false;
74  
75  	/* These handle encryption. */
76  
77  	/**
78  	 * Property encryption handler.
79  	 */
80  	protected PropertyEncryptionUtil m_util = new PropertyEncryptionUtil();
81  	
82  	/**
83  	 * Handles the actual encryption.
84  	 */
85  	private AbstractPropertyEncryptor m_cryptor;
86  
87  	/**
88  	 * Custom location and name for the cryptor.properties file.
89  	 */
90  	private String m_cryptorFile = null;
91  	
92  	/**
93  	 * Sets the location of the env bean property properties file. {@inheritDoc}
94  	 */
95  	@Override
96  	public void postProcessBeanFactory(
97  		ConfigurableListableBeanFactory beanFactory) throws BeansException {
98  		
99  		// new inheritable env support
100 		boolean envXmlFound = false;
101 		EnvXml envXmlConfigLoader;
102 		if (m_applicationContext instanceof ModuleApplicationContext) {
103 			ModuleApplicationContext mac = (ModuleApplicationContext) m_applicationContext;
104 			envXmlConfigLoader = new EnvXml(m_applicationContext, mac.isMostSpecificResourceLast());
105 		} else {
106 			envXmlConfigLoader = new EnvXml();
107 		}
108 		if (envXmlConfigLoader.hasValidConfigurations()) {
109 			super.setProperties((Properties) envXmlConfigLoader.getGroupConfiguration(EnvXml.ENV_GROUP_BEAN_OVERRIDES));
110 			super.setLocalOverride(true);
111 			envXmlFound = true;
112 		}
113 		
114 		// old only-one-env-on-classpath strategy
115 		Resource envBeanPropertyLocation = m_applicationContext
116 			.getResource(ENV_BEAN_PROPERTY_PROPERTIES_LOCATION);
117 	
118 		String envBeanPropertyLocationUrl = "no url";
119 		if (envBeanPropertyLocation.exists()) {
120 			try {
121 				envBeanPropertyLocationUrl = envBeanPropertyLocation.getURL()
122 					.toString();
123 			} catch (IOException e) {
124 				envBeanPropertyLocationUrl = "unknown url";
125 			}
126 		}
127 	
128 		if (!envXmlFound) {
129 			if (envBeanPropertyLocation.exists()) {
130 				s_logger.debug("The used env bean property properties file is '"
131 					+ envBeanPropertyLocationUrl + "'.");
132 				super.setLocation(envBeanPropertyLocation);
133 			} else {
134 				s_logger.warn("No env bean property properties file could be found. The"
135 						+ " correct location for this file is '"
136 						+ ENV_BEAN_PROPERTY_PROPERTIES_LOCATION + "'.");
137 			}
138 		}
139 			
140 		super.postProcessBeanFactory(beanFactory);
141 	}
142 
143 	/** {@inheritDoc} */
144 	@Override
145 	protected void applyPropertyValue(ConfigurableListableBeanFactory factory,
146 		String beanName, String property, String value) {
147 		try {
148 			super.applyPropertyValue(factory, beanName, property, value);
149 		} catch (NoSuchBeanDefinitionException e) {
150 			if (m_ignoreBeanNameNotFound) {
151 				s_logger
152 					.warn("No bean with name '" + beanName
153 						+ "' found. Therefore "
154 						+ "no properties could be applied.");
155 			} else {
156 				s_logger
157 					.error("No bean with name '" + beanName
158 						+ "' found. Therefore "
159 						+ "no properties could be applied.");
160 				throw e;
161 			}
162 		}
163 	}
164 
165 	/**
166 	 * NOT ALLOWED TO USE!
167 	 * 
168 	 * {@inheritDoc}
169 	 */
170 	@Override
171 	public void setLocation(Resource location) {
172 		CoreNotificationHelper.notifyMisconfiguration(
173 				"It is not allowed to set the location manually!");
174 	}
175 
176 	/**
177 	 * NOT ALLOWED TO USE!
178 	 * 
179 	 * {@inheritDoc}
180 	 */
181 	@Override
182 	public void setLocations(Resource[] locations) {
183 		CoreNotificationHelper.notifyMisconfiguration(
184 				"It is not allowed to set the locations manually!");
185 	}
186 
187 	/**
188 	 * {@inheritDoc}
189 	 */
190 	public void setApplicationContext(ApplicationContext applicationContext)
191 		throws BeansException {
192 		m_applicationContext = applicationContext;
193 	}
194 
195 	/**
196 	 * @return Returns <code>true</code> if ignoreBeanNameNotFound is set.
197 	 */
198 	public boolean isIgnoreBeanNameNotFound() {
199 		return m_ignoreBeanNameNotFound;
200 	}
201 
202 	/**
203 	 * @param ignoreBeanNameNotFound
204 	 *            Should invalid bean names be ignored?
205 	 */
206 	public void setIgnoreBeanNameNotFound(boolean ignoreBeanNameNotFound) {
207 		this.m_ignoreBeanNameNotFound = ignoreBeanNameNotFound;
208 	}
209 
210 	/**
211 	 * This is meant to be used as a bean property to turn off encryption in an
212 	 * internal setting.
213 	 */
214 	public void setNoEncryption() {
215 		m_util.deactivate();
216 	}
217 
218 	/**
219 	 * Set a true custom password.
220 	 *
221 	 * @param source A PasswordSource interface.
222 	 */
223 	public void setPasswordSource(PasswordSource source) {
224 		m_util.setSource(source);
225 	}
226 
227 	/**
228 	 * @param file The file containing the encryption properties.
229 	 */
230 	public void setCryptorFile(String file) {
231 		m_cryptorFile = file;
232 	}
233 
234 	/**
235 	 * Decrypts values read from the env-*.properties files.
236 	 *
237 	 * @param originalValue
238 	 *   The value read from env-*.properties The initialization cannot
239 	 *   go in constructor as we don't have all the required properties
240 	 *   there yet.
241 	 * @return The string with all encrypted values decrypted.
242 	 */
243 	protected String convertPropertyValue(String originalValue) {
244 		String value = originalValue;
245 		
246 		if (!m_util.isInited()) {
247 			if (m_cryptorFile != null) {
248 				m_util.init(m_applicationContext, m_cryptorFile);
249 			} else {
250 				m_util.init(m_applicationContext);
251 			}
252 			if (m_util.isActive()) {
253 				m_cryptor = m_util.getCryptor();
254 			}
255 		}
256 		if (m_util.isActive()) {
257 			try {
258 				value = m_cryptor.processString(originalValue);
259 			} catch (EncryptionException e) {
260 				throw new BeanDefinitionStoreException(
261 					"Error during decryption.");
262 			}
263 		}
264 		
265 		return super.convertPropertyValue(value);
266 	}
267 }