/** * * Copyright 2015 Kamran Zafar * * Licensed 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.xeustechnologies.jcl.context; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.transform.Source; import javax.xml.transform.stream.StreamSource; import javax.xml.validation.SchemaFactory; import org.objenesis.Objenesis; import org.objenesis.ObjenesisStd; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.w3c.dom.Document; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xeustechnologies.jcl.AbstractClassLoader; import org.xeustechnologies.jcl.JarClassLoader; import org.xeustechnologies.jcl.ProxyClassLoader; import org.xeustechnologies.jcl.exception.JclContextException; import org.xeustechnologies.jcl.utils.PathResolver; import org.xml.sax.SAXException; import org.xml.sax.SAXParseException; /** * The class loads the JclContext from XML file. See the documentation and * schema for more details on how to write the JCL context xml. * * @author Kamran * */ public class XmlContextLoader implements JclContextLoader { private static final String CLASSPATH = "classpath:"; private static final String ELEMENT_JCL = "jcl"; private static final String ELEMENT_SOURCES = "sources"; private static final String ELEMENT_SOURCE = "source"; private static final String ELEMENT_LOADERS = "loaders"; private static final String ELEMENT_LOADER = "loader"; private static final String ELEMENT_ENABLED = "enabled"; private static final String ELEMENT_ORDER = "order"; private static final String ELEMENT_STRICT = "strict"; private static final String ELEMENT_BOOT_DELEGATION = "bootDelegation"; private static final String ATTRIBUTE_CLASS = "class"; private static final String ATTRIBUTE_NAME = "name"; private static final String JCL_BOOTOSGI = "jcl.bootosgi"; private static final String JCL_SYSTEM = "jcl.system"; private static final String JCL_THREAD = "jcl.thread"; private static final String JCL_LOCAL = "jcl.local"; private static final String JCL_CURRENT = "jcl.current"; private static final String JCL_PARENT = "jcl.parent"; private static final String XML_SCHEMA_LANG = "http://www.w3.org/2001/XMLSchema"; private static final String JCL_CONTEXT_SCHEMA = "org/xeustechnologies/jcl/context/jcl-context.xsd"; private final String file; private final JclContext jclContext; private final List<PathResolver> pathResolvers = new ArrayList<PathResolver>(); private final transient Logger logger = LoggerFactory.getLogger(XmlContextLoader.class); public XmlContextLoader(String file) { this.file = file; jclContext = new JclContext(); } /** * Loads the JCL context from XML file * * @see org.xeustechnologies.jcl.context.JclContextLoader#loadContext() */ public void loadContext() { DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); factory.setValidating( false ); factory.setNamespaceAware( true ); SchemaFactory schemaFactory = SchemaFactory.newInstance( XML_SCHEMA_LANG ); try { factory.setSchema( schemaFactory.newSchema( new Source[] { new StreamSource( getClass().getClassLoader() .getResourceAsStream( JCL_CONTEXT_SCHEMA ) ) } ) ); } catch (SAXException e) { throw new JclContextException( e ); } try { DocumentBuilder builder = factory.newDocumentBuilder(); Document d = null; if (file.startsWith( CLASSPATH )) d = builder.parse( getClass().getClassLoader().getResourceAsStream( file.split( CLASSPATH )[1] ) ); else { d = builder.parse( file ); } NodeList nl = d.getElementsByTagName( ELEMENT_JCL ); for (int i = 0; i < nl.getLength(); i++) { Node n = nl.item( i ); String name = n.getAttributes().getNamedItem( ATTRIBUTE_NAME ).getNodeValue(); JarClassLoader jcl = new JarClassLoader(); NodeList config = n.getChildNodes(); for (int j = 0; j < config.getLength(); j++) { Node c = config.item( j ); if (c.getNodeName().equals( ELEMENT_LOADERS )) { processLoaders( jcl, c ); } else if (c.getNodeName().equals( ELEMENT_SOURCES )) { processSources( jcl, c ); } } jclContext.addJcl( name, jcl ); logger.debug( "JarClassLoader[{}] loaded into context.", name ); } } catch (SAXParseException e) { JclContextException we = new JclContextException( e.getMessage() + " [" + file + " (" + e.getLineNumber() + ", " + e.getColumnNumber() + ")]" ); we.setStackTrace( e.getStackTrace() ); throw we; } catch (JclContextException e) { throw e; } catch (Exception e) { throw new JclContextException( e ); } } /** * Unloads the context * * @see org.xeustechnologies.jcl.context.JclContextLoader#unloadContext() */ public void unloadContext() { JclContext.destroy(); } private void processSources(JarClassLoader jcl, Node c) { NodeList sources = c.getChildNodes(); for (int k = 0; k < sources.getLength(); k++) { Node s = sources.item( k ); if (s.getNodeName().equals( ELEMENT_SOURCE )) { String path = s.getTextContent(); Object[] res = null; for (PathResolver pr : pathResolvers) { res = pr.resolvePath( path ); if (res != null) { for (Object r : res) jcl.add( r ); break; } } if (res == null) jcl.add( path ); } } } private void processLoaders(JarClassLoader jcl, Node c) { NodeList loaders = c.getChildNodes(); for (int k = 0; k < loaders.getLength(); k++) { Node l = loaders.item( k ); if (l.getNodeName().equals( ELEMENT_LOADER )) { if (l.getAttributes().getNamedItem( ATTRIBUTE_NAME ).getNodeValue().equals( JCL_PARENT )) { processLoader( jcl.getParentLoader(), l ); } else if (l.getAttributes().getNamedItem( ATTRIBUTE_NAME ).getNodeValue().equals( JCL_CURRENT )) { processLoader( jcl.getCurrentLoader(), l ); } else if (l.getAttributes().getNamedItem( ATTRIBUTE_NAME ).getNodeValue().equals( JCL_LOCAL )) { processLoader( jcl.getLocalLoader(), l ); } else if (l.getAttributes().getNamedItem( ATTRIBUTE_NAME ).getNodeValue().equals( JCL_THREAD )) { processLoader( jcl.getThreadLoader(), l ); } else if (l.getAttributes().getNamedItem( ATTRIBUTE_NAME ).getNodeValue().equals( JCL_SYSTEM )) { processLoader( jcl.getSystemLoader(), l ); } else if (l.getAttributes().getNamedItem( ATTRIBUTE_NAME ).getNodeValue().equals( JCL_BOOTOSGI )) { processLoader( jcl.getOsgiBootLoader(), l ); } else { Objenesis objenesis = new ObjenesisStd(); Class<?> clazz = null; try { clazz = getClass().getClassLoader().loadClass( l.getAttributes().getNamedItem( ATTRIBUTE_CLASS ).getNodeValue() ); } catch (Exception e) { throw new JclContextException( e ); } ProxyClassLoader pcl = (ProxyClassLoader) objenesis.newInstance( clazz ); jcl.addLoader( pcl ); processLoader( pcl, l ); } } } } private void processLoader(ProxyClassLoader loader, Node node) { NodeList oe = node.getChildNodes(); for (int i = 0; i < oe.getLength(); i++) { Node noe = oe.item( i ); if (noe.getNodeName().equals( ELEMENT_ORDER ) && !( loader instanceof AbstractClassLoader.OsgiBootLoader )) { loader.setOrder( Integer.parseInt( noe.getTextContent() ) ); } else if (noe.getNodeName().equals( ELEMENT_ENABLED )) { loader.setEnabled( Boolean.parseBoolean( noe.getTextContent() ) ); } else if (noe.getNodeName().equals( ELEMENT_STRICT ) && loader instanceof AbstractClassLoader.OsgiBootLoader) { ( (AbstractClassLoader.OsgiBootLoader) loader ).setStrictLoading( Boolean.parseBoolean( noe .getTextContent() ) ); } else if (noe.getNodeName().equals( ELEMENT_BOOT_DELEGATION ) && loader instanceof AbstractClassLoader.OsgiBootLoader) { ( (AbstractClassLoader.OsgiBootLoader) loader ).setBootDelagation( noe.getTextContent().split( "," ) ); } } logger.debug( "Loader[{}] configured: [{}, {}]", loader.getClass().getName(), loader.getOrder(), loader.isEnabled() ); } public void addPathResolver(PathResolver pr) { pathResolvers.add( pr ); } }