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.lang.reflect.Constructor;
009: import org.jasig.portal.properties.PropertiesManager;
010: import org.apache.commons.logging.Log;
011: import org.apache.commons.logging.LogFactory;
012: import org.xml.sax.Attributes;
013: import org.xml.sax.ContentHandler;
014: import org.xml.sax.SAXException;
015: import org.xml.sax.helpers.DefaultHandler;
016:
017: /**
018: * Processes all channel definitions located in a CAR and instantiates and
019: * delegates to an inner content handler for each block to do the real work
020: * of publishing.
021: *
022: * @author Mark Boyd {@link <a href="mailto:mark.boyd@engineer.com">mark.boyd@engineer.com</a>}
023: * @version $Revision: 36690 $
024: */
025: public class ChannelDefinitionTagHandler extends DefaultHandler {
026: private static final Log log = LogFactory
027: .getLog(ChannelDefinitionTagHandler.class);
028: private static Class cHandlerClass = null;
029: private static Constructor cDefaultConstructor = null;
030: private static Constructor cExtendedConstructor = null;
031:
032: private ContentHandler handlerInstance = null;
033: private ParsingContext ctx = null;
034:
035: private static final String HANDLER_PROPERTY = "org.jasig.portal.car.ChannelDefinition.contentHandler";
036:
037: /**
038: * Construct a ChannelDefinitionHandler that receives events from parsing
039: * a channel archive deployment descriptor but only for any contained
040: * channel-definition elements and their children.
041: *
042: * @param ctx
043: */
044: ChannelDefinitionTagHandler(ParsingContext ctx) {
045: this .ctx = ctx;
046:
047: if (cHandlerClass == null) {
048: initialize();
049: }
050: }
051:
052: /**
053: * Load an appropriate class for handling the channel definition content
054: * and publishing the channel specified therein.
055: */
056: private void initialize() {
057: String declaredClass = null;
058:
059: try {
060: declaredClass = PropertiesManager
061: .getProperty(HANDLER_PROPERTY);
062: } catch (Exception e) {
063: // no handler specified so use default.
064: }
065: if (declaredClass != null)
066: loadTheClass(declaredClass);
067: else
068: cHandlerClass = DefaultChanPubInnerHandler.class;
069:
070: if (cHandlerClass != null)
071: getTheConstructor();
072: }
073:
074: /**
075: * Attempt to load the class specified.
076: * @param handlerClass
077: */
078: private void loadTheClass(String handlerClass) {
079: try {
080: CarResources cRes = CarResources.getInstance();
081: ClassLoader cl = cRes.getClassLoader();
082: cHandlerClass = cl.loadClass(handlerClass);
083: } catch (ClassNotFoundException clfe) {
084: log.error("Specified contentHandler class " + handlerClass
085: + " specified in portal.properties not found. "
086: + "Ignoring channel-definition block "
087: + "in deployment descriptor of "
088: + ctx.getJarFile().getName() + ".");
089: }
090: }
091:
092: private void getTheConstructor() {
093: try {
094: cExtendedConstructor = cHandlerClass
095: .getConstructor(new Class[] { ParsingContext.class });
096: return;
097: } catch (NoSuchMethodException nsme) {
098: // since this constructor is optional ignore exception
099: // and try default construction.
100: }
101: try {
102: cDefaultConstructor = cHandlerClass
103: .getConstructor((Class[]) null);
104: } catch (NoSuchMethodException nsme) {
105: log.error("Niether Extended constructor nor default, zero "
106: + "parameter constructor were found "
107: + "for specified contentHandler class "
108: + cHandlerClass.getName()
109: + " specified in portal.properties. Ignoring "
110: + "channel-definition block "
111: + "in deployment descriptor of "
112: + ctx.getJarFile().getName() + ".", nsme);
113: }
114: }
115:
116: /**
117: * Attempt to load an instance of the class. The classes must support a
118: * default constructor but can optionally provide a constructor with a
119: * single argument of type DescriptorHandler. If found that constructor
120: * will be used. If not found then the default constructor wil be used.
121: *
122: * @return
123: */
124: private Object instantiateTheClass() {
125: Object obj = null;
126:
127: try {
128: if (cExtendedConstructor != null)
129: obj = cExtendedConstructor
130: .newInstance(new Object[] { ctx });
131: else if (cDefaultConstructor != null)
132: obj = cDefaultConstructor.newInstance(new Object[] {});
133: } catch (Exception e) {
134: log
135: .error(
136: "Unable to create specified contentHandler class "
137: + cHandlerClass.getName()
138: + " specified in portal.properties. Ignoring "
139: + "channel-definition block "
140: + "in deployment descriptor of "
141: + ctx.getJarFile().getName() + ".",
142: e);
143: }
144: return obj;
145: }
146:
147: /**
148: * Casts the object to a ContentHandler and logs any error that occurs.
149: *
150: * @param obj
151: * @return
152: */
153: private ContentHandler castToContentHandler(Object obj) {
154: ContentHandler handler = null;
155:
156: try {
157: handler = (ContentHandler) obj;
158: } catch (ClassCastException cce) {
159: log.error("ContentHandler class "
160: + obj.getClass().getName()
161: + " specified in portal.properties"
162: + " does not implement ContentHandler."
163: + " Ignoring channel-definition block in"
164: + " deployment descriptor of "
165: + ctx.getJarFile().getName() + ".");
166: }
167: return handler;
168: }
169:
170: ///////////////////// Content Handler Implementations //////////////////
171:
172: /**
173: * Handle start element events.
174: */
175: public void startElement(String namespaceURI, String localName,
176: String qName, Attributes atts) throws SAXException {
177: // if starting a new channel definition then instantiate a new
178: // inner handler to which to pass events
179: if (qName.equals(DescriptorHandler.CHANDEF_TAG_NAME)
180: && ctx.getPath().equals(DescriptorHandler.CHANDEFS)) {
181: if (cHandlerClass != null) {
182: Object obj = instantiateTheClass();
183: handlerInstance = castToContentHandler(obj);
184: }
185: }
186:
187: if (handlerInstance != null)
188: handlerInstance.startElement(namespaceURI, localName,
189: qName, atts);
190: }
191:
192: /**
193: * Handle the characters event to capture textual content for elements.
194: */
195: public void characters(char[] ch, int start, int length)
196: throws SAXException {
197: if (handlerInstance != null)
198: handlerInstance.characters(ch, start, length);
199: }
200:
201: /**
202: * Handle the closing element event.
203: */
204: public void endElement(String namespaceURI, String localName,
205: String qName) throws SAXException {
206: // while within channel-definition block handler will be non-null and
207: // should receive all events.
208: if (handlerInstance != null)
209: handlerInstance.endElement(namespaceURI, localName, qName);
210:
211: if (qName.equals(DescriptorHandler.CHANDEF_TAG_NAME)
212: && ctx.getPath().equals(DescriptorHandler.CHANDEFS)) {
213: // leaving block so remove the handler in prep for a new
214: // block
215: handlerInstance = null;
216: }
217: }
218: }
|