Java tutorial
/****************************************************************************** * Copyright (c) 2010-2013, Linagora * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Linagora - initial API and implementation *******************************************************************************/ package com.ebmwebsourcing.petals.common.internal.provisional.utils; import java.io.File; import java.io.FilenameFilter; import java.io.IOException; import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IFolder; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IProjectDescription; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.CoreException; import org.eclipse.core.runtime.IPath; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.NullProgressMonitor; import org.eclipse.core.runtime.Path; import org.eclipse.jdt.core.IClasspathEntry; import org.eclipse.jdt.core.IJavaElement; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IPackageFragment; import org.eclipse.jdt.core.IPackageFragmentRoot; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jdt.ui.jarpackager.IJarExportRunnable; import org.eclipse.jdt.ui.jarpackager.JarPackageData; import com.ebmwebsourcing.petals.common.internal.PetalsCommonPlugin; /** * @author Vincent Zurczak - EBM WebSourcing */ public final class JavaUtils { /** * Private constructor for utility class. */ private JavaUtils() { // nothing } /** * Get the referenced projects from a Java project. * <p>The result includes the argument project.</p> * * @param javaProject * @return */ public static List<IJavaProject> getJavaProjectDependencies(IJavaProject javaProject) { if (javaProject == null) return Collections.emptyList(); List<IJavaProject> result = new ArrayList<IJavaProject>(); result.add(javaProject); String[] projectNames; try { projectNames = javaProject.getRequiredProjectNames(); } catch (JavaModelException e1) { PetalsCommonPlugin.log(e1, IStatus.WARNING); projectNames = new String[0]; } for (String projectName : projectNames) { IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); try { if (!project.exists() || !project.isOpen() || !project.hasNature(JavaCore.NATURE_ID)) continue; } catch (CoreException e) { PetalsCommonPlugin.log(e, IStatus.ERROR); continue; } IJavaProject p = JavaCore.create(project); result.add(p); } return result; } /** * Updates the class path of a Java project with libraries embedded by the studio. * @param jp the Java project * @param folders the folder names * @throws IOException * @throws JavaModelException */ public static void updateClasspathWithProjectLibraries(IJavaProject jp, IProgressMonitor monitor, String... folders) throws IOException, JavaModelException { if (folders == null) return; // Keep the current entries ArrayList<IClasspathEntry> entries = new ArrayList<IClasspathEntry>(); entries.addAll(Arrays.asList(jp.getRawClasspath())); FilenameFilter filter = new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.endsWith(".jar") || name.endsWith(".zip"); } }; for (String folder : folders) { File pojoLibPath = ResourceUtils.getPluginBinaryPath("com.ebmwebsourcing.petals.libs.esb", folder); //$NON-NLS-1$ if (pojoLibPath == null) { PetalsCommonPlugin.log("Could not find the Petals libraries in the distribution.", IStatus.ERROR); throw new IOException("Petals libraries could not be located."); } // Add the libraries in the project class path File[] jarFiles = pojoLibPath.listFiles(filter); if (jarFiles != null) { for (File jarFile : jarFiles) { IPath path = new Path(jarFile.getAbsolutePath()); IClasspathEntry entry = JavaCore.newLibraryEntry(path, null, null); entries.add(entry); } } } IClasspathEntry[] newEntries = CollectionUtils.convertToArray(entries, IClasspathEntry.class); if (!jp.hasClasspathCycle(newEntries)) jp.setRawClasspath(newEntries, monitor); } /** * Makes an Eclipse project a Java project. * <p> * If the project does not exist, or is not accessible, then nothing is done.<br /> * If the project does not have the Java nature, this nature is added. * </p> * <p> * The default output directory is "bin". If this directory does not exist, it is created. * If the creation fails, then no output directory is set. * </p> * <p> * The default source directory is "src/main/java". If this directory does not exist, it is created. * If the creation fails, then no source directory is set. * </p> * * @param project the project to transform into a Java project * @return the created Java project * @throws CoreException if something went wrong */ public static IJavaProject createJavaProject(IProject project) throws CoreException { IJavaProject jp = null; if (project.isAccessible()) { // Add the Java nature? if (!project.hasNature(JavaCore.NATURE_ID)) { IProjectDescription description = project.getDescription(); String[] natures = description.getNatureIds(); String[] newNatures = new String[natures.length + 1]; System.arraycopy(natures, 0, newNatures, 0, natures.length); newNatures[natures.length] = JavaCore.NATURE_ID; description.setNatureIds(newNatures); project.setDescription(description, null); } // Set the default class path jp = JavaCore.create(project); IProgressMonitor monitor = new NullProgressMonitor(); // // Output location IPath ppath = project.getFullPath(); IPath binPath = ppath.append(PetalsConstants.LOC_BIN_FOLDER); File binFile = ResourcesPlugin.getWorkspace().getRoot().getLocation().append(binPath).toFile(); if (binFile.exists() && binFile.isDirectory() || !binFile.exists() && binFile.mkdirs()) { jp.setOutputLocation(binPath, monitor); } Set<IClasspathEntry> entries = new HashSet<IClasspathEntry>(); entries.addAll(Arrays.asList(jp.getRawClasspath())); entries.add(JavaRuntime.getDefaultJREContainerEntry()); // // Remove the "src" entry IClasspathEntry srcEntry = null; for (IClasspathEntry entry : entries) { if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) { srcEntry = entry; break; } } // // Specify a new source entry if (srcEntry != null) entries.remove(srcEntry); String[] srcPaths = new String[] { PetalsConstants.LOC_SRC_FOLDER, PetalsConstants.LOC_JAVA_RES_FOLDER }; for (String s : srcPaths) { IPath srcPath = ppath.append(s); File srcFile = ResourcesPlugin.getWorkspace().getRoot().getLocation().append(srcPath).toFile(); if (srcFile.exists() && srcFile.isDirectory() || !srcFile.exists() && srcFile.mkdirs()) { project.refreshLocal(IResource.DEPTH_INFINITE, monitor); srcEntry = JavaCore.newSourceEntry(srcPath); entries.add(srcEntry); } else { PetalsCommonPlugin.log("Could not set '" + s + "' as a source folder.", IStatus.ERROR); } } jp.setRawClasspath(entries.toArray(new IClasspathEntry[entries.size()]), monitor); } return jp; } /** * Gets the source folders of a IJavaProject. * @param javaProject * @return the list of source folders in this Java project */ public static List<IClasspathEntry> getSourceFolders(IJavaProject javaProject) { List<IClasspathEntry> result = new ArrayList<IClasspathEntry>(); try { for (IClasspathEntry entry : javaProject.getRawClasspath()) { if (entry.getEntryKind() == IClasspathEntry.CPE_SOURCE) result.add(entry); } } catch (JavaModelException e) { PetalsCommonPlugin.log(e, IStatus.ERROR); } return result; } /** * Get the class path from Java project. * * @param javaProject * @param getReferencedProjectClasspath * @param binaryDirectory * @return the class path as a list of string locations. */ public static List<String> getClasspath(IJavaProject javaProject, boolean getReferencedProjectClasspath, boolean binaryDirectory) { List<String> paths = new ArrayList<String>(); try { if (javaProject != null) { // Get the raw class path IClasspathEntry[] entries = javaProject.getRawClasspath(); for (IClasspathEntry entry : entries) { switch (entry.getEntryKind()) { case IClasspathEntry.CPE_PROJECT: if (!getReferencedProjectClasspath) break; String projectName = entry.getPath().toString(); IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); IJavaProject jProject = JavaCore.create(project); List<String> subPaths = getClasspath(jProject, true, binaryDirectory); paths.addAll(subPaths); break; case IClasspathEntry.CPE_LIBRARY: IPath path = entry.getPath(); paths.add(path.toString()); break; case IClasspathEntry.CPE_VARIABLE: entry = JavaCore.getResolvedClasspathEntry(entry); if (entry != null) { path = entry.getPath(); paths.add(path.toString()); } break; } } // Add the "bin" directory? if (binaryDirectory && javaProject.getOutputLocation() != null) { IPath path = ResourcesPlugin.getWorkspace().getRoot().getLocation(); path = path.append(javaProject.getOutputLocation()); paths.add(path.toString()); } } } catch (JavaModelException e) { PetalsCommonPlugin.log(e, IStatus.ERROR); } return paths; } /** * Creates a JAR file containing all the resources contained in the source folders of a Java project. * @param jp the Java project * @param monitor the progress monitor * @return the JAR file, which was saved in the temporary folder (and should be deleted after use) * @throws InvocationTargetException if the creation failed * @throws InterruptedException if the creation was interrupted */ public static File createDefaultJar(IJavaProject jp, IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { // Create a default JAR for the implementation JarPackageData jarDescription = new JarPackageData(); jarDescription.setIncludeDirectoryEntries(true); jarDescription.setExportClassFiles(true); jarDescription.setOverwrite(true); jarDescription.setIncludeDirectoryEntries(true); jarDescription.setExportJavaFiles(false); jarDescription.setCompress(true); jarDescription.setExportErrors(true); jarDescription.setExportWarnings(true); // Add all the files in the source folders List<Object> filesToPackage = new ArrayList<Object>(); for (IClasspathEntry entry : getSourceFolders(jp)) { // PETALSSTUD-130: use the project location and not the workspace root as a reference File f = jp.getProject().getLocation().append(entry.getPath().removeFirstSegments(1)).toFile(); // PETALSSTUD-130 IFolder folder = (IFolder) ResourceUtils.getResource(f); if (folder != null) { List<IFile> files = ResourceUtils.getFilesByRegexp(folder, ".*"); filesToPackage.addAll(files); } } Object[] elements = new Object[filesToPackage.size()]; jarDescription.setElements(filesToPackage.toArray(elements)); // Create the JAR IPath jarLocation = new Path(System.getProperty("java.io.tmpdir")) .append(jp.getProject().getName() + ".jar"); // Bug: Windows => path separator = "\" // But IPath#isAbsolute() only checks for "/" path separators // => We replace the path separator // Otherwise, the JAR is created, but not at the location we would expect jarLocation = new Path(jarLocation.toString().replaceAll("\\\\", "/")); jarDescription.setJarLocation(jarLocation); IJarExportRunnable runnable = jarDescription.createJarExportRunnable(null); runnable.run(monitor); IStatus status = runnable.getStatus(); if (!status.isOK()) PetalsCommonPlugin.getDefault().getLog().log(status); return jarLocation.toFile(); } /** * Creates a new source folder. * <p> * If the folder does not exist, it is created.<br /> * If the directory is already in the class path, then this method does nothing. * </p> * * @param jp the Java project * @param folderName the folder name * @param monitor the progress monitor * @return the created folder * @throws CoreException if something went wrong */ public static IFolder createSourceFolder(IJavaProject jp, String folderName, IProgressMonitor monitor) throws CoreException { IFolder newSourceFolder = jp.getProject().getFolder(folderName); if (!newSourceFolder.exists()) newSourceFolder.create(true, true, monitor); IClasspathEntry srcEntry = JavaCore.newSourceEntry(newSourceFolder.getFullPath()); Set<IClasspathEntry> entries = new HashSet<IClasspathEntry>(); entries.addAll(Arrays.asList(jp.getRawClasspath())); entries.add(srcEntry); jp.setRawClasspath(entries.toArray(new IClasspathEntry[entries.size()]), monitor); return newSourceFolder; } /** * Gets a set of JAR files from a Java project, in order to package them. * @param jp the Java project * @param monitor the progress monitor * @return an instance of {@link ExportableClassPath} (never null) */ public static ExportableClassPath getExportableClasspath(IJavaProject jp, IProgressMonitor monitor) { ExportableClassPath result = new ExportableClassPath(); try { // Check the class path IClasspathEntry[] entries = jp.getRawClasspath(); for (IClasspathEntry entry : entries) updateExportableResult(result, entry, monitor); // Package the implementation File jarFile = createDefaultJar(jp, monitor); result.implementationJars.add(jarFile); monitor.worked(1); } catch (JavaModelException e) { PetalsCommonPlugin.log(e, IStatus.ERROR); } catch (InvocationTargetException e) { PetalsCommonPlugin.log(e, IStatus.ERROR); } catch (InterruptedException e) { PetalsCommonPlugin.log(e, IStatus.ERROR); } return result; } /** * Populates an {@link ExportableClassPath} instance from a class path entry. * @param result the {@link ExportableClassPath} instance to populate * @param entry a class path entry * @param monitor the progress monitor */ private static void updateExportableResult(ExportableClassPath result, IClasspathEntry entry, IProgressMonitor monitor) { switch (entry.getEntryKind()) { case IClasspathEntry.CPE_PROJECT: String projectName = entry.getPath().toString(); IProject project = ResourcesPlugin.getWorkspace().getRoot().getProject(projectName); IJavaProject jProject = JavaCore.create(project); ExportableClassPath subResult = getExportableClasspath(jProject, monitor); result.implementationJars.addAll(subResult.implementationJars); result.libraryJars.addAll(subResult.libraryJars); monitor.worked(1); break; case IClasspathEntry.CPE_LIBRARY: IPath path = entry.getPath(); if (path != null) { File f = path.toFile(); if (f.exists()) { if (f.getName().endsWith(".zip") || f.getName().endsWith(".jar")) result.libraryJars.add(f); } } break; case IClasspathEntry.CPE_VARIABLE: entry = JavaCore.getResolvedClasspathEntry(entry); if (entry != null) updateExportableResult(result, entry, monitor); break; } } /** * This class is used to manage the class path elements to export for a Java project. * <p> * It manages through 2 distinct lists the libraries used in the project, and the * implementations JAR that are built during the export operation. * </p> * <p> * Once this class has been used, the method {@link #deleteImplementationJars()} should * be invoked. * </p> */ public static class ExportableClassPath { private final Set<File> libraryJars = new HashSet<File>(); private final Set<File> implementationJars = new HashSet<File>(); /** * @return the class path, including both the library and the */ public Set<File> getExportableClassPath() { Set<File> result = new HashSet<File>(); result.addAll(this.libraryJars); result.addAll(this.implementationJars); return result; } /** * Deletes the all (temporary) implementation JAR files. */ public void deleteImplementationJars() { for (File f : this.implementationJars) { if (!f.exists()) PetalsCommonPlugin.log(f.getAbsolutePath() + " does not exist.", IStatus.WARNING); if (f.exists() && !f.delete()) f.deleteOnExit(); } } } /** * Finds the direct children for a given package. * <p> * Copied (or almost) from the JDT. * </p> * * @param parent the package fragment root (will be searched from <code>fragment</code> if null) * @param fragment the fragment to analyze (can be null if <code>parent</code> is not) * @return a list of package fragments * @throws JavaModelException if an error occurred with the Java model */ public static List<IPackageFragment> findDirectSubPackages(IPackageFragmentRoot parent, IPackageFragment fragment) throws JavaModelException { // Special case for the default package if (fragment != null && fragment.isDefaultPackage()) return Collections.emptyList(); // Find the package parent? if (parent == null) { IJavaElement elt = fragment; while (elt.getParent() != null) { elt = elt.getParent(); if (elt instanceof IPackageFragmentRoot) { parent = (IPackageFragmentRoot) elt; break; } } } // Find the direct children List<IPackageFragment> result = new ArrayList<IPackageFragment>(); if (parent != null) { IJavaElement[] children = parent.getChildren(); String prefix = fragment != null ? fragment.getElementName() + '.' : ""; //$NON-NLS-1$ int prefixLen = prefix.length(); for (IJavaElement element : children) { IPackageFragment curr = (IPackageFragment) element; String name = curr.getElementName(); if (name.startsWith(prefix) && name.length() > prefixLen && name.indexOf('.', prefixLen) == -1) result.add(curr); else if (fragment == null && curr.isDefaultPackage()) result.add(curr); } } return result; } }