001: /* Copyright 2001 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.services;
007:
008: import java.io.IOException;
009: import java.io.InputStream;
010: import java.lang.reflect.Array;
011: import java.lang.reflect.Method;
012: import java.lang.reflect.Modifier;
013: import java.util.ArrayList;
014: import java.util.List;
015:
016: import javax.naming.Context;
017: import javax.xml.parsers.SAXParser;
018: import javax.xml.parsers.SAXParserFactory;
019:
020: import org.apache.commons.logging.Log;
021: import org.apache.commons.logging.LogFactory;
022: import org.jasig.portal.PortalException;
023: import org.jasig.portal.car.CarResources;
024: import org.jasig.portal.utils.DTDResolver;
025: import org.jasig.portal.utils.ResourceLoader;
026: import org.xml.sax.Attributes;
027: import org.xml.sax.ContentHandler;
028: import org.xml.sax.InputSource;
029: import org.xml.sax.XMLReader;
030: import org.xml.sax.helpers.XMLReaderFactory;
031:
032: /**
033: * ExternalServices starts up all the runtime services for the uPortal.
034: * These services can be customized at an installation location by editing the
035: * services.xml file under the properties directory. For example, the
036: * connection pooling is a service that can be provided by different vendor
037: * implementations.
038: * Services are bound into the uPortal /services JNDI branch if <jndiname/> element
039: * is specified in the service description.
040: *
041: * @author Sridhar Venkatesh <svenkatesh@interactivebusiness.com>
042: * @version $Revision: 36612 $
043: */
044: public class ExternalServices {
045:
046: private static final Log log = LogFactory
047: .getLog(ExternalServices.class);
048:
049: private ServiceHandler svcHandler;
050: private Context servicesContext;
051:
052: public ExternalServices(Context servicesContext) {
053: this .servicesContext = servicesContext;
054: svcHandler = new ServiceHandler();
055: }
056:
057: public static void startServices(Context servicesContext)
058: throws PortalException {
059:
060: InputStream svcDescriptor = null;
061:
062: try {
063: svcDescriptor = ResourceLoader.getResourceAsStream(
064: ExternalServices.class, "/properties/services.xml");
065: } catch (Exception ex) {
066: throw new PortalException(
067: "Failed to load services.xml. External "
068: + "portal services will not be started", ex);
069: }
070:
071: CarResources cRes = CarResources.getInstance();
072:
073: if (svcDescriptor != null || cRes.hasDescriptors()) {
074: ExternalServices svcMgr = new ExternalServices(
075: servicesContext);
076:
077: if (cRes.hasDescriptors()) {
078: try {
079: cRes
080: .getServices((ContentHandler) svcMgr.svcHandler);
081: } catch (Exception ex) {
082: throw new PortalException(
083: "Failed to start external portal "
084: + "services in CAR descriptors.",
085: ex);
086: }
087: }
088: if (svcDescriptor != null) {
089: try {
090: XMLReader parser = XMLReaderFactory
091: .createXMLReader();
092: parser.setEntityResolver(new DTDResolver(
093: "services.dtd"));
094: parser.setContentHandler(svcMgr.svcHandler);
095: parser.parse(new InputSource(svcDescriptor));
096: } catch (Exception ex) {
097: throw new PortalException(
098: "Failed to start external portal "
099: + "services defined in services.xml.",
100: ex);
101: } finally {
102: try {
103: svcDescriptor.close(); //do not need to check for null.
104: } catch (IOException exception) {
105: log
106: .error("ExternalServices:startServices()::could not close InputStream "
107: + exception);
108: }
109: }
110: }
111: }
112: }
113:
114: protected SAXParser createParser() throws Exception {
115: SAXParserFactory factory = SAXParserFactory.newInstance();
116: return factory.newSAXParser();
117: }
118:
119: /**
120: * Controls output of ExternalServices.
121: * @param msg a string to output
122: */
123: protected void outputMessage(String msg) {
124: System.out.println("External services: " + msg);
125: log.info("External services: " + msg);
126: }
127:
128: /**
129: * Returns the appropriate class for the given class name. Checks to see
130: * whether the class belongs to a primitive data type or a Java Object.
131: * @param className - Name of the class. Primitive datatypes must be specified
132: * as xxx.class or Xxxx.TYPE. (e.g. int.class or Integer.TYPE).
133: */
134: public static Class getClassObject(String className)
135: throws Exception {
136: if ((className.indexOf("TYPE") != -1)
137: || (className.indexOf("class") != -1)) {
138: if (className.equals("boolean.class")
139: || className.equals("Boolean.TYPE")) {
140: return Boolean.TYPE;
141: } else if (className.equals("byte.class")
142: || className.equals("Byte.TYPE")) {
143: return Byte.TYPE;
144: } else if (className.equals("short.class")
145: || className.equals("Short.TYPE")) {
146: return Short.TYPE;
147: } else if (className.equals("char.class")
148: || className.equals("Char.TYPE")) {
149: return java.lang.Character.TYPE;
150: } else if (className.equals("int.class")
151: || className.equals("Integer.TYPE")) {
152: return Integer.TYPE;
153: } else if (className.equals("long.class")
154: || className.equals("Long.TYPE")) {
155: return Long.TYPE;
156: } else if (className.equals("float.class")
157: || className.equals("Float.TYPE")) {
158: return Float.TYPE;
159: } else if (className.equals("double.class")
160: || className.equals("Double.TYPE")) {
161: return Double.TYPE;
162: }
163: } else {
164: return CarResources.getInstance().getClassLoader()
165: .loadClass(className);
166: }
167: return null;
168: }
169:
170: class ServiceItem {
171: StringBuffer name = new StringBuffer("");
172: StringBuffer javaClass = new StringBuffer("");
173: StringBuffer jndiName = new StringBuffer("");
174: StringBuffer startMethod = new StringBuffer("");
175: StringBuffer methodType = new StringBuffer("");
176: List argList;
177:
178: public void setName(String svcName) {
179: name.append(svcName);
180: }
181:
182: public String getName() {
183: return name.toString();
184: }
185:
186: public void setJavaClass(String svcClass) {
187: javaClass.append(svcClass);
188: }
189:
190: public String getJavaClass() {
191: return javaClass.toString();
192: }
193:
194: public void setStartMethod(String methodName) {
195: startMethod.append(methodName);
196: }
197:
198: public String getStartMethod() {
199: return startMethod.toString();
200: }
201:
202: public void setJndiName(String name) {
203: this .jndiName.append(name);
204: }
205:
206: public String getJndiName() {
207: return jndiName.toString();
208: }
209:
210: public void setMethodType(String type) {
211: methodType.append(type);
212: }
213:
214: public boolean isStatic() {
215: return (methodType.length() > 0);
216: }
217:
218: public void addArgument(Argument argItem) {
219: if (argList == null)
220: argList = new ArrayList();
221:
222: argList.add(argItem);
223: }
224:
225: public Object[] getArguments() throws Exception {
226: Object[] args;
227:
228: if (argList != null) {
229: args = new Object[argList.size()];
230: for (int i = 0; i < argList.size(); i++) {
231: Argument argItem = (Argument) argList.get(i);
232: args[i] = argItem.getValue();
233: }
234: } else
235: args = new Object[0];
236:
237: return args;
238: }
239:
240: public Class[] getArgumentClasses() throws Exception {
241: Class[] classNames = null;
242:
243: if (argList != null) {
244: classNames = new Class[argList.size()];
245:
246: for (int i = 0; i < argList.size(); i++) {
247: Argument argItem = (Argument) argList.get(i);
248: String className = argItem.getDataType();
249:
250: if (argItem.getArray()) {
251: classNames[i] = Array.newInstance(
252: getClassObject(className), 1)
253: .getClass();
254: } else {
255: classNames[i] = getClassObject(className);
256: }
257: }
258: }
259:
260: return classNames;
261: }
262: }
263:
264: class Argument {
265: String datatype;
266: boolean array;
267: ArrayList values = new ArrayList(); // when array=true, there may be more than one value
268:
269: public void addValue(String argValue) {
270: values.add(argValue);
271: }
272:
273: public String getDataType() {
274: return datatype;
275: }
276:
277: public void setDataType(String argDataType) {
278: datatype = argDataType;
279: }
280:
281: public boolean getArray() {
282: return array;
283: }
284:
285: public void setArray(boolean b) {
286: array = b;
287: }
288:
289: public Object getValue() throws Exception {
290: Object value = null;
291: if (array) {
292: value = Array.newInstance(getClassObject(datatype),
293: values.size());
294: for (int i = 0; i < values.size(); i++) {
295: Array.set(value, i, values.get(i));
296: }
297: } else {
298: value = getValue(datatype, (String) values.get(0));
299: }
300: return value;
301: }
302:
303: private Object getValue(String className, String value)
304: throws Exception {
305: if ((className.indexOf("TYPE") != -1)
306: || (className.indexOf("class") != -1)) {
307: try {
308: if (className.equals("boolean.class")
309: || className.equals("BOOLEAN.TYPE")) {
310: return new Boolean(value);
311: } else if (className.equals("byte.class")
312: || className.equals("Byte.TYPE")) {
313: return new Byte(value);
314: } else if (className.equals("short.class")
315: || className.equals("Short.TYPE")) {
316: return new Short(value);
317: } else if (className.equals("char.class")
318: || className.equals("Char.TYPE")) {
319: return new java.lang.Character(value.charAt(0));
320: } else if (className.equals("int.class")
321: || className.equals("Integer.TYPE")) {
322: return new Integer(value);
323: } else if (className.equals("long.class")
324: || className.equals("Long.TYPE")) {
325: return new Long(value);
326: } else if (className.equals("float.class")
327: || className.equals("Float.TYPE")) {
328: return new Float(value);
329: } else if (className.equals("double.class")
330: || className.equals("Double.TYPE")) {
331: return new Double(value);
332: }
333: } catch (NumberFormatException nfe) {
334: outputMessage("Cannot convert " + value
335: + " to declared datatype class "
336: + className);
337: }
338: } else {
339: return value;
340: }
341: return null;
342: }
343: }
344:
345: class ServiceHandler extends org.xml.sax.helpers.DefaultHandler {
346: ServiceItem svcItem;
347: String elementName;
348: Argument argItem;
349: boolean argProcessing = false;
350: boolean jndiNameporcessing = false;
351:
352: public void startElement(String namespaceURI, String localName,
353: String qName, Attributes atts) {
354: elementName = qName;
355: if (qName.equals("service")) {
356: svcItem = new ServiceItem();
357: } else if (qName.equals("method")) {
358: svcItem.setMethodType(atts.getValue("type"));
359: } else if (qName.equals("arguments")) {
360: argProcessing = true;
361: } else if (qName.equals("argitem")) {
362: argItem = new Argument();
363: } else if (qName.equals("datatype")) {
364: String array = atts.getValue("array");
365: argItem.setArray(array != null && array.equals("true"));
366: }
367: }
368:
369: public void endElement(String namespaceURI, String localName,
370: String qName) {
371: elementName = null; // The element has ended. Null it.
372:
373: if (qName.equals("service")) {
374: String javaClass = svcItem.getJavaClass();
375: Class[] classNames = null;
376: Object[] args = null;
377: Class svcClass = null;
378:
379: try {
380: svcClass = CarResources.getInstance()
381: .getClassLoader().loadClass(javaClass);
382: args = svcItem.getArguments();
383: classNames = svcItem.getArgumentClasses();
384: } catch (java.lang.ClassNotFoundException cnfe) {
385: outputMessage("Class not found - "
386: + cnfe.getMessage());
387: return;
388: } catch (Exception e) {
389: outputMessage("The service \"" + svcItem.getName()
390: + "\" FAILED TO START.");
391: return;
392: }
393:
394: try {
395: Object obj = null;
396: Object returnObject = null;
397:
398: // check if any method is specified
399: if (svcItem.getStartMethod().length() > 0) {
400: Method startMethod = svcClass.getMethod(svcItem
401: .getStartMethod(), classNames);
402: if (Modifier.isStatic(startMethod
403: .getModifiers())) {
404: // no need to instantiate an object
405: returnObject = startMethod.invoke(null,
406: args);
407: } else {
408: // instantiate
409: obj = svcClass.newInstance();
410: returnObject = startMethod
411: .invoke(obj, args);
412: }
413: outputMessage("initialized \""
414: + svcItem.getName() + "\"");
415: }
416:
417: // check if jndi binding needed
418: if (svcItem.getJndiName().length() > 0) {
419: if (returnObject != null) {
420: // a non-void method was specified
421: // in the service description, bind
422: // returned object
423: servicesContext.bind(svcItem.getJndiName(),
424: returnObject);
425: outputMessage("bound intialization result for service \""
426: + svcItem.getName() + "\"");
427: } else {
428: if (obj == null) {
429: // instantiate
430: obj = svcClass.newInstance();
431: }
432: servicesContext.bind(svcItem.getJndiName(),
433: obj);
434: outputMessage("bound class instance for service \""
435: + svcItem.getName() + "\"");
436: }
437: }
438: return;
439: } catch (java.lang.NoSuchMethodException nsme) {
440: outputMessage("Method not found - "
441: + nsme.getMessage());
442: } catch (java.lang.Exception ex) {
443: outputMessage("General Exception - "
444: + ex.getMessage());
445: ex.printStackTrace();
446: }
447: outputMessage("The service \"" + svcItem.getName()
448: + "\" FAILED TO START.");
449:
450: } else if (qName.equals("arguments")) {
451: argProcessing = false;
452: } else if (qName.equals("argitem")) {
453: svcItem.addArgument(argItem);
454: argItem = null;
455: }
456: }
457:
458: public void characters(char ch[], int start, int length) {
459: if (elementName == null)
460: return;
461:
462: String chValue = new String(ch, start, length);
463:
464: if (elementName.equals("name")) {
465: svcItem.setName(chValue);
466: } else if (elementName.equals("class")) {
467: svcItem.setJavaClass(chValue);
468: } else if (elementName.equals("jndi_name")) {
469: svcItem.setJndiName(chValue);
470: } else if (elementName.equals("method")) {
471: svcItem.setStartMethod(chValue);
472: } else if (elementName.equals("datatype") && argProcessing) {
473: argItem.setDataType(chValue);
474: } else if (elementName.equals("value")) {
475: if (argProcessing) {
476: argItem.addValue(chValue);
477: }
478: }
479: }
480: }
481: }
|