Java tutorial
/************************************************************************* * Copyright 2009-2012 Eucalyptus Systems, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need * additional information or have any questions. * * This file may incorporate work covered under the following copyright * and permission notice: * * Software License Agreement (BSD License) * * Copyright (c) 2008, Regents of the University of California * All rights reserved. * * Redistribution and use of this software 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 OWNER 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. USERS OF THIS SOFTWARE ACKNOWLEDGE * THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE LICENSED MATERIAL, * COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS SOFTWARE, * AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING * IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, * SANTA BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, * WHICH IN THE REGENTS' DISCRETION MAY INCLUDE, WITHOUT LIMITATION, * REPLACEMENT OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO * IDENTIFIED, OR WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT * NEEDED TO COMPLY WITH ANY SUCH LICENSES OR RIGHTS. * * This file may incorporate work covered under the following copyright and * permission notice: * * Copyright (c) 2003-2010, Dennis M. Sosnoski. * 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. * * * Neither the name of JiBX nor the names of its contributors may * be used to endorse or promote products derived from this software * without specific prior written permission. * * 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 OWNER 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. ************************************************************************/ /** * Binding classloader. This is intended to substitute for the System * classloader (i.e., the one used for loading user classes). It first processes * one or more binding definitions, caching the binary classes modified by the * bindings. It then uses these modified forms of the classes when they're * requested for loading. * * @author Dennis M. Sosnoski * @author chris grzegorczyk <grze@eucalyptus.com> */ package com.eucalyptus.bootstrap; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.MalformedURLException; import java.net.URL; import java.net.URLClassLoader; import java.util.ArrayList; import java.util.List; import java.util.Map; import org.apache.commons.io.FileUtils; import org.apache.log4j.Logger; import org.jibx.binding.Loader; import org.jibx.binding.Utility; import org.jibx.binding.classes.BoundClass; import org.jibx.binding.classes.ClassCache; import org.jibx.binding.classes.ClassFile; import org.jibx.binding.classes.MungedClass; import org.jibx.binding.def.BindingBuilder; import org.jibx.binding.def.BindingDefinition; import org.jibx.binding.def.MappingBase; import org.jibx.binding.model.BindingElement; import org.jibx.binding.model.IncludeElement; import org.jibx.binding.model.MappingElement; import org.jibx.binding.model.MappingElementBase; import org.jibx.binding.model.ValidationContext; import org.jibx.runtime.JiBXException; import org.jibx.runtime.impl.UnmarshallingContext; import org.jibx.util.ClasspathUrlExtender; import com.eucalyptus.system.SubDirectory; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.io.ByteStreams; import com.google.common.io.InputSupplier; import com.google.common.io.Resources; public class BootstrapClassLoader extends URLClassLoader { private static Logger LOG = Logger.getLogger(BootstrapClassLoader.class); private static BootstrapClassLoader singleton = null; public static BootstrapClassLoader init() { try { if (singleton == null) { if (SubDirectory.CLASSCACHE.getFile().exists()) { try { FileUtils.deleteDirectory(SubDirectory.CLASSCACHE.getFile()); } catch (IOException ex) { LOG.error(ex, ex); } } SubDirectory.CLASSCACHE.check(); String[] paths = Utility.getClassPaths(); URL[] urls = new URL[paths.length]; for (int i = 0; i < urls.length; i++) { urls[i] = new File(paths[i]).toURI().toURL(); } singleton = new BootstrapClassLoader(urls); } Thread.currentThread().setContextClassLoader(singleton); return singleton; } catch (final MalformedURLException ex) { LOG.error(ex, ex); return null; } } private final List<BindingDefinition> bindings = Lists.newArrayList(); private boolean isBound; private final Map<String, ClassFile> classMap = Maps.newHashMap(); public static BootstrapClassLoader getInstance() { return init(); } private BootstrapClassLoader(URL[] urls) throws MalformedURLException { super(urls, ClassLoader.getSystemClassLoader()); List<String> fpaths = Lists.newArrayList(); for (URL path : Loader.getClassPaths()) { LOG.debug(path); if ("file".equals(path.getProtocol())) { fpaths.add(path.getPath()); } } // set paths to be used for loading referenced classes String[] dirs = (String[]) fpaths.toArray(new String[0]); ClassCache.setPaths(dirs); ClassFile.setPaths(dirs); ClasspathUrlExtender.setClassLoader(ClassFile.getClassLoader()); // reset static information accumulation for binding BoundClass.reset(); MungedClass.reset(); BindingDefinition.reset(); } public void reset() { this.bindings.clear(); this.classMap.clear(); this.isBound = false; BoundClass.reset(); MungedClass.reset(); BindingDefinition.reset(); } public static URL[] getClassPaths() throws MalformedURLException { String[] paths = Utility.getClassPaths(); URL[] urls = new URL[paths.length]; for (int i = 0; i < urls.length; i++) { urls[i] = new File(paths[i]).toURI().toURL(); } return urls; } public void loadBinding(String fname, String sname, InputStream is, URL url) throws JiBXException, IOException { throw new IllegalStateException("Call not allowed: only resources can currently be loaded."); } public void loadFileBinding(String path) throws JiBXException, IOException { throw new IllegalStateException("Call not allowed: only resources can currently be loaded."); } public void loadResourceBinding(String path) throws JiBXException, IOException { if (this.isBound) { throw new IllegalStateException("Call not allowed after bindings compiled"); } else { URL url = Resources.getResource(path); InputSupplier<InputStream> inSupplier = Resources.newInputStreamSupplier(url); if (inSupplier == null) { throw new IOException("Resource " + path + " not found"); } else { String fname = path; int split = fname.lastIndexOf('/'); if (split >= 0) { fname = fname.substring(split + 1); } String defaultBindingName = Utility.bindingFromFileName(fname); try { ValidationContext vctx = BindingElement.newValidationContext(); BindingElement root = BindingElement.validateBinding(fname, url, inSupplier.getInput(), vctx); if (vctx.getErrorCount() == 0 && vctx.getFatalCount() == 0) { ClassFile classFile = findMappedClass(root); String tpack = root.getTargetPackage(); if (tpack == null && classFile != null) { tpack = classFile.getPackage(); } String bindingName = root.getName(); UnmarshallingContext uctx = new UnmarshallingContext(); uctx.setDocument(inSupplier.getInput(), fname, null); if (classFile != null) { bindingName = (bindingName == null ? defaultBindingName : bindingName); BoundClass.setModify(classFile.getRoot(), tpack, bindingName); } BindingDefinition bindingDefinition = BindingBuilder.unmarshalBindingDefinition(uctx, defaultBindingName, url); File rootFile = null; if (tpack == null) { tpack = bindingDefinition.getDefaultPackage(); } if (classFile == null) { rootFile = ClassCache.getModifiablePath(); if (root == null) { throw new IllegalStateException( "Need modifiable directory on classpath for storing generated factory class file"); } if (tpack == null) { tpack = ""; } } else { rootFile = classFile.getRoot(); if (tpack == null) { tpack = classFile.getPackage(); } } bindingDefinition.setFactoryLocation(tpack, rootFile); } } catch (JiBXException ex) { LOG.error("Unable to process binding " + url, ex); } } } } private static ClassFile findMappedClass(BindingElement root) { ArrayList childs = root.topChildren(); if (childs != null) { // recursively search for modifiable mapped class for (int i = childs.size() - 1; i >= 0; i--) { Object child = childs.get(i); if (child instanceof MappingElement) { // end scan if a real mapping is found MappingElementBase map = (MappingElementBase) child; ClassFile cf = map.getHandledClass().getClassFile(); if (!cf.isInterface() && cf.isModifiable()) { return cf; } } else if (child instanceof IncludeElement) { // recurse on included binding BindingElement bind = ((IncludeElement) child).getBinding(); if (bind != null) { ClassFile cf = findMappedClass(bind); if (cf != null) { return cf; } } } } } return null; } public void processBindings() throws JiBXException { if (!this.isBound) { for (BindingDefinition binding : this.bindings) { binding.generateCode(System.getProperty("euca.debug.binding.compile") != null, System.getProperty("euca.debug.binding.compile") != null); } ClassFile[][] lists = MungedClass.fixDispositions(); for (BindingDefinition binding : this.bindings) { binding.addClassList(lists[0], lists[1]); } for (int i = 0; i < lists[0].length; i++) { ClassFile clas = lists[0][i]; this.classMap.put(clas.getName(), clas); } this.isBound = true; } } protected boolean isBoundClass(String name) { // if ( !this.isBound ) { // try { // this.processBindings( ); // } catch ( JiBXException e ) { // e.printStackTrace( ); // } // } return this.classMap.containsKey(name); } protected Class findClass(String name) throws ClassNotFoundException { if (isBoundClass(name)) { try { ClassFile clas = (ClassFile) this.classMap.get(name); ByteArrayOutputStream bos = new ByteArrayOutputStream(); clas.writeFile(bos); byte[] bytes = bos.toByteArray(); return defineClass(name, bytes, 0, bytes.length); } catch (IOException e) { throw new ClassNotFoundException("Unable to load modified class " + name); } } else { return super.findClass(name); } } }