Java tutorial
/** * 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; } }