net.sourceforge.floggy.eclipse.builder.MTJBuilder.java Source code

Java tutorial

Introduction

Here is the source code for net.sourceforge.floggy.eclipse.builder.MTJBuilder.java

Source

/**
 * Copyright (c) 2006-2011 Floggy Open Source Group. All rights reserved.
 *
 * 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 net.sourceforge.floggy.eclipse.builder;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import javassist.ClassPool;
import javassist.NotFoundException;
import net.sourceforge.floggy.eclipse.ConfigurationFileAction;
import net.sourceforge.floggy.persistence.Weaver;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.eclipse.core.resources.IFile;
import org.eclipse.core.resources.IFolder;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IPath;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.jdt.core.IClasspathEntry;
import org.eclipse.jdt.core.IJavaProject;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.JavaModelException;

/**
 * For performing a build in the case where either the Mobile Tools for Java,
 * or Pulsar is being used. One of the main differences here is that in these
 * environments it's necessary to package some floggy impl classes in a jar
 * so that MTJ/Pulsar can do the bytecode verification needed.
 *
 * @author <a href="mailto:thiago.moreira@floggy.org">Thiago Moreira</a>
 * @author <a href="mailto:dan.murphy@floggy.org">Dan Murphy</a>
 * @version $Revision$
  */
public class MTJBuilder extends AbstractBuilder {
    private static final Log LOG = LogFactory.getLog(MTJBuilder.class);

    /**
     * Entry point into builder
     *
     * @param project the project to be build
     * @param monitor the current progress monitor displayed to the user
     * @return List of any projects which the one being built says it depends on
     * @throws Exception if an irrecoverable error occurs
    */
    public IProject[] build(IProject project, IProgressMonitor monitor) throws Exception {
        LOG.debug(project.getName() + " is going to be build using the MTJBuilder");

        List classPoolList = new ArrayList();
        ClassPool classPool = new ClassPool();
        IJavaProject javaProject = JavaCore.create(project);

        configureClassPool(classPool, classPoolList, javaProject, true);

        if (validateClasspath(project, classPool)) {
            Weaver weaver = new Weaver(classPool);
            IPath root = project.getLocation();
            File input = root.removeLastSegments(1).append(javaProject.getOutputLocation()).toFile();

            IFile implJar = project.getFile("floggy-persistence-framework-impl.jar");
            IFolder floggyTemp = project.getFolder(".floggy.tmp");

            if (!floggyTemp.exists()) {
                floggyTemp.create(IResource.DERIVED, true, monitor);
            }

            IFile configurationFile = project
                    .getFile(project.getPersistentProperty(ConfigurationFileAction.PROPERTY_NAME));

            weaver.setEmbeddedClassesOutputPool(implJar.getLocation().toFile());
            weaver.setOutputFile(floggyTemp.getLocation().toFile());
            weaver.setInputFile(input);
            weaver.setClasspath((String[]) classPoolList.toArray(new String[classPoolList.size()]));

            if (!configurationFile.exists()) {
                weaver.setConfiguration(createWeaverConfiguration(project));
            } else {
                weaver.setConfigurationFile(configurationFile.getLocation().toFile());
            }
            // Let the weaving commence
            weaver.execute();

            IPath path = javaProject.getOutputLocation();

            if (path.segmentCount() > 1) {
                path = path.removeFirstSegments(1);
            }

            IFolder outputLocation = project.getFolder(path);
            floggyTemp.refreshLocal(IResource.DEPTH_INFINITE, monitor);
            copyFiles(floggyTemp, outputLocation, monitor);
            outputLocation.refreshLocal(IResource.DEPTH_INFINITE, monitor);
            cleanFolder(floggyTemp, monitor);
        }
        return project.getReferencedProjects();
    }

    /**
     * Entry point into the configureClassPool, recursively called to deal with dependencies
     * @param classPool
     * @param classPoolList
     * @param javaProject
     * @param isRootProject   true when this is the project that the builder was requested to build, false for dependencies
     * @throws NotFoundException
     * @throws CoreException
     */
    private void configureClassPool(ClassPool classPool, List classPoolList, IJavaProject javaProject,
            boolean isRootProject) throws NotFoundException, CoreException {
        LOG.debug("Configuring ClassPool for " + javaProject.getProject().getName()
                + (isRootProject ? " (root project)" : " (project dependency"));
        IClasspathEntry[] entries = javaProject.getResolvedClasspath(true);
        configureClassPool(classPool, classPoolList, entries, javaProject.getProject(), isRootProject);
        // now do dependencies (recursively)
        IProject[] dependencies = javaProject.getProject().getReferencedProjects();
        for (int i = 0; i < dependencies.length; i++) {
            configureClassPool(classPool, classPoolList, JavaCore.create(dependencies[i]), false);
        }
    }

    /**
     * This is where the classpool is actually set. The typical case only requires adding the required jar files
     * to the classpool (classPool and classPoolList), however if the project is dependent on other projects then
     * not only do we need the jar files from these dependencies but we also need the output folders.
     * @TODO EXPERIMENTAL - Dependencies support should be considered experimental at this time because it isn't fully tested ! 
     */
    private void configureClassPool(ClassPool classPool, List classPoolList, IClasspathEntry[] entries,
            IProject project, boolean isRootProject) throws NotFoundException, JavaModelException {

        IClasspathEntry classpathEntry;
        String pathName;

        for (int i = 0; i < entries.length; i++) {
            classpathEntry = JavaCore.getResolvedClasspathEntry(entries[i]);
            IPath classIPath = classpathEntry.getPath();

            if ((isRootProject || classpathEntry.isExported())
                    && classpathEntry.getEntryKind() == IClasspathEntry.CPE_LIBRARY) {
                pathName = getAccessablePathName(classIPath, project);
            } else if (classpathEntry.getEntryKind() == IClasspathEntry.CPE_SOURCE) {
                classIPath = classpathEntry.getOutputLocation();
                if (classIPath == null) {
                    classIPath = JavaCore.create(project).getOutputLocation();
                }
                pathName = getAccessablePathName(classIPath, project);
            } else {
                // Currently we only add : All source folders, All libs in the root project & Exported libs in other projects
                continue;
            }

            if (pathName.contains("floggy-persistence-framework-impl.jar")) {
                continue;
            }
            if (pathName != null && !classPoolList.contains(pathName)) {
                LOG.debug(pathName + " added to classPool");
                classPoolList.add(pathName);
                classPool.appendClassPath(pathName);
            } else {
                LOG.debug(pathName + " alreaded added to classPool");
            }
        }
    }

    /**
     * Make sure that the files or directories are available to the weaver, which doesn't understand eclipse project paths
     * @param path
     * @param project
     * @return
     */
    private String getAccessablePathName(IPath path, IProject project) {
        String pathName = null;
        File pathFile = path.toFile();
        if (pathFile != null && pathFile.exists()) {
            pathName = pathFile.toString();
        } else {
            IFile pathIFile = project.getWorkspace().getRoot().getFile(path);
            if (pathIFile.getLocationURI() != null) {
                pathName = pathIFile.getLocationURI().getPath();
            }
        }
        return pathName;
    }
}