Package org.apache.tools.ant.types.resources

Source Code of org.apache.tools.ant.types.resources.AbstractClasspathResource$ClassLoaderWithFlag

/*
*  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.tools.ant.types.resources;

import org.apache.tools.ant.AntClassLoader;
import org.apache.tools.ant.Project;
import org.apache.tools.ant.types.Resource;
import org.apache.tools.ant.types.Path;
import org.apache.tools.ant.types.Reference;
import org.apache.tools.ant.util.FileUtils;

import java.io.FilterInputStream;
import java.io.InputStream;
import java.io.IOException;
import java.util.Stack;

/**
*
* A Resource representation of anything that is accessed via a Java classloader.
* The core methods to set/resolve the classpath are provided.
* @since Ant 1.8.0
*
*/

public abstract class AbstractClasspathResource extends Resource {
    private Path classpath;
    private Reference loader;
    private boolean parentFirst = true;

    /**
     * Set the classpath to use when looking up a resource.
     * @param classpath to add to any existing classpath
     */
    public void setClasspath(Path classpath) {
        checkAttributesAllowed();
        if (this.classpath == null) {
            this.classpath = classpath;
        } else {
            this.classpath.append(classpath);
        }
        setChecked(false);
    }

    /**
     * Add a classpath to use when looking up a resource.
     * @return The classpath to be configured
     */
    public Path createClasspath() {
        checkChildrenAllowed();
        if (classpath == null) {
            classpath = new Path(getProject());
        }
        setChecked(false);
        return classpath.createPath();
    }

    /**
     * Set the classpath to use when looking up a resource,
     * given as reference to a <path> defined elsewhere
     * @param r The reference value
     */
    public void setClasspathRef(Reference r) {
        checkAttributesAllowed();
        createClasspath().setRefid(r);
    }

    /**
     * get the classpath used by this <code>LoadProperties</code>.
     * @return The classpath
     */
    public Path getClasspath() {
        if (isReference()) {
            return ((AbstractClasspathResource) getCheckedRef()).getClasspath();
        }
        dieOnCircularReference();
        return classpath;
    }

    /**
     * Get the loader.
     * @return the loader.
     */
    public Reference getLoader() {
        if (isReference()) {
            return ((AbstractClasspathResource) getCheckedRef()).getLoader();
        }
        dieOnCircularReference();
        return loader;
    }

    /**
     * Use the reference to locate the loader. If the loader is not
     * found, taskdef will use the specified classpath and register it
     * with the specified name.
     *
     * This allow multiple taskdef/typedef to use the same class loader,
     * so they can be used together. It eliminate the need to
     * put them in the CLASSPATH.
     *
     * @param r the reference to locate the loader.
     */
    public void setLoaderRef(Reference r) {
        checkAttributesAllowed();
        loader = r;
    }

    /**
     * Whether to consult the parent classloader first.
     *
     * <p>Only relevant if a classpath has been specified.</p>
     *
     * @since Ant 1.8.0
     */
    public void setParentFirst(boolean b) {
        parentFirst = b;
    }

    /**
     * Overrides the super version.
     * @param r the Reference to set.
     */
    public void setRefid(Reference r) {
        if (loader != null || classpath != null) {
            throw tooManyAttributes();
        }
        super.setRefid(r);
    }

    /**
     * Learn whether this resource exists. This implementation opens the input stream
     * as the test.
     * @return true if this resource exists.
     */
    public boolean isExists() {
        if (isReference()) {
            return  ((Resource) getCheckedRef()).isExists();
        }
        dieOnCircularReference();
        InputStream is = null;
        try {
            is = getInputStream();
            return is != null;
        } catch (IOException ex) {
            return false;
        } finally {
            FileUtils.close(is);
        }
    }

    /**
     * Return an InputStream for reading the contents of this Resource.
     * @return an InputStream object.
     * @throws IOException if an error occurs.
     */
    public InputStream getInputStream() throws IOException {
        if (isReference()) {
            return ((Resource) getCheckedRef()).getInputStream();
        }
        dieOnCircularReference();

        final ClassLoaderWithFlag classLoader = getClassLoader();
        return !classLoader.needsCleanup()
            ? openInputStream(classLoader.getLoader())
            : new FilterInputStream(openInputStream(classLoader.getLoader())) {
                    public void close() throws IOException {
                        FileUtils.close(in);
                        classLoader.cleanup();
                    }
                    protected void finalize() throws Throwable {
                        try {
                            close();
                        } finally {
                            super.finalize();
                        }
                    }
                };
    }

    /**
     * combines the various ways that could specify a ClassLoader and
     * potentially creates one that needs to be cleaned up when it is
     * no longer needed so that classes can get garbage collected.
     */
    protected ClassLoaderWithFlag getClassLoader() {
        ClassLoader cl = null;
        boolean clNeedsCleanup = false;
        if (loader != null) {
            cl = (ClassLoader) loader.getReferencedObject();
        }
        if (cl == null) {
            if (getClasspath() != null) {
                Path p = getClasspath().concatSystemClasspath("ignore");
                if (parentFirst) {
                    cl = getProject().createClassLoader(p);
                } else {
                    cl = AntClassLoader.newAntClassLoader(getProject()
                                                          .getCoreLoader(),
                                                          getProject(),
                                                          p, false);
                }
                clNeedsCleanup = loader == null;
            } else {
                cl = JavaResource.class.getClassLoader();
            }
            if (loader != null && cl != null) {
                getProject().addReference(loader.getRefId(), cl);
            }
        }
        return new ClassLoaderWithFlag(cl, clNeedsCleanup);
    }

    /**
     * open the input stream from a specific classloader
     * @param cl the classloader to use. Will be null if the system classloader is used
     * @return an open input stream for the resource
     * @throws IOException if an error occurs.
     */
    protected abstract InputStream openInputStream(ClassLoader cl) throws IOException;

    protected synchronized void dieOnCircularReference(Stack<Object> stk, Project p) {
        if (isChecked()) {
            return;
        }
        if (isReference()) {
            super.dieOnCircularReference(stk, p);
        } else {
            if (classpath != null) {
                pushAndInvokeCircularReferenceCheck(classpath, stk, p);
            }
            setChecked(true);
        }
    }

    public static class ClassLoaderWithFlag {
        private final ClassLoader loader;
        private final boolean cleanup;

        ClassLoaderWithFlag(ClassLoader l, boolean needsCleanup) {
            loader = l;
            cleanup = needsCleanup && l instanceof AntClassLoader;
        }
        public ClassLoader getLoader() { return loader; }
        public boolean needsCleanup() { return cleanup; }
        public void cleanup() {
            if (cleanup) {
                ((AntClassLoader) loader).cleanup();
            }
        }
    }
}
TOP

Related Classes of org.apache.tools.ant.types.resources.AbstractClasspathResource$ClassLoaderWithFlag

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.