nx01/nx01-x4o-driver/src/main/java/org/x4o/xml/X4ODriverManager.java

312 lines
12 KiB
Java

/*
* Copyright (c) 2004-2014, Willem Cazander
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
* that the following conditions are met:
*
* * Redistributions of source code must retain the above copyright notice, this list of conditions and the
* following disclaimer.
* * 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.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS 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 COPYRIGHT HOLDER OR 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.
*/
package org.x4o.xml;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import org.x4o.xml.lang.DefaultX4OLanguage;
import org.x4o.xml.lang.DefaultX4OLanguageConfiguration;
import org.x4o.xml.lang.X4OLanguage;
import org.x4o.xml.lang.X4OLanguageClassLoader;
import org.x4o.xml.lang.X4OLanguageConfiguration;
import org.x4o.xml.lang.phase.DefaultX4OPhaseManager;
import org.x4o.xml.lang.phase.X4OPhaseException;
import org.x4o.xml.lang.phase.X4OPhaseLanguageInit;
import org.x4o.xml.lang.phase.X4OPhaseLanguageRead;
import org.x4o.xml.lang.phase.X4OPhaseLanguageWrite;
import org.x4o.xml.lang.phase.X4OPhaseManager;
import org.x4o.xml.lang.phase.X4OPhaseType;
import org.x4o.xml.lang.task.X4OLanguageTask;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.ext.DefaultHandler2;
/**
* X4ODriverManager controls all the x4o driver and languages loaded in the class-path.
*
* @author Willem Cazander
* @version 1.0 Apr 6, 2013
*/
public final class X4ODriverManager {
public final static String X4O_DRIVERS_RESOURCE = "META-INF/x4o-drivers.xml";
private final static X4ODriverManager instance;
private Logger logger = null;
private volatile boolean reloadDrivers = true;
private Map<String, String> classdrivers = null;
private Map<String, String> defaultDrivers = null;
private Map<String, X4ODriver<?>> drivers = null;
private Map<String, X4OLanguageTask> languageTasks = null;
private X4ODriverManager() {
logger = Logger.getLogger(X4ODriverManager.class.getName());
classdrivers = new HashMap<String, String>(10);
defaultDrivers = new HashMap<String, String>(10);
drivers = new HashMap<String, X4ODriver<?>>(10);
languageTasks = new HashMap<String, X4OLanguageTask>(10);
}
static {
instance = new X4ODriverManager();
}
private void registerX4OLanguageTask(String className) {
try {
X4OLanguageTask task = (X4OLanguageTask) X4OLanguageClassLoader.newInstance(className);
if (languageTasks.containsKey(task.getId())) {
throw new RuntimeException("Can't add duplicate language task: " + task.getId());
}
languageTasks.put(task.getId(), task);
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
static public X4OLanguageTask getX4OLanguageTask(String taskId) {
instance.lazyInit(); // fixme
return instance.languageTasks.get(taskId);
}
static public List<X4OLanguageTask> getX4OLanguageTasks() {
instance.lazyInit(); // fixme
return new ArrayList<X4OLanguageTask>(instance.languageTasks.values());
}
static protected String getDefaultLanguageVersion(String[] languages) {
if (languages == null || languages.length == 0) {
return X4ODriver.DEFAULT_LANGUAGE_VERSION;
}
String languageVersion = languages[languages.length - 1];
return languageVersion;
}
static protected X4OPhaseManager getDefaultBuildPhaseManager() {
DefaultX4OPhaseManager manager = new DefaultX4OPhaseManager();
new X4OPhaseLanguageInit().createPhases(manager);
new X4OPhaseLanguageRead().createPhases(manager);
new X4OPhaseLanguageWrite().createPhases(manager);
return manager;
}
static protected X4OLanguage getDefaultBuildLanguage(X4ODriver<?> driver, String version) {
if (version == null) {
version = driver.getLanguageVersionDefault();
}
DefaultX4OLanguage result = new DefaultX4OLanguage(driver.buildLanguageConfiguration(), driver.buildPhaseManager(), driver.getLanguageName(), version);
try {
result.getPhaseManager().runPhases(result.createLanguageSession(), X4OPhaseType.INIT); // TODO: fix phase to interface T
} catch (X4OPhaseException e) {
throw new RuntimeException(e); // TODO: change layer
}
return result;
}
static protected X4OLanguageConfiguration getDefaultBuildLanguageConfiguration() {
DefaultX4OLanguageConfiguration config = new DefaultX4OLanguageConfiguration();
config.fillDefaults();
X4OLanguageConfiguration result = config.createProxy();
return result;
}
static public void registerX4ODriver(X4ODriver<?> driver) {
if (driver == null) {
throw new NullPointerException("Can't register null driver.");
}
if (driver.getLanguageName() == null) {
throw new NullPointerException("Error in driver impl languageName is null in: " + driver.getClass());
}
if (driver.getLanguageName().length() == 0) {
throw new IllegalArgumentException("Error in driver impl languageName is empty in: " + driver.getClass());
}
if (driver.getLanguageVersions() == null) {
throw new NullPointerException("Error in driver impl languageVersions is null in: " + driver.getClass());
}
if (driver.getLanguageVersions().length == 0) {
throw new IllegalArgumentException("Error in driver impl languageVersions is empty in: " + driver.getClass());
}
instance.drivers.put(driver.getLanguageName(), driver);
}
static public void deregisterX4ODriver(X4ODriver<?> driver) {
if (driver == null) {
throw new NullPointerException("Can't deregister null driver.");
}
if (driver.getLanguageName() == null) {
throw new NullPointerException("Error in driver impl languageName is null in: " + driver.getClass());
}
instance.drivers.remove(driver.getLanguageName());
}
static public X4ODriver<?> getX4ODriver(String language) {
if (language == null) {
throw new NullPointerException("Can't provider driver for null language.");
}
if (language.length() == 0) {
throw new IllegalArgumentException("Can't provider driver for empty language.");
}
if (instance.drivers.containsKey(language)) {
return instance.drivers.get(language);
}
instance.lazyInit();
X4ODriver<?> result = instance.createX4ODriver(language);
if (result == null) {
throw new IllegalArgumentException("Can't find driver for language: " + language);
}
return result;
}
static public List<String> getX4OLanguages() {
instance.lazyInit();
List<String> result = new ArrayList<String>(10);
result.addAll(instance.classdrivers.keySet());
result.addAll(instance.defaultDrivers.keySet());
Collections.sort(result);
return result;
}
private void lazyInit() {
if (reloadDrivers == false) {
return;
}
instance.loadLanguageDrivers();
reloadDrivers = false;
}
private X4ODriver<?> createX4ODriver(String language) {
String driverClassName = null;
if (classdrivers.containsKey(language)) {
driverClassName = classdrivers.get(language);
} else if (defaultDrivers.containsKey(language)) {
driverClassName = defaultDrivers.get(language);
}
if (driverClassName == null) {
return null;
}
try {
Class<?> driverClass = X4OLanguageClassLoader.loadClass(driverClassName);
// Constructor<?> markedConstructor = driverClass.getDeclaredConstructor(new Class[]{ConstructorMarker.class});
// X4ODriver<?> driver = (X4ODriver<?>)markedConstructor.newInstance(new Object[]{new ConstructorMarker()});
X4ODriver<?> driver = (X4ODriver<?>) X4OLanguageClassLoader.newInstance(driverClass);
registerX4ODriver(driver);
return driver;
} catch (ClassNotFoundException e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
/*
* TODO: Class to make sure all driver instances are created by this manager instance.
*
* final public class ConstructorMarker { private ConstructorMarker() { } }
*/
/**
* Loads all defined language drivers in classpath.
*/
private void loadLanguageDrivers() {
logger.finer("loading x4o drivers from: " + X4O_DRIVERS_RESOURCE);
try {
Enumeration<URL> e = Thread.currentThread().getContextClassLoader().getResources(X4O_DRIVERS_RESOURCE);
while (e.hasMoreElements()) {
URL u = e.nextElement();
loadDriversXml(u.openStream());
}
e = Thread.currentThread().getContextClassLoader().getResources("/" + X4O_DRIVERS_RESOURCE);
while (e.hasMoreElements()) {
URL u = e.nextElement();
loadDriversXml(u.openStream());
}
} catch (Exception e) {
throw new IllegalStateException(e.getMessage(), e);
}
}
/**
* Parser xml inputstream and add into drivers and defaultDrivers lists.
*
* @param in The inputstream to parser.
* @throws IOException
* @throws SAXException
* @throws ParserConfigurationException
*/
private void loadDriversXml(InputStream in) throws IOException, SAXException, ParserConfigurationException {
if (in == null) {
throw new NullPointerException("Can't parse null input stream");
}
DriversTagHandler xth = new DriversTagHandler();
SAXParserFactory factory = SAXParserFactory.newInstance();
factory.setNamespaceAware(true);
SAXParser parser = factory.newSAXParser();
XMLReader reader = parser.getXMLReader();
reader.setContentHandler(xth);
reader.setProperty("http://xml.org/sax/properties/lexical-handler", xth);
reader.setProperty("http://xml.org/sax/properties/declaration-handler", xth);
try {
reader.parse(new InputSource(in));
} finally {
in.close();
}
}
private class DriversTagHandler extends DefaultHandler2 {
@Override
public void startElement(String namespaceUri, String tag, String qName, Attributes attr) throws SAXException {
if ("drivers".equals(tag)) {
String version = attr.getValue("version");
logger.finest("Version attribute: " + version);
} else if ("driver".equals(tag)) {
String language = attr.getValue("language");
String className = attr.getValue("className");
logger.finest("Driver className: " + className + " for language: " + language);
if (classdrivers.containsKey(className) == false) {
classdrivers.put(language, className);
}
} else if ("defaultDriver".equals(tag)) {
String language = attr.getValue("language");
logger.finest("DefaultDriver language: " + language);
if (defaultDrivers.containsKey(language) == false) {
defaultDrivers.put(language, language);
}
} else if ("languageTask".equals(tag)) {
String className = attr.getValue("className");
logger.finest("Language task className: " + className);
X4ODriverManager.instance.registerX4OLanguageTask(className);
}
}
}
}