blob: 86517f9b1b737ae68b566fe268e83b76aa7b9228 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.openejb.config.sys;
import org.apache.openejb.OpenEJBException;
import org.apache.openejb.config.ConfigUtils;
import org.apache.openejb.jee.JAXBContextFactory;
import org.apache.openejb.loader.IO;
import org.apache.openejb.util.Join;
import org.apache.openejb.util.Saxs;
import org.xml.sax.Attributes;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLFilterImpl;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.MarshalException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.ValidationEvent;
import javax.xml.bind.ValidationEventHandler;
import javax.xml.bind.ValidationException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.transform.sax.SAXSource;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
public abstract class JaxbOpenejb {
@SuppressWarnings({"unchecked"})
public static <T> T create(Class<T> type) {
if (type == null) throw new NullPointerException("type is null");
if (type == ConnectionManager.class) {
return (T) createConnectionManager();
} else if (type == Connector.class) {
return (T) createConnector();
} else if (type == Container.class) {
return (T) createContainer();
} else if (type == Deployments.class) {
return (T) createDeployments();
} else if (type == JndiProvider.class) {
return (T) createJndiProvider();
} else if (type == Openejb.class) {
return (T) createOpenejb();
} else if (type == ProxyFactory.class) {
return (T) createProxyFactory();
} else if (type == Resource.class) {
return (T) createResource();
} else if (type == SecurityService.class) {
return (T) createSecurityService();
} else if (type == ServiceProvider.class) {
return (T) createServiceProvider();
} else if (type == ServicesJar.class) {
return (T) createServicesJar();
} else if (type == TransactionManager.class) {
return (T) createTransactionManager();
} else if (type == Tomee.class) {
return (T) createTomee();
}
throw new IllegalArgumentException("Unknown type " + type.getName());
}
public static <T> T create(String type) {
if (type == null) throw new NullPointerException("type is null");
if (type.equals("ConnectionManager")) {
return (T) createConnectionManager();
} else if (type.equals("Connector")) {
return (T) createConnector();
} else if (type.equals("Container")) {
return (T) createContainer();
} else if (type.equals("Deployments")) {
return (T) createDeployments();
} else if (type.equals("JndiProvider")) {
return (T) createJndiProvider();
} else if (type.equals("Openejb")) {
return (T) createOpenejb();
} else if (type.equals("Tomee")) {
return (T) createTomee();
} else if (type.equals("ProxyFactory")) {
return (T) createProxyFactory();
} else if (type.equals("Resource")) {
return (T) createResource();
} else if (type.equals("SecurityService")) {
return (T) createSecurityService();
} else if (type.equals("ServiceProvider")) {
return (T) createServiceProvider();
} else if (type.equals("ServicesJar")) {
return (T) createServicesJar();
} else if (type.equals("TransactionManager")) {
return (T) createTransactionManager();
} else if (type.equals("Service")) {
return (T) createService();
}
throw new IllegalArgumentException("Unknown type " + type);
}
public static ServicesJar readServicesJar(final String providerPath) throws OpenEJBException {
final ClassLoader loader = Thread.currentThread().getContextClassLoader();
final List<URL> sources = new ArrayList<URL>();
{ // Find URLs in the classpath
final String path1 = "META-INF/" + providerPath + "/service-jar.xml";
final String path2 = providerPath.replace('.', '/') + "/service-jar.xml";
final List<String> paths = Arrays.asList(path1, path2);
for (String p : paths) {
try {
final Enumeration<URL> resources = loader.getResources(p);
if (resources != null){
sources.addAll(Collections.list(resources));
}
} catch (IOException e) {
throw new OpenEJBException(String.format("Unable to scan for service-jar.xml file: getResource('%s')", p), e);
}
}
if (sources.size() == 0) {
throw new OpenEJBException("No service-jar.xml files found: searched " + Join.join(" and ", paths));
}
}
final ServicesJar servicesJar = new ServicesJar();
{
for (URL url : sources) {
try {
final InputStream read = IO.read(url);
try {
final ServicesJar jar = parseServicesJar(read);
servicesJar.getServiceProvider().addAll(jar.getServiceProvider());
} catch (Exception e) {
throw new OpenEJBException("Unable to parse service-jar.xml file for provider " + providerPath + " at " + url, e);
} finally {
IO.close(read);
}
} catch (IOException e) {
throw new OpenEJBException("Unable to read service-jar.xml file for provider " + providerPath + " at " + url, e);
}
}
}
return servicesJar;
}
public static ServicesJar parseServicesJar(InputStream in) throws ParserConfigurationException, SAXException, IOException {
InputSource inputSource = new InputSource(in);
SAXParser parser = Saxs.namespaceAwareFactory().newSAXParser();
final ServicesJar servicesJar1 = new ServicesJar();
final PropertiesAdapter propertiesAdapter = new PropertiesAdapter();
parser.parse(inputSource, new DefaultHandler() {
private ServiceProvider provider;
private StringBuilder content;
public void startDocument() throws SAXException {
}
public void startElement(String uri, String localName, String qName, Attributes att) throws SAXException {
if (!localName.equals("ServiceProvider")) return;
provider = new ServiceProvider();
provider.setId(att.getValue("","id"));
provider.setService(att.getValue("", "service"));
provider.setFactoryName(att.getValue("", "factory-name"));
provider.setConstructor(att.getValue("", "constructor"));
provider.setClassName(att.getValue("", "class-name"));
provider.setParent(att.getValue("", "parent"));
String typesString = att.getValue("", "types");
if (typesString != null){
final ListAdapter listAdapter = new ListAdapter();
final List<String> types = listAdapter.unmarshal(typesString);
provider.getTypes().addAll(types);
}
servicesJar1.getServiceProvider().add(provider);
}
public void characters(char ch[], int start, int length) throws SAXException {
if (content == null) content = new StringBuilder();
content.append(ch, start, length);
}
public void endElement(String uri, String localName, String qName) throws SAXException {
if (provider == null || content == null) return;
try {
provider.getProperties().putAll(propertiesAdapter.unmarshal(content.toString()));
} catch (Exception e) {
throw new SAXException(e);
}
provider = null;
content = null;
}
});
ServicesJar servicesJar = servicesJar1;
return servicesJar;
}
public static Openejb readConfig(String configFile) throws OpenEJBException {
InputStream in = null;
try {
if (configFile.startsWith("jar:")) {
URL url = new URL(configFile);
in = IO.read(url);
} else if (configFile.startsWith("file:")) {
URL url = new URL(configFile);
in = IO.read(url);
} else {
in = IO.read(new File(configFile));
}
return readConfig(new InputSource(in));
} catch (MalformedURLException e) {
throw new OpenEJBException("Unable to resolve location " + configFile, e);
} catch (Exception e) {
throw new OpenEJBException("Unable to read OpenEJB configuration file at " + configFile, e);
} finally {
IO.close(in);
}
}
public static Openejb readConfig(final InputSource in) throws IOException, SAXException, ParserConfigurationException {
return SaxOpenejb.parse(in);
}
public static void writeConfig(String configFile, Openejb openejb) throws OpenEJBException {
OutputStream out = null;
try {
File file = new File(configFile);
out = IO.write(file);
marshal(Openejb.class, openejb, out);
} catch (IOException e) {
throw new OpenEJBException(ConfigUtils.messages.format("conf.1040", configFile, e.getLocalizedMessage()), e);
} catch (MarshalException e) {
if (e.getCause() instanceof IOException) {
throw new OpenEJBException(ConfigUtils.messages.format("conf.1040", configFile, e.getLocalizedMessage()), e);
} else {
throw new OpenEJBException(ConfigUtils.messages.format("conf.1050", configFile, e.getLocalizedMessage()), e);
}
} catch (ValidationException e) {
/* TODO: Implement informative error handling here.
The exception will say "X doesn't match the regular
expression Y"
This should be checked and more relevant information
should be given -- not everyone understands regular
expressions.
*/
/* NOTE: This doesn't seem to ever happen. When the object graph
* is invalid, the MarshalException is thrown, not this one as you
* would think.
*/
throw new OpenEJBException(ConfigUtils.messages.format("conf.1060", configFile, e.getLocalizedMessage()), e);
} catch (JAXBException e) {
throw new OpenEJBException(e);
} finally {
if (out != null) {
try {
out.close();
} catch (Exception e) {
}
}
}
}
public static final ThreadLocal<Set<String>> currentPublicId = new ThreadLocal<Set<String>>();
private static Map<Class, JAXBContext> jaxbContexts = new HashMap<Class, JAXBContext>();
public static <T> String marshal(Class<T> type, Object object) throws JAXBException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
marshal(type, object, baos);
return new String(baos.toByteArray());
}
public static <T> void marshal(Class<T> type, Object object, OutputStream out) throws JAXBException {
JAXBContext jaxbContext = getContext(type);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty("jaxb.formatted.output", true);
marshaller.marshal(object, out);
}
public static <T> JAXBContext getContext(Class<T> type) throws JAXBException {
JAXBContext jaxbContext = jaxbContexts.get(type);
if (jaxbContext == null) {
jaxbContext = JAXBContextFactory.newInstance(type);
jaxbContexts.put(type, jaxbContext);
}
return jaxbContext;
}
public static <T> T unmarshal(Class<T> type, InputStream in, boolean filter) throws ParserConfigurationException, SAXException, JAXBException {
InputSource inputSource = new InputSource(in);
SAXParser parser = Saxs.namespaceAwareFactory().newSAXParser();
JAXBContext ctx = getContext(type);
Unmarshaller unmarshaller = ctx.createUnmarshaller();
unmarshaller.setEventHandler(new ValidationEventHandler() {
public boolean handleEvent(ValidationEvent validationEvent) {
System.out.println(validationEvent);
return false;
}
});
SAXSource source;
if (filter) {
NamespaceFilter xmlFilter = new NamespaceFilter(parser.getXMLReader());
xmlFilter.setContentHandler(unmarshaller.getUnmarshallerHandler());
source = new SAXSource(xmlFilter, inputSource);
} else {
source = new SAXSource(inputSource);
}
currentPublicId.set(new TreeSet<String>());
try {
return unmarshaller.unmarshal(source, type).getValue();
} finally {
currentPublicId.set(null);
}
}
@SuppressWarnings({"unchecked"})
public static <T> T unmarshal(Class<T> type, InputStream in) throws ParserConfigurationException, SAXException, JAXBException {
return unmarshal(type, in, true);
}
public static class NamespaceFilter extends XMLFilterImpl {
public NamespaceFilter(XMLReader xmlReader) {
super(xmlReader);
}
public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
Set<String> publicIds = currentPublicId.get();
if (publicIds != null) {
publicIds.add(publicId);
}
return super.resolveEntity(publicId, systemId);
}
public void startElement(String uri, String localName, String qname, Attributes atts) throws SAXException {
super.startElement("http://www.openejb.org/System/Configuration", localName, qname, atts);
}
}
public static ConnectionManager createConnectionManager() {
return new ConnectionManager();
}
public static Connector createConnector() {
return new Connector();
}
public static Container createContainer() {
return new Container();
}
public static Deployments createDeployments() {
return new Deployments();
}
public static Service createService() {
return new Service();
}
public static JndiProvider createJndiProvider() {
return new JndiProvider();
}
public static Openejb createOpenejb() {
return new Openejb();
}
private static Tomee createTomee() {
return new Tomee();
}
public static ProxyFactory createProxyFactory() {
return new ProxyFactory();
}
public static Resource createResource() {
return new Resource();
}
public static SecurityService createSecurityService() {
return new SecurityService();
}
public static ServiceProvider createServiceProvider() {
return new ServiceProvider();
}
public static ServicesJar createServicesJar() {
return new ServicesJar();
}
public static TransactionManager createTransactionManager() {
return new TransactionManager();
}
}