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) 2009 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.xml;
18  
19  import java.io.IOException;
20  import java.util.HashMap;
21  import java.util.Map;
22  import java.util.Properties;
23  
24  import javax.xml.parsers.SAXParser;
25  import javax.xml.parsers.SAXParserFactory;
26  
27  import org.apache.commons.lang.ArrayUtils;
28  import org.springframework.core.io.Resource;
29  import org.springframework.core.io.support.ResourcePatternResolver;
30  
31  import ch.elca.el4j.core.io.support.ListResourcePatternResolverDecorator;
32  import ch.elca.el4j.core.io.support.ManifestOrderedConfigLocationProvider;
33  import ch.elca.el4j.core.io.support.OrderedPathMatchingResourcePatternResolver;
34  import ch.elca.el4j.env.InvalidEnvXmlContentException;
35  import ch.elca.el4j.env.xml.handlers.BeanOverridesHandler;
36  import ch.elca.el4j.env.xml.handlers.EnvGroupHandler;
37  import ch.elca.el4j.env.xml.handlers.PlaceholdersHandler;
38  import ch.elca.el4j.services.monitoring.notification.CoreNotificationHelper;
39  import ch.elca.el4j.util.codingsupport.PropertiesHelper;
40  
41  /**
42   * The central class get env properties configured via env.xml files.
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/xml/EnvXml.java $
45   *
46   * @author Stefan Wismer (SWI)
47   */
48  public class EnvXml {
49  	/**
50  	 * The group type name for env placeholders.
51  	 */
52  	public static final String ENV_GROUP_PLACEHOLDERS = "placeholders";
53  	
54  	/**
55  	 * The group type name for env bean override properties.
56  	 */
57  	public static final String ENV_GROUP_BEAN_OVERRIDES = "bean-overrides";
58  	
59  	/**
60  	 * The env.xml location pattern.
61  	 */
62  	public static final String ENV_XML_LOCATION = "classpath*:env.xml";
63  	
64  	/**
65  	 * The env-values.properties location pattern.
66  	 */
67  	private static final String ENV_VALUES_PROPERTIES_LOCATION = "classpath*:env-values.properties";
68  	
69  	/**
70  	 * The env-constants.properties location pattern (for final properties).
71  	 */
72  	private static final String ENV_CONSTANTS_PROPERTIES_LOCATION = "classpath*:env-constants.properties";
73  	
74  	/**
75  	 * The registered env group handlers.
76  	 */
77  	private Map<String, EnvGroupHandler> m_handlers = new HashMap<String, EnvGroupHandler>();
78  	
79  	/**
80  	 * The cached configuration.
81  	 */
82  	private Map<String, Object> m_configuration = null;
83  	
84  	/**
85  	 * The resolver to ask for the resources.
86  	 */
87  	private final ResourcePatternResolver m_resourcePatternResolver;
88  
89  	/**
90  	 * Is most specific resource (that resolver returns) last? 
91  	 */
92  	private final boolean m_isMostSpecificResourceLast;
93  	
94  	/**
95  	 * Override values for variable resolution.
96  	 */
97  	private Properties m_overrideValues;
98  	
99  	/**
100 	 * The env.xml configuration reader.
101 	 */
102 	public EnvXml() {
103 		ListResourcePatternResolverDecorator resolver = new ListResourcePatternResolverDecorator(
104 			new ManifestOrderedConfigLocationProvider(),
105 			new OrderedPathMatchingResourcePatternResolver());
106 		// most specific resource has to be last, because later properties will overwrite previously set ones.
107 		resolver.setMostSpecificResourceLast(true);
108 		resolver.setMergeWithOuterResources(true);
109 		
110 		m_resourcePatternResolver = resolver;
111 		m_isMostSpecificResourceLast = true;
112 		createDefaultHandlers();
113 	}
114 	/**
115 	 * The env.xml configuration reader.
116 	 * @param resourcePatternResolver     the resolver to ask for the resources
117 	 * @param mostSpecificResourceLast    is most specific resource last
118 	 */
119 	public EnvXml(ResourcePatternResolver resourcePatternResolver, boolean mostSpecificResourceLast) {
120 		m_resourcePatternResolver = resourcePatternResolver;
121 		m_isMostSpecificResourceLast = mostSpecificResourceLast;
122 		createDefaultHandlers();
123 	}
124 	
125 	/**
126 	 * Create and register default group handlers.
127 	 */
128 	private void createDefaultHandlers() {
129 		m_handlers.put(ENV_GROUP_PLACEHOLDERS, new PlaceholdersHandler());
130 		m_handlers.put(ENV_GROUP_BEAN_OVERRIDES, new BeanOverridesHandler());
131 	}
132 	
133 	/**
134 	 * @return    the configuration for each group
135 	 */
136 	private Map<String, Object> retrieveConfiguration() {
137 		try {
138 			SAXParserFactory factory = SAXParserFactory.newInstance(); 
139 			SAXParser saxParser = factory.newSAXParser();
140 			
141 			EnvSaxHandler saxHandler = new EnvSaxHandler(m_handlers);
142 			
143 			Resource[] xmlResources = m_resourcePatternResolver.getResources(ENV_XML_LOCATION);
144 			if (!m_isMostSpecificResourceLast) {
145 				ArrayUtils.reverse(xmlResources);
146 			}
147 			for (Resource resource : xmlResources) {
148 				saxHandler.startResource(resource);
149 				saxParser.parse(resource.getInputStream(), saxHandler);
150 			}
151 			
152 			// read values from properties files
153 			Resource[] propResources = m_resourcePatternResolver.getResources(ENV_VALUES_PROPERTIES_LOCATION);
154 			if (!m_isMostSpecificResourceLast) {
155 				ArrayUtils.reverse(propResources);
156 			}
157 			Properties values = PropertiesHelper.loadPropertiesFromResources(propResources);
158 			
159 			// read constants from properties files
160 			Resource[] constPropResources = m_resourcePatternResolver.getResources(ENV_CONSTANTS_PROPERTIES_LOCATION);
161 			if (!m_isMostSpecificResourceLast) {
162 				ArrayUtils.reverse(constPropResources);
163 			}
164 			values.putAll(PropertiesHelper.loadPropertiesFromResources(constPropResources));
165 			
166 			// override values
167 			if (m_overrideValues != null) {
168 				values.putAll(m_overrideValues);
169 			}
170 			
171 			for (EnvGroupHandler handler : m_handlers.values()) {
172 				handler.filterData(values);
173 			}
174 			
175 			Map<String, Object> config = new HashMap<String, Object>();
176 			for (String handlerName : m_handlers.keySet()) {
177 				config.put(handlerName, m_handlers.get(handlerName).getData());
178 			}
179 			return config;
180 		} catch (InvalidEnvXmlContentException e) {
181 			throw e;
182 		} catch (Exception e) {
183 			CoreNotificationHelper.notifyMisconfiguration("Error while loading env.xml files.", e);
184 			return null;
185 		}
186 	}
187 	
188 	/**
189 	 * @return    <code>true</code> if at least one env.xml file could be found.
190 	 */
191 	public boolean hasValidConfigurations() {
192 		try {
193 			return m_resourcePatternResolver.getResources(ENV_XML_LOCATION).length > 0;
194 		} catch (IOException e) {
195 			return false;
196 		}
197 	}
198 
199 	/**
200 	 * @return    the override values for variable resolution
201 	 */
202 	public Properties getOverrideValues() {
203 		return m_overrideValues;
204 	}
205 	
206 	/**
207 	 * @param overrideValues    the override values for variable resolution
208 	 */
209 	public void setOverrideValues(Properties overrideValues) {
210 		m_overrideValues = overrideValues;
211 	}
212 	
213 	/**
214 	 * Get the configuration of a specif env group.
215 	 * @param groupType    the group type name
216 	 * @return             the configuration
217 	 */
218 	public Object getGroupConfiguration(String groupType) {
219 		if (m_configuration == null) {
220 			m_configuration = retrieveConfiguration();
221 		}
222 		return m_configuration.get(groupType);
223 	}
224 	
225 	/**
226 	 * Register an env group handler.
227 	 * @param groupType    the group type name
228 	 * @param handler      the handler
229 	 */
230 	public void registerHandler(String groupType, EnvGroupHandler handler) {
231 		if (handler == null) {
232 			m_handlers.remove(groupType);
233 		} else {
234 			m_handlers.put(groupType, handler);
235 		}
236 		m_configuration = null;
237 	}
238 	
239 	/**
240 	 * Unregister an env group handler.
241 	 * @param groupType    the group type name
242 	 */
243 	public void unregisterHandler(String groupType) {
244 		m_handlers.remove(groupType);
245 		m_configuration = null;
246 	}
247 }