name.martingeisse.webide.features.java.compiler.classpath.AbstractLibraryFileManager.java Source code

Java tutorial

Introduction

Here is the source code for name.martingeisse.webide.features.java.compiler.classpath.AbstractLibraryFileManager.java

Source

/**
 * Copyright (c) 2010 Martin Geisse
 *
 * This file is distributed under the terms of the MIT license.
 */

package name.martingeisse.webide.features.java.compiler.classpath;

import java.io.IOException;
import java.util.Iterator;
import java.util.Set;

import javax.tools.FileObject;
import javax.tools.ForwardingJavaFileManager;
import javax.tools.JavaFileManager;
import javax.tools.JavaFileObject;
import javax.tools.JavaFileObject.Kind;
import javax.tools.StandardLocation;

import name.martingeisse.common.util.GenericTypeUtil;

import org.apache.commons.collections.iterators.IteratorChain;
import org.apache.commons.lang3.StringUtils;
import org.apache.log4j.Logger;

/**
 * Base class for {@link JavaFileManager} implementations for
 * class libraries. Such implementations handle only specific
 * locations, and do not accept output files.
 * 
 * This class implements {@link ForwardingJavaFileManager} for
 * file manager chaining.
 */
public abstract class AbstractLibraryFileManager extends ForwardingJavaFileManager<JavaFileManager> {

    /**
     * the logger
     */
    @SuppressWarnings("unused")
    private static Logger logger = Logger.getLogger(AbstractLibraryFileManager.class);

    /**
     * the libraryNameForLogging
     */
    private final String libraryNameForLogging;

    /**
     * Constructor.
     * @param libraryNameForLogging the name used for this library in log messages
     * @param next the next file manager to search
     */
    public AbstractLibraryFileManager(final String libraryNameForLogging, final JavaFileManager next) {
        super(next);
        this.libraryNameForLogging = libraryNameForLogging;
    }

    /**
     * Getter method for the libraryNameForLogging.
     * @return the libraryNameForLogging
     */
    public String getLibraryNameForLogging() {
        return libraryNameForLogging;
    }

    /* (non-Javadoc)
     * @see javax.tools.ForwardingJavaFileManager#flush()
     */
    @Override
    public final void flush() throws IOException {
        super.flush();
    }

    /* (non-Javadoc)
     * @see javax.tools.ForwardingJavaFileManager#getFileForInput(javax.tools.JavaFileManager.Location, java.lang.String, java.lang.String)
     */
    @Override
    public final FileObject getFileForInput(final Location location, final String packageName,
            final String relativeName) throws IOException {
        String loggingName = "library [" + libraryNameForLogging + "] package [" + packageName + "], name ["
                + relativeName + "]";
        if (location == StandardLocation.CLASS_PATH) {
            logger.trace("searching library for file: " + loggingName);
            final FileObject file = getLibraryFile(packageName, relativeName);
            if (file != null) {
                logger.trace("found file in library: " + loggingName);
                return file;
            }
        } else {
            logger.trace("skipping library for non-classpath file: " + loggingName);
        }
        return super.getFileForInput(location, packageName, relativeName);
    }

    /**
     * Returns a file from this library, or null if not found.
     * 
     * @param packageName the package to look in
     * @param relativeName the file name
     * @return the file
     * @throws IOException on I/O errors
     */
    protected abstract FileObject getLibraryFile(String packageName, String relativeName) throws IOException;

    /* (non-Javadoc)
     * @see javax.tools.ForwardingJavaFileManager#getFileForOutput(javax.tools.JavaFileManager.Location, java.lang.String, java.lang.String, javax.tools.FileObject)
     */
    @Override
    public final FileObject getFileForOutput(final Location location, final String packageName,
            final String relativeName, final FileObject sibling) throws IOException {
        return super.getFileForOutput(location, packageName, relativeName, sibling);
    }

    /* (non-Javadoc)
     * @see javax.tools.ForwardingJavaFileManager#getJavaFileForInput(javax.tools.JavaFileManager.Location, java.lang.String, javax.tools.JavaFileObject.Kind)
     */
    @Override
    public final JavaFileObject getJavaFileForInput(final Location location, final String className,
            final Kind kind) throws IOException {
        String loggingName = "library [" + libraryNameForLogging + "] class [" + className + "], kind [" + kind
                + "]";
        if (location == StandardLocation.CLASS_PATH && kind == Kind.CLASS) {
            logger.trace("searching library for class " + loggingName);
            final JavaFileObject file = getLibraryClassFile(className);
            if (file != null) {
                logger.trace("found class in library: " + loggingName);
                return file;
            }
        } else {
            logger.trace("skipping library for non-class or non-classpath class: " + loggingName);
        }
        return super.getJavaFileForInput(location, className, kind);
    }

    /**
     * Returns a Java class file from this library, or null if not found.
     * 
     * @param className the class name
     * @return the file
     * @throws IOException on I/O errors
     */
    protected abstract JavaFileObject getLibraryClassFile(String className) throws IOException;

    /* (non-Javadoc)
     * @see javax.tools.ForwardingJavaFileManager#getJavaFileForOutput(javax.tools.JavaFileManager.Location, java.lang.String, javax.tools.JavaFileObject.Kind, javax.tools.FileObject)
     */
    @Override
    public final JavaFileObject getJavaFileForOutput(final Location location, final String className,
            final Kind kind, final FileObject sibling) throws IOException {
        return super.getJavaFileForOutput(location, className, kind, sibling);
    }

    /* (non-Javadoc)
     * @see javax.tools.ForwardingJavaFileManager#hasLocation(javax.tools.JavaFileManager.Location)
     */
    @Override
    public final boolean hasLocation(final Location location) {
        boolean result = (location == StandardLocation.CLASS_PATH) || super.hasLocation(location);
        logger.trace("library [" + libraryNameForLogging + "] has location [" + location + "]: " + result);
        return result;
    }

    /* (non-Javadoc)
     * @see javax.tools.ForwardingJavaFileManager#inferBinaryName(javax.tools.JavaFileManager.Location, javax.tools.JavaFileObject)
     */
    @Override
    public final String inferBinaryName(Location location, JavaFileObject file) {
        String loggingName = "location [" + location + "], file [" + file + "]";
        if (location == StandardLocation.CLASS_PATH) {
            logger.trace("trying to infer binary name in library for " + loggingName);
            String result = inferLibraryBinaryName(file);
            logger.trace("result: " + result);
            if (result != null) {
                return result;
            }
        }
        return super.inferBinaryName(location, file);
    }

    /**
     * Tries to infer the binary name for the specified file.
     * @param file the file
     * @return the binary name, or null if not known
     */
    public abstract String inferLibraryBinaryName(JavaFileObject file);

    /* (non-Javadoc)
     * @see javax.tools.ForwardingJavaFileManager#list(javax.tools.JavaFileManager.Location, java.lang.String, java.util.Set, boolean)
     */
    @Override
    public final Iterable<JavaFileObject> list(final Location location, final String packageName,
            final Set<Kind> kinds, final boolean recurse) throws IOException {
        logger.trace("listing library [" + libraryNameForLogging + "] files for location [" + location
                + "], package [" + packageName + "], kinds [" + StringUtils.join(kinds, ", ") + "], recurse ["
                + recurse + "]");
        final Iterable<JavaFileObject> superIterable = super.list(location, packageName, kinds, recurse);
        if (location == StandardLocation.CLASS_PATH && kinds.contains(Kind.CLASS)) {
            final Iterable<JavaFileObject> libraryIterable = listLibraryClassFiles(packageName, recurse);
            logger.trace(
                    "contributed files from this library: " + StringUtils.join(libraryIterable.iterator(), ", "));
            return new Iterable<JavaFileObject>() {
                @Override
                public Iterator<JavaFileObject> iterator() {
                    return GenericTypeUtil
                            .unsafeCast(new IteratorChain(superIterable.iterator(), libraryIterable.iterator()));
                }
            };
        } else {
            logger.trace("no contribution from this library because of location/kinds");
            return superIterable;
        }
    }

    /**
     * Lists all class files in a specific package (and optionally subpackages) from this library.
     * @param packageName the package name
     * @param recurse whether to include subpackages
     * @return an iterable for the files
     * @throws IOException on I/O errors
     */
    protected abstract Iterable<JavaFileObject> listLibraryClassFiles(String packageName, boolean recurse)
            throws IOException;

}