package com.dbxml.labrador.broker;
/*
* The dbXML Labrador Software License, Version 1.0
*
*
* Copyright (c) 2003 The dbXML Group, L.L.C. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* 3. The end-user documentation included with the redistribution,
* if any, must include the following acknowledgment:
* "This product includes software developed by The
* dbXML Group, L.L.C. (http://www.dbxml.com/)."
* Alternately, this acknowledgment may appear in the software
* itself, if and wherever such third-party acknowledgments normally
* appear.
*
* 4. The names "Labrador" and "dbXML Group" must not be used to
* endorse or promote products derived from this software without
* prior written permission. For written permission, please contact
* info@dbxml.com
*
* 5. Products derived from this software may not be called "Labrador",
* nor may "Labrador" appear in their name, without prior written
* permission of The dbXML Group, L.L.C..
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE DBXML GROUP, L.L.C. OR ITS
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* $Id: Configurator.java,v 1.10 2003/10/06 17:36:32 bradford Exp $
*/
import com.dbxml.labrador.Describer;
import com.dbxml.labrador.Filter;
import com.dbxml.labrador.Handler;
import com.dbxml.labrador.Resolver;
import com.dbxml.labrador.configuration.Configurable;
import com.dbxml.labrador.configuration.Configuration;
import com.dbxml.labrador.configuration.ConfigurationCallback;
import com.dbxml.labrador.configuration.ConfigurationException;
import com.dbxml.labrador.util.DOMHelper;
import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URL;
import java.util.StringTokenizer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.xml.sax.SAXException;
/**
* Configurator is a utility class that offloads the Broker
* configuration responsibility.
*/
final class Configurator {
private static final int BUFFER_SIZE = 8192;
private static final String ELEM_LABRADOR = "labrador";
private static final int TYPE_RESOLVER = 0;
private static final int TYPE_DESCRIBER = 1;
private static final int TYPE_HANDLER = 2;
private static final int TYPE_FILTER = 3;
private static final int TYPE_INSTANCE = 4;
private static final String[] ELEM_NAMES = {"resolver",
"describer",
"handler",
"filter",
"instance"};
private static final Class[] ELEM_CLASSES = {Resolver.class,
Describer.class,
Handler.class,
Filter.class,
Object.class};
private static final String ELEM_ROOT = "root";
private static final String ATTR_CLASS = "class";
private static final String ATTR_STATIC = "static";
private static final String ATTR_NAME = "name";
private static final String ATTR_INITIALIZER = "initializer";
private static final String METHOD_SETCONFIG = "setConfig";
private Broker broker;
public Configurator(Broker broker) {
this.broker = broker;
}
public void configure() {
Broker.println("Labrador Broker Initialization");
String config = System.getProperty(Broker.PROP_CONFIG);
if ( config != null && config.length() > 0 ) {
try {
if ( config.indexOf("://") != -1 ) {
// Load config from a URL
URL url = new URL(config);
InputStream is = url.openStream();
BufferedInputStream bis = new BufferedInputStream(is, BUFFER_SIZE);
loadConfiguration(bis);
is.close();
}
else {
// Load config from a File
FileInputStream fis = new FileInputStream(config);
BufferedInputStream bis = new BufferedInputStream(fis, BUFFER_SIZE);
loadConfiguration(bis);
fis.close();
}
return;
}
catch ( Exception e ) {
Broker.printwarning("Labrador Configuration Error");
Broker.printwarning(" '" + config + "' " + e.getMessage());
Broker.printwarning(" Falling back to internal configuration");
}
}
// Fall back to the resource based config
try {
InputStream is = this.getClass().getResourceAsStream(Broker.DEFAULT_CONFIG);
BufferedInputStream bis = new BufferedInputStream(is, BUFFER_SIZE);
loadConfiguration(bis);
is.close();
}
catch ( Exception e ) {
Broker.printerr("Labrador Configuration Error");
Broker.printerr(" Default configuration cannot be read");
Broker.printerr(" " + e.getMessage());
}
String instances = System.getProperty(Broker.PROP_INSTANCES);
if ( instances != null ) {
try {
Document doc = DOMHelper.newDocument();
Element root = doc.createElement(ELEM_ROOT);
doc.appendChild(root);
StringTokenizer st = new StringTokenizer(instances, ",");
while ( st.hasMoreTokens() ) {
String className = st.nextToken();
if ( className.trim().length() != -1 ) {
Element instElem = doc.createElement(ELEM_NAMES[TYPE_INSTANCE]);
root.appendChild(instElem);
int idx = className.indexOf('=');
if ( idx != -1 ) {
String instName = className.substring(0, idx);
className = className.substring(idx + 1);
instElem.setAttribute(ATTR_NAME, instName);
}
instElem.setAttribute(ATTR_CLASS, className);
Configuration cfg = new Configuration(instElem);
Object o = constructInstance(cfg, ELEM_CLASSES[TYPE_INSTANCE]);
Broker.println("Instance: " + o.getClass().getName());
}
}
}
catch ( Exception e ) {
Broker.printerr("Labrador Configuration Error");
Broker.printerr(" " + e.getMessage());
}
}
}
private void loadConfiguration(InputStream is) throws ConfigurationException, IOException {
try {
Document doc = DOMHelper.parse(is);
Configuration root = new Configuration(doc);
if ( !root.getName().equals(ELEM_LABRADOR) )
throw new IOException("Invalid configuration format");
root.processChildren(new ConfigurationCallback() {
public void process(Configuration cfg) {
for ( int j = 0; j < ELEM_NAMES.length; j++ ) {
if ( cfg.getName().equals(ELEM_NAMES[j]) ) {
Class c = ELEM_CLASSES[j];
Object o = constructInstance(cfg, c);
if ( o != null ) {
switch ( j ) {
case TYPE_RESOLVER:
broker.addResolver((Resolver)o);
break;
case TYPE_DESCRIBER:
broker.addDescriber((Describer)o);
break;
case TYPE_HANDLER:
broker.addHandler((Handler)o);
break;
case TYPE_FILTER:
broker.addFilter((Filter)o);
break;
case TYPE_INSTANCE:
Broker.println("Instance: " + o.getClass().getName());
break;
}
}
continue;
}
}
}
});
}
catch ( SAXException e ) {
Broker.printerr("Labrador Configuration Error");
Broker.printerr(" Couldn't parse configuration");
Broker.printerr(" " + e.getMessage());
return;
}
}
private Object constructInstance(Configuration cfg, Class comp) {
try {
Class c = Class.forName(cfg.getAttribute(ATTR_CLASS));
if ( comp != null && c.getClass().isAssignableFrom(comp) ) {
Broker.printerr("Labrador Configuration Error");
Broker.printerr(" Class is not compatible");
Broker.printerr(" " + comp.getName());
return null;
}
String nameValue = cfg.getAttribute(ATTR_NAME);
if ( cfg.getBooleanAttribute(ATTR_STATIC) ) {
try {
// If an initializer attribute is specified, call it either
// passing the specified name or void parameters.
String initValue = cfg.getAttribute(ATTR_INITIALIZER);
if ( initValue != null && initValue.length() > 0 ) {
if ( nameValue != null && nameValue.length() > 0 ) {
Method m = c.getMethod(initValue, new Class[]{String.class});
int mods = m.getModifiers();
if ( Modifier.isStatic(mods) && Modifier.isPublic(mods) )
m.invoke(c, new Object[]{nameValue});
}
else {
Method m = c.getMethod(initValue, new Class[0]);
int mods = m.getModifiers();
if ( Modifier.isStatic(mods) && Modifier.isPublic(mods) )
m.invoke(c, new Object[0]);
}
}
}
catch ( Exception e ) {
Broker.printerr("Labrador Configuration Error");
Broker.printerr(" Couldn't find initializer method");
Broker.printerr(" " + e.getMessage());
}
try {
// If this is a static instance, check for a static setConfig
// method and call it with the current Configuration object
Method m = c.getMethod(METHOD_SETCONFIG, new Class[]{Configuration.class});
if ( m != null ) {
int mods = m.getModifiers();
if ( Modifier.isStatic(mods) && Modifier.isPublic(mods) )
m.invoke(c, new Object[]{cfg});
}
}
catch ( Exception e ) {
// If it doesn't have the setConfig method, then no biggie
}
return null;
}
else {
Object obj;
// If a name is specified, construct the object with the name
// as a parameter, otherwise use the default constructor.
if ( nameValue != null && nameValue.length() > 0 ) {
Constructor constructor = c.getConstructor(new Class[]{String.class});
obj = constructor.newInstance(new Object[]{nameValue});
}
else
obj = c.newInstance();
// If the object is Configurable, call setMethod with the
// current Configuration object.
if ( obj instanceof Configurable )
((Configurable)obj).setConfig(cfg);
return obj;
}
}
catch ( Exception ex ) {
ex.printStackTrace(System.err);
Broker.printerr("Labrador Configuration Error");
Broker.printerr(" Couldn't create class instance");
Broker.printerr(" " + ex.getMessage());
return null;
}
}
}