001: /* Copyright 2002 The JA-SIG Collaborative. All rights reserved.
002: * See license distributed with this file and
003: * available online at http://www.uportal.org/license.html
004: */
005:
006: package org.jasig.portal.car;
007:
008: import java.io.IOException;
009: import java.io.InputStream;
010: import java.util.Iterator;
011: import java.util.Map;
012: import java.util.Properties;
013: import java.util.Map.Entry;
014: import java.util.jar.JarFile;
015: import java.util.zip.ZipEntry;
016: import java.util.zip.ZipException;
017:
018: import javax.xml.parsers.FactoryConfigurationError;
019: import javax.xml.parsers.ParserConfigurationException;
020: import javax.xml.parsers.SAXParser;
021: import javax.xml.parsers.SAXParserFactory;
022:
023: import org.apache.commons.logging.Log;
024: import org.apache.commons.logging.LogFactory;
025: import org.jasig.portal.utils.SAX2BufferImpl;
026: import org.xml.sax.ContentHandler;
027: import org.xml.sax.SAXException;
028:
029: /**
030: * Class to parse the component deployment descriptor causing some tags to
031: * take action during parsing and others to cache information in the
032: * descriptor making it accessible via accessor methods.
033: *
034: * @author Mark Boyd {@link <a href="mailto:mark.boyd@engineer.com">mark.boyd@engineer.com</a>}
035: * @version $Revision: 36690 $
036: */
037: public class DescriptorHandler {
038: public final static String RCS_ID = "@(#) $Header$";
039: private static final Log log = LogFactory
040: .getLog(DescriptorHandler.class);
041: // variables that act as recipients of descriptor data
042: private Properties workers = new Properties();
043: private SAX2BufferImpl services = new SAX2BufferImpl();
044:
045: // define the supported tags
046: public static final String COMPONENT_TAG_NAME = "component";
047: public static final String WORKER_TAG_NAME = "worker";
048: public static final String SERVICE_TAG_NAME = "service";
049: public static final String EXTENSION_TAG_NAME = "ext";
050: public static final String CHANDEF_TAG_NAME = "channel-definition";
051: public static final String CHANTYPE_TAG_NAME = "channel-type";
052: public static final String DATABASE_TAG_NAME = "database";
053: public static final String PROCESS_TAG_NAME = "processIf";
054:
055: // define ancestry paths in the XML that identify specific sub-tree
056: // portions of the xml to be handled by different contentHandlers. This
057: // enables us to only use portions of the tree or the whole tree as needed.
058:
059: public static final Path COMPONENT = Path
060: .fromTag(COMPONENT_TAG_NAME);
061: public static final Path WORKERS = new Path().append(
062: COMPONENT_TAG_NAME).append(WORKER_TAG_NAME);
063: public static final Path PROCESS = new Path().append(
064: COMPONENT_TAG_NAME).append(PROCESS_TAG_NAME);
065: public static final Path SERVICES = new Path().append(
066: COMPONENT_TAG_NAME).append(SERVICE_TAG_NAME);
067: public static final Path EXTENSIONS = new Path().append(
068: COMPONENT_TAG_NAME).append(EXTENSION_TAG_NAME);
069: public static final Path CHANDEFS = new Path().append(
070: COMPONENT_TAG_NAME).append(CHANDEF_TAG_NAME);
071: public static final Path CHANTYPES = new Path().append(
072: COMPONENT_TAG_NAME).append(CHANTYPE_TAG_NAME);
073: public static final Path DBDEFS = new Path().append(
074: COMPONENT_TAG_NAME).append(DATABASE_TAG_NAME);
075:
076: /**
077: Constructs a new CAR descriptor handler that will parse the descriptor
078: passing relevant portions to handlers designed specifically for that
079: portion.
080: */
081: DescriptorHandler(JarFile jarFile) {
082: ParsingContext ctx = new ParsingContext(jarFile);
083:
084: PathRouter[] routers = new PathRouter[] {
085: new PathRouter(WORKERS, new WorkerTagHandler(workers)),
086: new PathRouter(SERVICES, services),
087: new PathRouter(DescriptorHandler.EXTENSIONS,
088: new ExtensionTagHandler(ctx)),
089: new PathRouter(DescriptorHandler.CHANDEFS,
090: new ChannelDefinitionTagHandler(ctx)),
091: new PathRouter(DescriptorHandler.CHANTYPES,
092: new ChannelTypeTagHandler(ctx)),
093: new PathRouter(DescriptorHandler.DBDEFS,
094: new DatabaseTagHandler(ctx)) };
095: parseDescriptor(jarFile, new ComponentTagHandler(ctx, routers));
096: }
097:
098: /**
099: Parse the deployment descriptor for a CAR. No need to synchronize since
100: private and only called from constructor.
101: */
102:
103: private void parseDescriptor(JarFile jarFile,
104: ComponentTagHandler handler) {
105: ZipEntry entry = jarFile
106: .getEntry(CarResources.DEPLOYMENT_DESCRIPTOR);
107: SAXParser parser = null;
108: InputStream is = null;
109:
110: if (entry == null) // should never happen
111: return;
112:
113: try {
114: is = jarFile.getInputStream(entry);
115: parser = SAXParserFactory.newInstance().newSAXParser();
116: } catch (ZipException ze) {
117: log.error("The zip entry "
118: + CarResources.DEPLOYMENT_DESCRIPTOR + " in "
119: + jarFile.getName()
120: + " has an invalid format. Details: " + ze);
121: } catch (IOException ioe) {
122: log.error("Unable to read entry "
123: + CarResources.DEPLOYMENT_DESCRIPTOR + " in "
124: + jarFile.getName() + ". Details: " + ioe);
125: } catch (SecurityException se) {
126: log.error("Unable to read entry "
127: + CarResources.DEPLOYMENT_DESCRIPTOR + " in "
128: + jarFile.getName()
129: + " because some entries are incorrectly signed. "
130: + "Details: " + se);
131: } catch (FactoryConfigurationError fce) {
132: log.error("Unable to read entry "
133: + CarResources.DEPLOYMENT_DESCRIPTOR + " in "
134: + jarFile.getName()
135: + " because a parser factory could not be created."
136: + " Details: " + fce);
137: } catch (ParserConfigurationException pce) {
138: log.error("Unable to read entry "
139: + CarResources.DEPLOYMENT_DESCRIPTOR + " in "
140: + jarFile.getName()
141: + " because a parser could not be created."
142: + " Details: " + pce);
143: } catch (SAXException sxe) {
144: log.error("Unable to read entry "
145: + CarResources.DEPLOYMENT_DESCRIPTOR + " in "
146: + jarFile.getName()
147: + " because a parser could not be created."
148: + " Details: " + sxe);
149: }
150:
151: try {
152: // can throw SAXException, IOException
153: parser.parse(is, handler);
154: } catch (RuntimeException re) {
155: log.error("Unable to completely parse entry "
156: + CarResources.DEPLOYMENT_DESCRIPTOR + " in "
157: + jarFile.getName()
158: + " because a fatal parser error occurred. ", re);
159: } catch (IOException ioe) {
160: log.error("Unable to completely parse entry "
161: + CarResources.DEPLOYMENT_DESCRIPTOR + " in "
162: + jarFile.getName(), ioe);
163: } catch (SAXException sxe) {
164: log.error("Unable to completely parse entry "
165: + CarResources.DEPLOYMENT_DESCRIPTOR + " in "
166: + jarFile.getName(), sxe);
167: } finally {
168: try {
169: if (is != null)
170: is.close();
171: } catch (IOException ioe) {
172: log.error("Unable to close inputStream", ioe);
173: }
174: }
175: }
176:
177: /////// Methods for use by CarResources to aquire descriptor info.
178:
179: /**
180: Adds to the passed in Properties object the names of workers and their
181: implementing classes as specified in the parsed deployment descriptor.
182: */
183: public synchronized void getWorkers(Properties p) {
184: if (workers.size() > 0) {
185: for (Iterator itr = workers.entrySet().iterator(); itr
186: .hasNext();) {
187: Map.Entry e = (Entry) itr.next();
188: if (!p.containsKey(e.getKey()))
189: p.put(e.getKey(), e.getValue());
190: }
191: }
192: }
193:
194: /**
195: Generates event calls to the passed in handler for service descriptions
196: extracted from the parsed the deployment descriptor.
197: */
198: public synchronized void getServices(ContentHandler c)
199: throws SAXException {
200: if (!services.isEmpty())
201: services.outputBuffer(c);
202: }
203: }
|