View Javadoc
1   package org.apache.fulcrum.yaafi.framework.factory;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *   http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.io.File;
23  import java.io.IOException;
24  import java.io.InputStream;
25  import java.util.Enumeration;
26  import java.util.Hashtable;
27  
28  import org.apache.avalon.framework.configuration.Configuration;
29  import org.apache.avalon.framework.configuration.DefaultConfiguration;
30  import org.apache.avalon.framework.configuration.DefaultConfigurationBuilder;
31  import org.apache.avalon.framework.context.Context;
32  import org.apache.avalon.framework.context.DefaultContext;
33  import org.apache.avalon.framework.logger.ConsoleLogger;
34  import org.apache.avalon.framework.logger.Logger;
35  import org.apache.avalon.framework.service.ServiceManager;
36  import org.apache.commons.lang3.StringUtils;
37  import org.apache.fulcrum.yaafi.framework.constant.AvalonMerlinConstants;
38  import org.apache.fulcrum.yaafi.framework.container.ServiceConstants;
39  import org.apache.fulcrum.yaafi.framework.crypto.CryptoStreamFactory;
40  import org.apache.fulcrum.yaafi.framework.util.InputStreamLocator;
41  import org.apache.fulcrum.yaafi.framework.util.Validate;
42  
43  /**
44   * Helper class to capture configuration related stuff. The are two ways for
45   * setting up the configuration:
46   * <ul>
47   * <li>set all parameters manually</li>
48   * <li>use a containerConfiguration file and provide the remaining settings</li>
49   * </ul>
50   *
51   * The Avalon context and configuration are created by
52   * <ul>
53   * <li>createFinalContext()</li>
54   * <li>createFinalConfiguration()</li>
55   * </ul>
56   *
57   * @author <a href="mailto:siegfried.goeschl@it20one.at">Siegfried Goeschl</a>
58   */
59  
60  public class ServiceContainerConfiguration {
61  	/** our default implementation class of the service container */
62  	private String serviceContainerClazzName;
63  
64  	/** the location of the component role file */
65  	private String componentRolesLocation;
66  
67  	/** is the component role file encrypted? */
68  	private String isComponentRolesEncrypted;
69  
70  	/** the location of the component configuration file */
71  	private String componentConfigurationLocation;
72  
73  	/** is the component configuration file encrypted? */
74  	private String isComponentConfigurationEncrypted;
75  
76  	/** the location of the paramaters file */
77  	private String parametersLocation;
78  
79  	/** is the parameters file encrypted? */
80  	private String isParametersEncrypted;
81  
82  	/** the user-supplied Avalon context */
83  	private DefaultContext context;
84  
85  	/** the Avalon logger */
86  	private Logger logger;
87  
88  	/** the application directory */
89  	private String applicationRootDir;
90  
91  	/** the temporary directory */
92  	private String tempRootDir;
93  
94  	/** the class loader passed in the Avalon Context */
95  	private ClassLoader componentClassLoader;
96  
97  	/** the type of container where YAAFI is embedded */
98  	private String containerFlavour;
99  
100 	/** the caller-supplied container configuration */
101 	private Configuration containerConfiguration;
102 
103 	/** to lookup service in the parent container */
104 	private ServiceManager parentServiceManager;
105 
106 	/** a list of ServiceManager maintaining their own services */
107 	private String[] serviceManagerList;
108 
109 	/** Constructor */
110 	public ServiceContainerConfiguration() {
111 		this(ConsoleLogger.LEVEL_DEBUG);
112 	}
113 
114 	/**
115 	 * Constructor.
116 	 *
117 	 * @param logLevel the log level for the console logger.
118 	 */
119 	public ServiceContainerConfiguration(int logLevel) {
120 		this.logger = new ConsoleLogger(logLevel);
121 		this.containerFlavour = ServiceConstants.AVALON_CONTAINER_YAAFI;
122 		this.serviceContainerClazzName = ServiceConstants.CLAZZ_NAME;
123 		this.componentRolesLocation = ServiceConstants.COMPONENT_ROLE_VALUE;
124 		this.isComponentRolesEncrypted = "false";
125 		this.componentConfigurationLocation = ServiceConstants.COMPONENT_CONFIG_VALUE;
126 		this.isComponentConfigurationEncrypted = "false";
127 		this.parametersLocation = ServiceConstants.COMPONENT_PARAMETERS_VALUE;
128 		this.isParametersEncrypted = "false";
129 		this.context = new DefaultContext();
130 		this.applicationRootDir = new File("").getAbsolutePath();
131 		this.tempRootDir = System.getProperty("java.io.tmpdir", ".");
132 		this.componentClassLoader = this.getClass().getClassLoader();
133 	}
134 
135 	/**
136 	 * Add a new entry to the context by creating a new one.
137 	 * 
138 	 * @param name  the name of the new entry
139 	 * @param value the value of the new entry
140 	 */
141 	public void addToContext(String name, Object value) {
142 		Validate.notEmpty(name, "name");
143 		Validate.notNull(value, "value");
144 		this.getContext().put(name, value);
145 	}
146 
147 	/**
148 	 * Add a hashtable to the context
149 	 * 
150 	 * @param hashtable the Hashtable to be added
151 	 */
152 	public void addToContext(Hashtable<?, ?> hashtable) {
153 		Validate.notNull(hashtable, "hashtable");
154 
155 		String name = null;
156 		Object value = null;
157 		Enumeration<?> keys = hashtable.keys();
158 
159 		while (keys.hasMoreElements()) {
160 			name = (String) keys.nextElement();
161 			value = hashtable.get(name);
162 			this.addToContext(name, value);
163 		}
164 	}
165 
166 	/**
167 	 * Create the final Avalon context passed to YAAFI containing
168 	 * <ul>
169 	 * <li>user-supplied context</li>
170 	 * <li>urn:avalon:home</li>
171 	 * <li>urn:avalon:temp</li>
172 	 * <li>urn:avalon:name</li>
173 	 * <li>urn:avalon:partition</li>
174 	 * <li>urn:avalon:classloader</li>
175 	 * </ul>
176 	 *
177 	 * @return the final Context
178 	 * @throws Exception if filename not defined
179 	 * @throws IOException if file not found
180 	 */
181 
182 	public Context createFinalContext() throws IOException, Exception {
183 		// 1) add the application root dir
184 
185 		this.addToContext(AvalonMerlinConstants.URN_AVALON_HOME, this.getApplicationRootDir());
186 
187 		// 2) add the temp root dir
188 
189 		this.addToContext(AvalonMerlinConstants.URN_AVALON_TEMP, this.getTempRootDir());
190 
191 		// 3) add the Avalon name
192 
193 		this.addToContext(AvalonMerlinConstants.URN_AVALON_NAME, ServiceConstants.ROLE_NAME);
194 
195 		// 4) add the Avalon partition name
196 
197 		this.addToContext(AvalonMerlinConstants.URN_AVALON_PARTITION, "root");
198 
199 		// 5) add the class loader
200 
201 		this.addToContext(AvalonMerlinConstants.URN_AVALON_CLASSLOADER, this.getComponentClassLoader());
202 
203 		return this.getContext();
204 	}
205 
206 	/**
207 	 * Create a final configuration.
208 	 *
209 	 * @return the configuration
210 	 */
211 	public Configuration createFinalConfiguration() {
212 		DefaultConfiguration result = null;
213 
214 		if (this.getContainerConfiguration() != null) {
215 			return this.getContainerConfiguration();
216 		} else {
217 			// the root element is "fulcrum-yaafi"
218 
219 			result = new DefaultConfiguration(ServiceConstants.ROLE_NAME);
220 
221 			// add the following fragement
222 			//
223 			// <containerFlavour>merlin</containerFlavour>
224 
225 			DefaultConfiguration containerFlavourConfig = new DefaultConfiguration(
226 					ServiceConstants.CONTAINERFLAVOUR_CONFIG_KEY);
227 
228 			containerFlavourConfig.setValue(this.getContainerFlavour());
229 
230 			result.addChild(containerFlavourConfig);
231 
232 			// add the following fragement
233 			//
234 			// <containerClazzName>...</containerClazzName>
235 
236 			DefaultConfiguration containerClazzNameConfig = new DefaultConfiguration(
237 					ServiceConstants.CONTAINERCLAZZNAME_CONFIG_KEY);
238 
239 			containerClazzNameConfig.setValue(this.getServiceContainerClazzName());
240 
241 			result.addChild(containerClazzNameConfig);
242 
243 			// add the following fragement
244 			//
245 			// <componentRoles>
246 			// <location>../conf/componentRoles.xml</location>
247 			// <isEncrypted>true</isEncrypted>
248 			// </componentRoles>
249 
250 			DefaultConfiguration componentRolesConfig = new DefaultConfiguration(ServiceConstants.COMPONENT_ROLE_KEYS);
251 
252 			DefaultConfiguration componentRolesLocation = new DefaultConfiguration(
253 					ServiceConstants.COMPONENT_LOCATION_KEY);
254 
255 			componentRolesLocation.setValue(this.getComponentRolesLocation());
256 
257 			DefaultConfiguration componentRolesIsEncrypted = new DefaultConfiguration(
258 					ServiceConstants.COMPONENT_ISENCRYPTED_KEY);
259 
260 			componentRolesIsEncrypted.setValue(this.isComponentRolesEncrypted());
261 
262 			componentRolesConfig.addChild(componentRolesLocation);
263 			componentRolesConfig.addChild(componentRolesIsEncrypted);
264 
265 			result.addChild(componentRolesConfig);
266 
267 			// add the following fragement
268 			//
269 			// <componentConfiguration>
270 			// <location>../conf/componentRoles.xml</location>
271 			// <isEncrypted>true</isEncrypted>
272 			// </componentConfiguration>
273 
274 			DefaultConfiguration componentConfigurationConfig = new DefaultConfiguration(
275 					ServiceConstants.COMPONENT_CONFIG_KEY);
276 
277 			DefaultConfiguration componentConfigurationLocation = new DefaultConfiguration(
278 					ServiceConstants.COMPONENT_LOCATION_KEY);
279 
280 			componentConfigurationLocation.setValue(this.getComponentConfigurationLocation());
281 
282 			DefaultConfiguration componentConfigurationIsEncrypted = new DefaultConfiguration(
283 					ServiceConstants.COMPONENT_ISENCRYPTED_KEY);
284 
285 			componentConfigurationIsEncrypted.setValue(this.isComponentConfigurationEncrypted());
286 
287 			componentConfigurationConfig.addChild(componentConfigurationLocation);
288 			componentConfigurationConfig.addChild(componentConfigurationIsEncrypted);
289 
290 			result.addChild(componentConfigurationConfig);
291 
292 			// Add the following fragement
293 			//
294 			// <parameters>
295 			// <location>../conf/parameters.properties</location>
296 			// <isEncrypted>true</isEncrypted>
297 			// </parameters>
298 
299 			DefaultConfiguration parameterConfigurationConfig = new DefaultConfiguration(
300 					ServiceConstants.COMPONENT_PARAMETERS_KEY);
301 
302 			DefaultConfiguration parameterConfigurationLocation = new DefaultConfiguration(
303 					ServiceConstants.COMPONENT_LOCATION_KEY);
304 
305 			parameterConfigurationLocation.setValue(this.getParametersLocation());
306 
307 			DefaultConfiguration parameterConfigurationIsEncrypted = new DefaultConfiguration(
308 					ServiceConstants.COMPONENT_ISENCRYPTED_KEY);
309 
310 			parameterConfigurationIsEncrypted.setValue(this.isParametersEncrypted());
311 
312 			parameterConfigurationConfig.addChild(parameterConfigurationLocation);
313 			parameterConfigurationConfig.addChild(parameterConfigurationIsEncrypted);
314 
315 			result.addChild(parameterConfigurationConfig);
316 
317 			// Add the following fragement
318 			//
319 			// <serviceManagers>
320 			// <serviceManagers>springFrameworkService</serviceManager>
321 			// </serviceManagers>
322 
323 			if (this.hasServiceManagerList()) {
324 				DefaultConfiguration serviceManagerListConfig = new DefaultConfiguration(
325 						ServiceConstants.SERVICEMANAGER_LIST_KEY);
326 
327 				for (int i = 0; i < this.serviceManagerList.length; i++) {
328 					DefaultConfiguration serviceManagerConfig = new DefaultConfiguration(
329 							ServiceConstants.SERVICEMANAGER_KEY);
330 
331 					serviceManagerConfig.setValue(this.serviceManagerList[i]);
332 
333 					serviceManagerListConfig.addChild(serviceManagerConfig);
334 				}
335 
336 				result.addChild(serviceManagerListConfig);
337 			}
338 
339 			return result;
340 		}
341 	}
342 
343 	/////////////////////////////////////////////////////////////////////////
344 	// Generated Getters/Setters
345 	/////////////////////////////////////////////////////////////////////////
346 
347 	/**
348 	 * @return Returns the serviceContainerClazzName.
349 	 */
350 	private String getServiceContainerClazzName() {
351 		return this.serviceContainerClazzName;
352 	}
353 
354 	/**
355 	 * @return Returns the componentConfigurationLocation.
356 	 */
357 	private String getComponentConfigurationLocation() {
358 		return componentConfigurationLocation;
359 	}
360 
361 	/**
362 	 * @param componentConfigurationLocation The componentConfigurationLocation to
363 	 *                                       set.
364 	 */
365 	public void setComponentConfigurationLocation(String componentConfigurationLocation) {
366 		Validate.notNull(componentConfigurationLocation, "componentConfigurationLocation");
367 		this.componentConfigurationLocation = componentConfigurationLocation;
368 	}
369 
370 	/**
371 	 * @return Returns the componentRolesLocation.
372 	 */
373 	private String getComponentRolesLocation() {
374 		return componentRolesLocation;
375 	}
376 
377 	/**
378 	 * @param componentRolesLocation The componentRolesLocation to set.
379 	 */
380 	public void setComponentRolesLocation(String componentRolesLocation) {
381 		this.componentRolesLocation = componentRolesLocation;
382 	}
383 
384 	/**
385 	 * @return Returns the context.
386 	 */
387 	private DefaultContext getContext() {
388 		return context;
389 	}
390 
391 	/**
392 	 * @param context The context to set.
393 	 */
394 	public void setContext(Context context) {
395 		if (context instanceof DefaultContext) {
396 			this.context = (DefaultContext) context;
397 		} else {
398 			this.context = new DefaultContext(context);
399 		}
400 	}
401 
402 	/**
403 	 * @return Returns the isComponentConfigurationEncrypted.
404 	 */
405 	private String isComponentConfigurationEncrypted() {
406 		return isComponentConfigurationEncrypted;
407 	}
408 
409 	/**
410 	 * @param isComponentConfigurationEncrypted The
411 	 *                                          isComponentConfigurationEncrypted to
412 	 *                                          set.
413 	 */
414 	public void setComponentConfigurationEncrypted(String isComponentConfigurationEncrypted) {
415 		this.isComponentConfigurationEncrypted = isComponentConfigurationEncrypted;
416 	}
417 
418 	/**
419 	 * @return Returns the isComponentRolesEncrypted.
420 	 */
421 	private String isComponentRolesEncrypted() {
422 		return isComponentRolesEncrypted;
423 	}
424 
425 	/**
426 	 * @param isComponentRolesEncrypted The isComponentRolesEncrypted to set.
427 	 */
428 	public void setComponentRolesEncrypted(String isComponentRolesEncrypted) {
429 		this.isComponentRolesEncrypted = isComponentRolesEncrypted;
430 	}
431 
432 	/**
433 	 * @return Returns the isParametersEncrypted.
434 	 */
435 	private String isParametersEncrypted() {
436 		return isParametersEncrypted;
437 	}
438 
439 	/**
440 	 * @param isParametersEncrypted The isParametersEncrypted to set.
441 	 */
442 	public void setParametersEncrypted(String isParametersEncrypted) {
443 		Validate.notEmpty(isParametersEncrypted, "isParametersEncrypted");
444 		this.isParametersEncrypted = isParametersEncrypted;
445 	}
446 
447 	/**
448 	 * @return Returns the logger.
449 	 */
450 	public Logger getLogger() {
451 		return logger;
452 	}
453 
454 	/**
455 	 * @param logger The logger to set.
456 	 */
457 	public void setLogger(Logger logger) {
458 		this.logger = logger;
459 	}
460 
461 	/**
462 	 * @return Returns the parametersLocation.
463 	 */
464 	private String getParametersLocation() {
465 		return parametersLocation;
466 	}
467 
468 	/**
469 	 * @param parametersLocation The parametersLocation to set.
470 	 */
471 	public void setParametersLocation(String parametersLocation) {
472 		this.parametersLocation = parametersLocation;
473 	}
474 
475 	/**
476 	 * @return Returns the applicationRootDir.
477 	 */
478 	private File getApplicationRootDir() {
479 		return new File(applicationRootDir);
480 	}
481 
482 	/**
483 	 * @param applicationRootDir The applicationRootDir to set.
484 	 */
485 	public void setApplicationRootDir(String applicationRootDir) {
486 		Validate.notNull(applicationRootDir, "applicationRootDir");
487 
488 		if (applicationRootDir.equals(".")) {
489 			this.applicationRootDir = new File("").getAbsolutePath();
490 		} else {
491 			this.applicationRootDir = new File(applicationRootDir).getAbsolutePath();
492 		}
493 	}
494 
495 	/**
496 	 * @return Returns the tempRootDir.
497 	 * @throws Exception 
498 	 * @throws IOException 
499 	 */
500 	private File getTempRootDir() throws IOException, Exception {
501 		return makeAbsoluteFile(this.getApplicationRootDir(), this.tempRootDir);
502 	}
503 
504 	/**
505 	 * @param tempRootDir The tempRootDir to set.
506 	 */
507 	public void setTempRootDir(String tempRootDir) {
508 		Validate.notNull(tempRootDir, "tempRootDir");
509 		this.tempRootDir = tempRootDir;
510 	}
511 
512 	/**
513 	 * @return Returns the classLoader.
514 	 */
515 	private ClassLoader getComponentClassLoader() {
516 		return componentClassLoader;
517 	}
518 
519 	/**
520 	 * @param componentClassLoader The classLoader to set.
521 	 */
522 	public void setComponentClassLoader(ClassLoader componentClassLoader) {
523 		Validate.notNull(componentClassLoader, "componentClassLoader");
524 		this.componentClassLoader = componentClassLoader;
525 	}
526 
527 	/**
528 	 * @return Returns the containerFlavour.
529 	 */
530 	private String getContainerFlavour() {
531 		return containerFlavour;
532 	}
533 
534 	/**
535 	 * @param containerFlavour The containerFlavour to set.
536 	 */
537 	public void setContainerFlavour(String containerFlavour) {
538 		this.containerFlavour = containerFlavour;
539 	}
540 
541 	/**
542 	 * @return Returns the containerConfiguration.
543 	 */
544 	private Configuration getContainerConfiguration() {
545 		return containerConfiguration;
546 	}
547 
548 	/**
549 	 * @param containerConfiguration The containerConfiguration to set.
550 	 */
551 	public void setContainerConfiguration(Configuration containerConfiguration) {
552 		this.containerConfiguration = containerConfiguration;
553 	}
554 
555 	/**
556 	 * Get the parent service manager to find service managed by the parent
557 	 * container.
558 	 *
559 	 * @return the parent container
560 	 */
561 
562 	public ServiceManager getParentServiceManager() {
563 		return parentServiceManager;
564 	}
565 
566 	/**
567 	 * Set the parent service manager to find service managed by the parent
568 	 * container.
569 	 *
570 	 * @param parentServiceManager the parent container
571 	 */
572 	public void setParentServiceManager(ServiceManager parentServiceManager) {
573 		this.parentServiceManager = parentServiceManager;
574 	}
575 
576 	/**
577 	 * Get a list of service manager managing their own set of services.
578 	 *
579 	 * @return a list of service implementing the ServiceManager interface
580 	 */
581 	public String[] getServiceManagerList() {
582 		return serviceManagerList;
583 	}
584 
585 	/**
586 	 * Set a list of service manager managing their own set of services.
587 	 *
588 	 * @param serviceManagerList a list of service implementing the ServiceManager
589 	 *                           interface
590 	 */
591 	public void setServiceManagerList(String[] serviceManagerList) {
592 		this.serviceManagerList = serviceManagerList;
593 	}
594 
595 	/**
596 	 * @return true if there is a service manager defined
597 	 */
598 	public boolean hasServiceManagerList() {
599 		if (this.serviceManagerList != null && this.serviceManagerList.length > 0)
600 			return true;
601 		return false;
602 	}
603 
604 	/**
605 	 * Loads a containerConfiguration file and set is as the Avalon configuration to
606 	 * be used for Configurable.configure(). Take care that the implementation uses
607 	 * an InputStreamLocator to find the containerConfiguration which uses the
608 	 * previously set application root directory.
609 	 *
610 	 * @param location the location of the containerConfiguration
611 	 * @throws IOException loading the configuration failed
612 	 */
613 	public void loadContainerConfiguration(String location) throws IOException {
614 		this.loadContainerConfiguration(location, "false");
615 	}
616 
617 	/**
618 	 * Loads a containerConfiguration file and set is as the Avalon configuration to
619 	 * be used for Configurable.configure(). Take care that the implementation uses
620 	 * an InputStreamLocator to find the containerConfiguration which uses the
621 	 * previously set application root directory.
622 	 *
623 	 * @param location    the location of the containerConfiguration
624 	 * @param isEncrypted is the file encrypted
625 	 * @throws IOException loading the configuration failed
626 	 */
627 	public void loadContainerConfiguration(String location, String isEncrypted) throws IOException {
628 		Configuration result = null;
629 
630 		InputStreamLocator locator = new InputStreamLocator(this.getApplicationRootDir(), this.getLogger());
631 
632 		DefaultConfigurationBuilder builder = new DefaultConfigurationBuilder();
633 		InputStream is = locator.locate(location);
634 
635 		if (is != null) {
636 			try {
637 				is = CryptoStreamFactory.getDecryptingInputStream(is, isEncrypted);
638 				result = builder.build(is);
639 				this.setContainerConfiguration(result);
640 			} catch (Exception e) {
641 				String msg = "Unable to parse the following file : " + location;
642 				this.getLogger().error(msg, e);
643 				throw new IOException(msg);
644 			}
645 		} else {
646 			String msg = "Unable to locate the containerConfiguration file : " + location;
647 			this.getLogger().error(msg);
648 			throw new IOException(msg);
649 		}
650 	}
651 
652 	/**
653 	 * Determines the absolute file.
654 	 * 
655 	 * @param baseDir  the base directory
656 	 * @param fileName the filename
657 	 * @return the absolute path
658 	 */
659 	private static File makeAbsoluteFile(File baseDir, String fileName) throws IOException, Exception {
660 		if (baseDir.exists()) {
661 			if (!StringUtils.isEmpty(fileName)) {
662 				File result = new File(fileName);
663 				if (!result.isAbsolute()) {
664 					result = new File(baseDir, fileName);
665 				}
666 				return result;
667 			} else {
668 				throw new Exception("No filename specified");
669 			}
670 		} else {
671 			throw new IOException("The directory does not exist");
672 		}
673 	}
674 }