001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2002 Jcorporate Ltd. All rights reserved.
005: *
006: * Redistribution and use in source and binary forms, with or without
007: * modification, are permitted provided that the following conditions
008: * are met:
009: *
010: * 1. Redistributions of source code must retain the above copyright
011: * notice, this list of conditions and the following disclaimer.
012: *
013: * 2. Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in
015: * the documentation and/or other materials provided with the
016: * distribution.
017: *
018: * 3. The end-user documentation included with the redistribution,
019: * if any, must include the following acknowledgment:
020: * "This product includes software developed by Jcorporate Ltd.
021: * (http://www.jcorporate.com/)."
022: * Alternately, this acknowledgment may appear in the software itself,
023: * if and wherever such third-party acknowledgments normally appear.
024: *
025: * 4. "Jcorporate" and product names such as "Expresso" must
026: * not be used to endorse or promote products derived from this
027: * software without prior written permission. For written permission,
028: * please contact info@jcorporate.com.
029: *
030: * 5. Products derived from this software may not be called "Expresso",
031: * or other Jcorporate product names; nor may "Expresso" or other
032: * Jcorporate product names appear in their name, without prior
033: * written permission of Jcorporate Ltd.
034: *
035: * 6. No product derived from this software may compete in the same
036: * market space, i.e. framework, without prior written permission
037: * of Jcorporate Ltd. For written permission, please contact
038: * partners@jcorporate.com.
039: *
040: * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
041: * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
042: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
043: * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
044: * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
045: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
046: * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
047: * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
048: * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
049: * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
050: * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
051: * SUCH DAMAGE.
052: * ====================================================================
053: *
054: * This software consists of voluntary contributions made by many
055: * individuals on behalf of the Jcorporate Ltd. Contributions back
056: * to the project(s) are encouraged when you make modifications.
057: * Please send them to support@jcorporate.com. For more information
058: * on Jcorporate Ltd. and its products, please see
059: * <http://www.jcorporate.com/>.
060: *
061: * Portions of this software are based upon other open source
062: * products and are subject to their respective licenses.
063: */
064:
065: package com.jcorporate.expresso.kernel.management;
066:
067: import com.jcorporate.expresso.kernel.ComponentBase;
068: import com.jcorporate.expresso.kernel.ComponentLifecycle;
069: import com.jcorporate.expresso.kernel.Configuration;
070: import com.jcorporate.expresso.kernel.RootContainerInterface;
071: import com.jcorporate.expresso.kernel.digester.ComponentConfig;
072: import com.jcorporate.expresso.kernel.digester.ExpressoServicesConfig;
073: import com.jcorporate.expresso.kernel.exception.ConfigurationException;
074: import com.jcorporate.expresso.kernel.exception.ExpressoRuntimeException;
075: import com.jcorporate.expresso.kernel.util.ClassLocator;
076: import org.w3c.dom.Document;
077: import org.w3c.dom.Element;
078:
079: import javax.xml.parsers.DocumentBuilderFactory;
080: import javax.xml.parsers.FactoryConfigurationError;
081: import javax.xml.parsers.ParserConfigurationException;
082: import java.io.BufferedOutputStream;
083: import java.io.File;
084: import java.io.FileOutputStream;
085: import java.io.IOException;
086: import java.io.OutputStream;
087: import java.util.Iterator;
088: import java.util.Map;
089:
090: /**
091: * Default Implementation of the class used to write the ExpressoServices
092: * configuration file to a file or stream. This class is an ExpressoComponent
093: * that receives various configuration items from the system.
094: * <p>This class also keeps keeps intact an instance of a DOM Writer. The particular
095: * implementation class for the <code>DOMWriter</code> depends on the contents
096: * of the Expresso Configuration file.</p>
097: *
098: * @author Michael Rimov
099: * @version $Revision: 1.5 $ on $Date: 2004/11/17 20:48:17 $
100: */
101:
102: public class DefaultServiceWriter extends ComponentBase implements
103: ServiceWriter, ComponentLifecycle {
104: DOMWriter domWriter = null;
105: String domWriterClass = null;
106:
107: /**
108: * Default Constructor
109: */
110: public DefaultServiceWriter() {
111: super ();
112: }
113:
114: /**
115: * Retrieves the DOMWriter isntantiated class. May be null if the component
116: * was unable to load the specified system.
117: *
118: * @return an instantiated DOMWRiter for file writing.
119: */
120: public DOMWriter getDOMWriter() {
121: return domWriter;
122: }
123:
124: /**
125: * Write the services file to a particular file location.
126: *
127: * @param rootContainer The RootContainer interface that will contain base
128: * information about the system state we are about to save.
129: * @param location The location to save the services file. (File name should be included
130: * in this parameter).
131: * @throws ExpressoRuntimeException upon error.
132: */
133: public void writeServicesFile(RootContainerInterface rootContainer,
134: String location) throws ExpressoRuntimeException {
135: try {
136: File f = new File(location);
137: if (f == null) {
138: throw new ExpressoRuntimeException(
139: "Unable to open file " + location
140: + " for writing");
141: }
142:
143: f.createNewFile();
144: OutputStream os = new BufferedOutputStream(
145: new FileOutputStream(f));
146: this .writeServicesFile(rootContainer, os);
147: os.flush();
148: os.close();
149: } catch (IOException ex) {
150: throw new ExpressoRuntimeException(
151: "I/O error writing config file", ex);
152: }
153: }
154:
155: /**
156: * Write the services file to a particular output stream
157: *
158: * @param rootContainer The RootContainer interface that will contain base
159: * information about the system state we are about to save.
160: * @param os The output stream to save the services file to.
161: * @throws ExpressoRuntimeException upon error.
162: */
163: public void writeServicesFile(RootContainerInterface rootContainer,
164: OutputStream os) throws ExpressoRuntimeException {
165: Document d = buildDOMTree(rootContainer
166: .getExpressoServicesConfig());
167: this .getDOMWriter().saveDocument(os, d);
168: }
169:
170: /**
171: * Convert the ExpressoServicesConfig bean to a DOM document that's compatible
172: * with what is expected in the expresso-services.xml file.
173: *
174: * @param configRoot the root of the configuration tree.
175: * @return a DOM document representing the entire tree.
176: * @throws ExpressoRuntimeException if there is an error building the DOM tree
177: */
178: protected Document buildDOMTree(ExpressoServicesConfig configRoot)
179: throws ExpressoRuntimeException {
180: try {
181: Document d = DocumentBuilderFactory.newInstance()
182: .newDocumentBuilder().newDocument();
183: Element root = d.createElement("expresso-services");
184: ComponentConfig c = configRoot.getRootConfig();
185: d.appendChild(root);
186: processComponentProperties(c, root, d);
187:
188: for (Iterator i = c.getChildComponents().iterator(); i
189: .hasNext();) {
190: ComponentConfig oneChild = (ComponentConfig) i.next();
191: processComponent(oneChild, root, d);
192: }
193:
194: return d;
195: } catch (ParserConfigurationException ex) {
196: throw new ExpressoRuntimeException(
197: "DOM Parser Configuration Error saving file", ex);
198: } catch (FactoryConfigurationError ex) {
199: throw new ExpressoRuntimeException(
200: "DOM Document Factory Configuration Error saving file",
201: ex);
202: }
203: }
204:
205: /**
206: * Recursively go through the Expresso-services.config and convert all the various
207: * components into the DOM tree.
208: *
209: * @param config the current config bean in the tree
210: * @param parent the Parent DOM Element to append items to
211: * @param dom the DOM tree, used for building the various elements in the DOM tree.
212: */
213: protected void processComponent(ComponentConfig config,
214: Element parent, Document dom) {
215: Element this Component = dom.createElement("component");
216: this Component.setAttribute("name", config.getName());
217: this Component.setAttribute("class-name", config.getClassName());
218: processComponentProperties(config, this Component, dom);
219: parent.appendChild(this Component);
220:
221: for (Iterator i = config.getChildComponents().iterator(); i
222: .hasNext();) {
223: ComponentConfig oneChild = (ComponentConfig) i.next();
224: processComponent(oneChild, this Component, dom);
225: }
226: }
227:
228: /**
229: * Write the current component's configuration to the current DOM element.
230: *
231: * @param config the current config to glean the properties from
232: * @param parent the parent element to append properties to as children.
233: * @param dom the DOM tree to use for Element factores
234: */
235: protected void processComponentProperties(ComponentConfig config,
236: Element parent, Document dom) {
237: //
238: //Write Simple Properties
239: //
240: for (Iterator i = config.getProperties().keySet().iterator(); i
241: .hasNext();) {
242: String propName = (String) i.next();
243: String propValue = config.getProperty(propName);
244: Element property = dom.createElement("property");
245: property.setAttribute("name", propName);
246: property.setAttribute("value", propValue);
247: parent.appendChild(property);
248: }
249:
250: //
251: //Write Mapped Properties
252: //
253: Map allMappedProperties = (Map) config.getAllMappedProperties();
254: for (Iterator i = allMappedProperties.keySet().iterator(); i
255: .hasNext();) {
256: String propertyName = (String) i.next();
257: Map subMap = (Map) allMappedProperties.get(propertyName);
258: for (Iterator j = subMap.keySet().iterator(); j.hasNext();) {
259: String propertyKey = (String) j.next();
260: String propertyValue = (String) subMap.get(propertyKey);
261: Element property = dom.createElement("mapped-property");
262: property.setAttribute("name", propertyName);
263: property.setAttribute("key", propertyKey);
264: property.setAttribute("value", propertyValue);
265: parent.appendChild(property);
266: }
267: }
268:
269: //
270: //Write Indexed Properties
271: //
272: Map allIndexedProperties = (Map) config
273: .getAllIndexedProperties();
274: for (Iterator i = allIndexedProperties.keySet().iterator(); i
275: .hasNext();) {
276: String propertyName = (String) i.next();
277: Map subMap = (Map) allMappedProperties.get(propertyName);
278: for (Iterator j = subMap.keySet().iterator(); j.hasNext();) {
279: Integer propertyIndex = (Integer) j.next();
280: String propertyValue = (String) subMap
281: .get(propertyIndex);
282: Element property = dom
283: .createElement("indexed-property");
284: property.setAttribute("name", propertyName);
285: property
286: .setAttribute("index", propertyIndex.toString());
287: property.setAttribute("value", propertyValue);
288: parent.appendChild(property);
289: }
290: }
291: }
292:
293: public void initialize() {
294:
295: }
296:
297: /**
298: * Configure the DefaultServiceWriter. The chief configuration value is
299: * the domWriter class, which describes which implementation to use for
300: * writing out DOM documents.
301: *
302: * @param newConfig the Configuration object to load items from.
303: * @throws ConfigurationException if the domWriterClass cannot be instantiated
304: */
305: public void configure(Configuration newConfig)
306: throws ConfigurationException {
307: String temp = (String) newConfig.get("domWriterClass");
308: try {
309: setDomWriterClass(temp);
310: } catch (ExpressoRuntimeException ex) {
311: throw new ConfigurationException(
312: "Invalid paramter 'serviceWriterClass'=" + temp, ex
313: .getNested());
314: }
315: }
316:
317: /**
318: * Reconfigure lifecycle event for this component. It attempts to load a new
319: * DOMWriter class, however, if unable to do so, it will rollback the configuration
320: * internally and throw a ConfigurationException.
321: *
322: * @param newConfig the Configuration object to load items from.
323: * @throws ConfigurationException if the system is unable to load the new DOMWriter
324: * class specified.
325: */
326: public void reconfigure(Configuration newConfig)
327: throws ConfigurationException {
328: String rollBackClass = this .getDomWriterClass();
329: try {
330: configure(newConfig);
331: } catch (ConfigurationException ex) {
332: try {
333: this .setDomWriterClass(rollBackClass);
334: } catch (ExpressoRuntimeException ex1) {
335: throw new ConfigurationException(
336: "Error rolling back configuration", ex1);
337: }
338:
339: throw new ConfigurationException(
340: "Error setting configuration", ex);
341: }
342: }
343:
344: /**
345: * Implementation of the Destroy() lifecycle event. nulls out all member
346: * properties.
347: */
348: public void destroy() {
349: domWriter = null;
350: domWriterClass = null;
351: }
352:
353: /**
354: * Retrieves the previously set classname of the Dom Writer
355: *
356: * @return java.lang.String
357: */
358: public String getDomWriterClass() {
359: return domWriterClass;
360: }
361:
362: /**
363: * Sets and loads the specified domWriter class.
364: *
365: * @param domWriterClass The classname of the DOMWriter to load
366: */
367: public void setDomWriterClass(String domWriterClass)
368: throws ExpressoRuntimeException {
369: try {
370: DOMWriter tmp = (DOMWriter) (ClassLocator
371: .loadClass(domWriterClass).newInstance());
372: this .domWriterClass = domWriterClass;
373: domWriter = tmp;
374: } catch (Exception ex) {
375: throw new ExpressoRuntimeException(
376: "Error setting DOM Writer Class", ex);
377: }
378: }
379: }
|