Package com.sun.istack.tools

Source Code of com.sun.istack.tools.ProtectedTask$AntElement

/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License").  You
* may not use this file except in compliance with the License.  You can
* obtain a copy of the License at
* http://glassfish.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt.  See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license."  If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above.  However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/

package com.sun.istack.tools;

import java.io.Closeable;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.DynamicConfigurator;
import org.apache.tools.ant.IntrospectionHelper;
import org.apache.tools.ant.Task;

import java.io.IOException;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.InvocationTargetException;
import java.net.URLClassLoader;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Iterator;
import java.util.Map.Entry;
import org.apache.tools.ant.AntClassLoader;

/**
* Executes a {@link Task} in a special class loader that allows
* us to control where to load 2.1 APIs, even if we run in Java 6.
*
* <p>
* No JDK 1.5 code here, please. This allows us to detect "require JDK5" bug nicely.
*
* @author Kohsuke Kawaguchi
* @author Bhakti Mehta
*/
public abstract class ProtectedTask extends Task implements DynamicConfigurator {

    private final AntElement root = new AntElement("root");

    public void setDynamicAttribute(String name, String value) throws BuildException {
        root.setDynamicAttribute(name,value);
    }

    public Object createDynamicElement(String name) throws BuildException {
        return root.createDynamicElement(name);
    }

    public void execute() throws BuildException {
        //Leave XJC2 in the publicly visible place
        // and then isolate XJC1 in a child class loader,
        // then use a MaskingClassLoader
        // so that the XJC2 classes in the parent class loader
        //  won't interfere with loading XJC1 classes in a child class loader
        ClassLoader ccl = SecureLoader.getContextClassLoader();
        try {
            ClassLoader cl = createClassLoader();
            Class driver = cl.loadClass(getCoreClassName());

            Task t = (Task)driver.newInstance();
            t.setProject(getProject());
            t.setTaskName(getTaskName());
            root.configure(t);

            SecureLoader.setContextClassLoader(cl);
            t.execute();
           
            driver = null;
            t.setTaskName(null);
            t.setProject(null);
            t = null;
        } catch (UnsupportedClassVersionError e) {
            throw new BuildException("Requires JDK 5.0 or later. Please download it from http://java.sun.com/j2se/1.5/");
        } catch (ClassNotFoundException e) {
            throw new BuildException(e);
        } catch (InstantiationException e) {
            throw new BuildException(e);
        } catch (IllegalAccessException e) {
            throw new BuildException(e);
        } catch (IOException e) {
            throw new BuildException(e);
        } finally {
            ClassLoader cl = Thread.currentThread().getContextClassLoader();
            SecureLoader.setContextClassLoader(ccl);
           
            //close/cleanup all classloaders but the one which loaded this class
            while (cl != null && !ccl.equals(cl)) {
                if (cl instanceof Closeable) {
                    //JDK7+, ParallelWorldClassLoader, Ant (AntClassLoader5)
                    try {
                        ((Closeable) cl).close();
                    } catch (IOException ex) {
                        throw new BuildException(ex);
                    }
                } else {
                    if (cl instanceof URLClassLoader) {
                        //JDK6 - API jars are loaded by instance of URLClassLoader
                        //so use proprietary API to release holded resources
                        try {
                            Class clUtil = ccl.loadClass("sun.misc.ClassLoaderUtil");
                            Method release = clUtil.getDeclaredMethod("releaseLoader", URLClassLoader.class);
                            release.invoke(null, cl);
                        } catch (ClassNotFoundException ex) {
                            //not Sun JDK 6, ignore
                        } catch (IllegalAccessException ex) {
                            throw new BuildException(ex);
                        } catch (IllegalArgumentException ex) {
                            throw new BuildException(ex);
                        } catch (InvocationTargetException ex) {
                            throw new BuildException(ex);
                        } catch (NoSuchMethodException ex) {
                            throw new BuildException(ex);
                        } catch (SecurityException ex) {
                            throw new BuildException(ex);
                        }
                    }
                }
                cl = getParentClassLoader(cl);
            }
            cl = null;
        }
    }

    /**
     * Returns the name of the class that extends {@link Task}.
     * This class will be loaded int the protected classloader.
     */
    protected abstract String getCoreClassName();

    /**
     * Creates a protective class loader that will host the actual task.
     */
    protected abstract ClassLoader createClassLoader() throws ClassNotFoundException, IOException;

    /* workaround for: https://issues.apache.org/bugzilla/show_bug.cgi?id=35436
       which is fixed in Ant 1.8 but 1.7 still needs to be supported */
    private ClassLoader getParentClassLoader(final ClassLoader cl) {
        //Calling getParent() on AntClassLoader doesn't return the - expected -
        //actual parent classloader but always the SystemClassLoader.
        if (cl instanceof AntClassLoader) {
            //1.8 added getConfiguredParent() to get correct 'parent' classloader
            if (System.getSecurityManager() == null) {
                return getPCL(cl);
            } else {
                return AccessController.doPrivileged(
                        new PrivilegedAction<ClassLoader>() {
                            public ClassLoader run() {
                                return getPCL(cl);
                            }
                        });
            }
        }
        return SecureLoader.getParentClassLoader(cl);
    }

    private ClassLoader getPCL(ClassLoader cl) {
        try {
            Method parentM = AntClassLoader.class.getDeclaredMethod("getConfiguredParent");
            return (ClassLoader) parentM.invoke(cl);
        } catch (IllegalAccessException ex) {
            throw new BuildException(ex);
        } catch (IllegalArgumentException ex) {
            throw new BuildException(ex);
        } catch (InvocationTargetException ex) {
            throw new BuildException(ex);
        } catch (NoSuchMethodException ex) {
            //Ant 1.7 try to get 'parent' field
            Field parentF = null;
            try {
                parentF = AntClassLoader.class.getDeclaredField("parent");
                parentF.setAccessible(true);
                return (ClassLoader) parentF.get(cl);
            } catch (IllegalAccessException ex1) {
                throw new BuildException(ex1);
            } catch (IllegalArgumentException ex1) {
                throw new BuildException(ex1);
            } catch (NoSuchFieldException ex1) {
                //not Ant 1.8 nor 1.7
                //should be some warning here?
            } catch (SecurityException ex1) {
                throw new BuildException(ex1);
            } finally {
                if (parentF != null) {
                    parentF.setAccessible(false);
                }
            }
        }
        return null;
    }

    /**
     * Captures the elements and attributes.
     */
    private class AntElement implements DynamicConfigurator {
        private final String name;

        private final Map/*<String,String>*/ attributes = new HashMap();

        private final List/*<AntElement>*/ elements = new ArrayList();

        public AntElement(String name) {
            this.name = name;
        }

        public void setDynamicAttribute(String name, String value) throws BuildException {
            attributes.put(name,value);
        }

        public Object createDynamicElement(String name) throws BuildException {
            AntElement e = new AntElement(name);
            elements.add(e);
            return e;
        }

        /**
         * Copies the properties into the Ant task.
         */
        public void configure(Object antObject) {
            IntrospectionHelper ih = IntrospectionHelper.getHelper(antObject.getClass());

            // set attributes first
            for (Iterator itr = attributes.entrySet().iterator(); itr.hasNext();) {
                Entry att = (Entry)itr.next();
                ih.setAttribute(getProject(), antObject, (String)att.getKey(), (String)att.getValue());
            }

            // then nested elements
            for (Iterator itr = elements.iterator(); itr.hasNext();) {
                AntElement e = (AntElement) itr.next();
                Object child = ih.createElement(getProject(), antObject, e.name);
                e.configure(child);
                ih.storeElement(getProject(), antObject, child, e.name);
            }
        }
    }
}
TOP

Related Classes of com.sun.istack.tools.ProtectedTask$AntElement

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.