001: /* ====================================================================
002: * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
003: *
004: * Copyright (c) 1995-2003 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: package com.jcorporate.expresso.kernel.digester;
065:
066: import com.jcorporate.expresso.kernel.util.FastStringBuffer;
067: import org.apache.commons.digester.Digester;
068: import org.apache.log4j.Logger;
069: import org.xml.sax.SAXException;
070:
071: import javax.xml.parsers.FactoryConfigurationError;
072: import javax.xml.parsers.ParserConfigurationException;
073: import java.io.File;
074: import java.io.FileInputStream;
075: import java.io.InputStream;
076: import java.net.URL;
077:
078: /**
079: * Digester class representing the entire expresso-services.xml file
080: *
081: * @author Michael Rimov
082: */
083:
084: public class ExpressoServicesConfig implements java.io.Serializable {
085:
086: /**
087: * This constant tells the limit to which we allow nesting of components.
088: * Thanks to digester not being recursive, and not wanting to write our own
089: * SAX parser, we use this kludge instead.
090: */
091: private static final int MAX_NESTING = 20;
092:
093: /**
094: * The log4j Logger [which is initialized by the time we get here]
095: */
096: private Logger log = Logger.getLogger(ExpressoServicesConfig.class);
097:
098: /**
099: * The name of the expresso config file name
100: */
101: private String fileName = null;
102:
103: /**
104: * The URL of expresso config file
105: */
106: private URL fileURL = null;
107:
108: /**
109: * The root of the Component configuration tree
110: */
111: private ComponentConfig root;
112:
113: /**
114: * A utility class to set the configuration of the SAX Parser
115: */
116: SaxParserConfigurer saxParserConfig;
117:
118: /**
119: * Default Constructor
120: */
121: public ExpressoServicesConfig() {
122: saxParserConfig = new SaxParserConfigurer();
123: }
124:
125: public static ExpressoServicesConfig newBlankContainer() {
126: ExpressoServicesConfig esc = new ExpressoServicesConfig();
127: esc.initBlankContainer();
128: return esc;
129: }
130:
131: public void initBlankContainer() {
132: root = new ComponentConfig();
133: }
134:
135: /**
136: * Loads the ExpressoServices file. When complete, call getRootConfig() to
137: * get the results of the Digesting of the configuration file.
138: */
139: public void loadExpressoServices() {
140: try {
141: javax.xml.parsers.SAXParserFactory spf = javax.xml.parsers.SAXParserFactory
142: .newInstance();
143: javax.xml.parsers.SAXParser sp = spf.newSAXParser();
144:
145: Digester digester = new Digester(sp);
146:
147: URL url = this
148: .getClass()
149: .getResource(
150: "/com/jcorporate/expresso/kernel/expresso-services_5_1.dtd");
151: if (url != null) {
152: digester
153: .register(
154: "-//Jcorporate Ltd//DTD Expresso Services Configuration 5.1//EN",
155: url.toString());
156: } else {
157: throw new IllegalArgumentException(
158: "Unable to locate "
159: + "expresso-services_5_1.dtd in component package");
160: }
161:
162: setDigesterRules(digester);
163:
164: InputStream is;
165:
166: if (fileName != null) {
167: File f = new File(fileName);
168: is = new FileInputStream(f);
169: } else if (fileURL != null) {
170: is = fileURL.openStream();
171: } else {
172: throw new IllegalArgumentException(
173: "Must set the filename to parse before loading Expresso Services");
174: }
175:
176: digester.parse(is);
177: } catch (FactoryConfigurationError ex) {
178: log
179: .error(
180: "Fatal error trying to find a suitable Digester compatible parser.",
181: ex);
182: } catch (SAXException ex) {
183: log
184: .error(
185: "Fatal error trying to digest expresso-services.xml file",
186: ex);
187: } catch (ParserConfigurationException ex) {
188: log
189: .error(
190: "Fatal error trying to find a suitable Digester compatible parser.",
191: ex);
192: } catch (java.io.IOException ex) {
193: log.error("Fatal IO error parsing input.", ex);
194: }
195:
196: }
197:
198: /**
199: * Set the filename of the expresso services file to load
200: *
201: * @param fileName the file name to load the Expresso services file from
202: */
203: public void setExpressoServicesFile(String fileName) {
204: if (log.isDebugEnabled()) {
205: log
206: .debug("Setting up to load Expresso Services file from: "
207: + fileName);
208: }
209: this .fileName = fileName;
210: }
211:
212: /**
213: * Retrieve the currently set Expresso Services file.
214: *
215: * @return java.lang.String
216: */
217: public String getExpressoServicesFile() {
218: return this .fileName;
219: }
220:
221: /**
222: * Set the URL of the ExpressoServices File to load.
223: *
224: * @param url the new URL for the services file.
225: */
226: public void setExpressoServicesFile(URL url) {
227: if (log.isDebugEnabled()) {
228: log
229: .debug("Setting up to load Expresso Services file from: "
230: + url.toString());
231: }
232: this .fileURL = url;
233: }
234:
235: /**
236: * Retrieve the URL of the file that currently is set for the Expresso Services
237: * file.
238: *
239: * @return java.net.URL the location of the Expresso services file
240: */
241: public URL getExpressoServicesFileURL() {
242: return this .fileURL;
243: }
244:
245: /**
246: * <p>Set the rules for the digester<p>
247: * <p><b>TOTAL HACK WARNING!</b> Since Digester doesn't seem to allow recursive
248: * rules, we dynamically write rules for up to a maximum component depth of
249: * 20.</p>
250: *
251: * @param digester the digester instance to use.
252: */
253: protected void setDigesterRules(Digester digester) {
254: root = new ComponentConfig();
255: digester.push(root);
256: digester.addSetProperties("expresso-services");
257: digester.addCallMethod("expresso-services/property",
258: "addProperty", 2);
259: digester.addCallParam("expresso-services/property", 0, "name");
260: digester.addCallParam("expresso-services/property", 1, "value");
261:
262: digester.addCallMethod("expresso-services/mapped-property",
263: "addMappedProperty", 3);
264: digester.addCallParam("expresso-services/mapped-property", 0,
265: "name");
266: digester.addCallParam("expresso-services/mapped-property", 1,
267: "key");
268: digester.addCallParam("expresso-services/mapped-property", 2,
269: "value");
270:
271: digester.addCallMethod("expresso-services/indexed-property",
272: "addMappedProperty", 3);
273: digester.addCallParam("expresso-services/indexed-property", 0,
274: "name");
275: digester.addCallParam("expresso-services/indexed-property", 1,
276: "index");
277: digester.addCallParam("expresso-services/indexed-property", 2,
278: "value");
279:
280: for (int i = 0; i < MAX_NESTING; i++) {
281: String componentDepthString = getComponentDepthString(i);
282: digester
283: .addObjectCreate(
284: "expresso-services/" + componentDepthString
285: + "component",
286: com.jcorporate.expresso.kernel.digester.ComponentConfig.class);
287: digester.addSetProperties("expresso-services/"
288: + componentDepthString + "component", new String[] {
289: "name", "class-name" }, new String[] { "name",
290: "className" });
291: digester.addCallMethod("expresso-services/"
292: + componentDepthString + "component/property",
293: "addProperty", 2);
294: digester.addCallParam("expresso-services/"
295: + componentDepthString + "component/property", 0,
296: "name");
297: digester.addCallParam("expresso-services/"
298: + componentDepthString + "component/property", 1,
299: "value");
300:
301: digester.addCallMethod("expresso-services/"
302: + componentDepthString
303: + "component/mapped-property", "addMappedProperty",
304: 3);
305: digester.addCallParam("expresso-services/"
306: + componentDepthString
307: + "component/mapped-property", 0, "name");
308: digester.addCallParam("expresso-services/"
309: + componentDepthString
310: + "component/mapped-property", 1, "key");
311: digester.addCallParam("expresso-services/"
312: + componentDepthString
313: + "component/mapped-property", 2, "value");
314:
315: digester.addCallMethod("expresso-services/"
316: + componentDepthString
317: + "component/indexed-property",
318: "addMappedProperty", 3);
319: digester.addCallParam("expresso-services/"
320: + componentDepthString
321: + "component/indexed-property", 0, "name");
322: digester.addCallParam("expresso-services/"
323: + componentDepthString
324: + "component/indexed-property", 1, "index");
325: digester.addCallParam("expresso-services/"
326: + componentDepthString
327: + "component/indexed-property", 2, "value");
328:
329: digester.addSetNext("expresso-services/"
330: + componentDepthString + "component",
331: "addChildComponent");
332: }
333:
334: }
335:
336: private String getComponentDepthString(int index) {
337: FastStringBuffer fsb = FastStringBuffer.getInstance();
338: for (int i = 0; i < index; i++) {
339: fsb.append("component/");
340: }
341:
342: String returnValue = fsb.toString();
343: fsb.release();
344:
345: return returnValue;
346: }
347:
348: /**
349: * Returns the Root of the ComponentConfig tree generated by the Digester.
350: * May be null if there was a complete error
351: *
352: * @return base of the ComponentConfig tree.
353: */
354: public ComponentConfig getRootConfig() {
355: return root;
356: }
357:
358: /**
359: * Test for equality... two ExpressoServiceConfig objets are equal if all
360: * the components are the same and each ComponentConfig is completely equal.
361: * The files that are the sources DO NOT have to be equal.
362: *
363: * @param parm1 the object to compare against.
364: * @return boolean true if the two objects are indeed equal
365: */
366: public boolean equals(Object parm1) {
367: if (parm1 == null) {
368: return false;
369: }
370:
371: if (!(parm1 instanceof ExpressoServicesConfig)) {
372: return false;
373: }
374:
375: ExpressoServicesConfig other = (ExpressoServicesConfig) parm1;
376:
377: ComponentConfig root = getRootConfig();
378: ComponentConfig otherRoot = other.getRootConfig();
379:
380: if ((root == null) ^ (otherRoot == null)) {
381: return false;
382: }
383:
384: if (root == null && otherRoot == null) {
385: return true;
386: }
387:
388: return root.equals(otherRoot);
389: }
390:
391: /**
392: * Retrieve The 'name' of the runtime configuration. This is gleaned
393: * from the root configuration element who's name is set during the
394: * xml digestion.
395: *
396: * @return java.lang.String
397: */
398: public String getName() {
399: return root.getName();
400: }
401:
402: }
|