| /******************************************************************************* |
| * Copyright (c) 2000, 2010 BEA Systems, Inc, IBM Corporation, and others |
| * |
| * 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: |
| * mkaufman@bea.com - initial API and implementation |
| * |
| *******************************************************************************/ |
| |
| package org.eclipse.jdt.apt.tests; |
| |
| import java.io.ByteArrayOutputStream; |
| import java.io.File; |
| import java.io.FileFilter; |
| import java.io.FileInputStream; |
| import java.io.FileNotFoundException; |
| import java.io.FileOutputStream; |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.net.URL; |
| import java.util.Collections; |
| import java.util.Enumeration; |
| import java.util.HashMap; |
| import java.util.Map; |
| import java.util.zip.ZipEntry; |
| import java.util.zip.ZipFile; |
| import java.util.zip.ZipInputStream; |
| import java.util.zip.ZipOutputStream; |
| |
| import org.eclipse.core.resources.IFile; |
| import org.eclipse.core.resources.IWorkspace; |
| import org.eclipse.core.resources.IWorkspaceDescription; |
| import org.eclipse.core.resources.ResourcesPlugin; |
| import org.eclipse.core.runtime.CoreException; |
| import org.eclipse.core.runtime.FileLocator; |
| import org.eclipse.core.runtime.IPath; |
| import org.eclipse.core.runtime.IStatus; |
| import org.eclipse.core.runtime.Path; |
| import org.eclipse.core.runtime.Plugin; |
| import org.eclipse.jdt.apt.core.internal.AptPlugin; |
| import org.eclipse.jdt.apt.core.internal.util.FileSystemUtil; |
| import org.eclipse.jdt.apt.tests.plugin.AptTestsPlugin; |
| import org.eclipse.jdt.core.IClasspathEntry; |
| import org.eclipse.jdt.core.IJavaProject; |
| import org.eclipse.jdt.core.JavaCore; |
| import org.eclipse.jdt.core.JavaModelException; |
| import org.eclipse.jdt.core.tests.util.Util; |
| |
| public class TestUtil |
| { |
| |
| private static File ANNO_JAR = null; |
| |
| /** |
| * Returns the annotation jar, creating it if it hasn't already been created. |
| * @return the java.io.File of the jar that was created. |
| */ |
| public static File createAndAddAnnotationJar( IJavaProject project ) |
| throws IOException, JavaModelException |
| { |
| if (ANNO_JAR == null) { |
| // The jar file will be created in the state location, e.g., .metadata/ |
| IPath statePath = AptPlugin.getPlugin().getStateLocation(); |
| IPath jarPath = statePath.append("org.eclipse.jdt.apt.tests.TestUtil.jar"); |
| ANNO_JAR = new File(jarPath.toOSString()); |
| String classesJarPath = ANNO_JAR.getAbsolutePath(); |
| |
| if (null != getFileInPlugin( AptTestsPlugin.getDefault(), new Path("/bin") )) { |
| // We're in a dev environment, where we jar up the classes from the plugin project |
| FileFilter filter = new PackageFileFilter( |
| ANNOTATIONS_PKG, getPluginClassesDir()); |
| Map<File, FileFilter> files = Collections.singletonMap( |
| new File(getPluginClassesDir()), filter); |
| zip( classesJarPath, files ); |
| } |
| else { |
| // We're in a releng environment, where we copy the already-built jar |
| File aptJarFile = getFileInPlugin( AptTestsPlugin.getDefault(), new Path("/apt.jar")); |
| if(null == aptJarFile) { |
| throw new FileNotFoundException("Could not find apt.jar file in org.eclipse.jdt.apt.tests plugin"); |
| } |
| moveFile(aptJarFile, classesJarPath); |
| } |
| |
| ANNO_JAR.deleteOnExit(); |
| } |
| |
| addLibraryEntry( project, new Path(ANNO_JAR.getAbsolutePath()), null /*srcAttachmentPath*/, |
| null /*srcAttachmentPathRoot*/, true ); |
| |
| return ANNO_JAR; |
| } |
| |
| /** |
| * Looks for the apt.jar that is defined in the build.properties |
| * and available when the plugin is built deployed. |
| * (currently when the plugin is built using releng the /bin directory classes are not available) |
| * |
| * else it creates an annotation jar containing annotations and processors |
| * from the "external.annotations" package, and adds it to the project. |
| * Classes will be found under [project]/binext, and manifest will be |
| * drawn from [project]/srcext/META-INF. |
| * This jar is meant to represent an annotation jar file not |
| * wrapped within a plugin. Note that adding a jar to a project makes |
| * its classes visible to the compiler but does NOT automatically cause |
| * its annotation processors to be loaded. |
| * @return the java.io.File of the jar that was created. |
| */ |
| public static File createAndAddExternalAnnotationJar( |
| IJavaProject project ) |
| throws IOException, JavaModelException |
| { |
| // create temporary file |
| File jarFile = File.createTempFile("org.eclipse.jdt.apt.tests.TestUtil", ".jar"); //$NON-NLS-1$//$NON-NLS-2$ |
| String classesJarPath = jarFile.getAbsolutePath(); |
| |
| File extBinDir = getFileInPlugin( AptTestsPlugin.getDefault(), new Path("/binext")); |
| if(null != extBinDir) { |
| |
| //create zip file in temp file location |
| FileFilter classFilter = new PackageFileFilter( |
| EXTANNOTATIONS_PKG, getPluginExtClassesDir()); |
| FileFilter manifestFilter = new PackageFileFilter( |
| "META-INF", getPluginExtSrcDir()); //$NON-NLS-1$ |
| Map<File, FileFilter> files = new HashMap<File, FileFilter>(2); |
| files.put(new File( getPluginExtClassesDir() ), classFilter); |
| files.put(new File( getPluginExtSrcDir() ), manifestFilter); |
| zip( classesJarPath, files ); |
| |
| } else { |
| |
| File extJarFile = getFileInPlugin( AptTestsPlugin.getDefault(), new Path("/aptext.jar")); |
| if(null != extJarFile) { |
| |
| // move extapt.jar to classesJarPath file |
| moveFile(extJarFile, classesJarPath); |
| |
| } else { |
| |
| throw new FileNotFoundException("Could not find aptext.jar file in org.eclipse.jdt.apt.tests plugin"); |
| } |
| |
| } |
| |
| addLibraryEntry( project, new Path(classesJarPath), null /*srcAttachmentPath*/, |
| null /*srcAttachmentPathRoot*/, true ); |
| |
| |
| // This file will be locked until GC takes care of unloading the |
| // annotation processor classes, so we can't delete it ourselves. |
| jarFile.deleteOnExit(); |
| return jarFile; |
| |
| } |
| |
| /** |
| * In automated tests, newly created resources are often locked by the |
| * Java Indexer and cannot be deleted right away. The methods in |
| * org.eclipse.jdt.core.tests.util.Util work around this by catching |
| * and retrying until success. This is a convenience method to fill a |
| * hole in the Util API. |
| * @return an IStatus that describes if the deletion was successful |
| */ |
| public static IStatus deleteFile(IPath path) { |
| IFile file = ResourcesPlugin.getWorkspace().getRoot().getFile(path); |
| return Util.delete(file); |
| } |
| |
| /** |
| * Set the autobuild to the value of the parameter and |
| * return the old one. This is a workaround for a synchronization |
| * problem: thread A creates a project, thus spawning thread B to |
| * do an autobuild. Thread A goes on to configure the project's |
| * classpath; at the same time, thread B calls APT, which configures |
| * the project's classpath. Access to the classpath is not |
| * synchronized, so there's a race for which thread's modification |
| * wins. We work around this by disabling autobuild. |
| * |
| * @param state the value to be set for autobuilding. |
| * @return the old value of the autobuild state |
| */ |
| public static boolean enableAutoBuild(boolean state) { |
| IWorkspace workspace= ResourcesPlugin.getWorkspace(); |
| IWorkspaceDescription desc= workspace.getDescription(); |
| boolean isAutoBuilding= desc.isAutoBuilding(); |
| if (isAutoBuilding != state) { |
| desc.setAutoBuilding(state); |
| try { |
| workspace.setDescription(desc); |
| } catch (CoreException e) { |
| e.printStackTrace(); |
| } |
| } |
| return isAutoBuilding; |
| } |
| |
| public static IPath getProjectPath( IJavaProject project ) |
| { |
| return project.getResource().getLocation(); |
| } |
| |
| public static String getPluginClassesDir() |
| { |
| return getFileInPlugin( AptTestsPlugin.getDefault(), new Path( "/bin" ) ) //$NON-NLS-1$ |
| .getAbsolutePath(); |
| } |
| |
| public static String getPluginExtClassesDir() |
| { |
| return getFileInPlugin( AptTestsPlugin.getDefault(), new Path( "/binext" ) ) //$NON-NLS-1$ |
| .getAbsolutePath(); |
| } |
| |
| public static String getPluginExtSrcDir() |
| { |
| return getFileInPlugin( AptTestsPlugin.getDefault(), new Path( "/srcext" ) ) //$NON-NLS-1$ |
| .getAbsolutePath(); |
| } |
| |
| /** |
| * |
| * @param plugin The Plugin to get file from |
| * @param path The path to the file in the Plugin |
| * @return File object if found, null otherwise |
| */ |
| public static java.io.File getFileInPlugin(Plugin plugin, IPath path) |
| { |
| try |
| { |
| URL installURL = plugin.getBundle().getEntry( path.toString() ); |
| if(null == installURL) |
| return null; // File Not found |
| |
| URL localURL = FileLocator.toFileURL( installURL ); |
| return new java.io.File( localURL.getFile() ); |
| } |
| catch( IOException e ) |
| { |
| return null; |
| } |
| } |
| |
| /** |
| * Could use File.renameTo(File) but it's platform dependant. |
| * |
| * @param from - The file to move |
| * @param path - The path to move it to |
| */ |
| public static void moveFile(File from , String toPath) |
| throws FileNotFoundException, IOException { |
| |
| FileInputStream fis = null; |
| FileOutputStream fos = null; |
| try |
| { |
| fis = new FileInputStream( from ); |
| fos = new FileOutputStream(new File(toPath)); |
| int b; |
| while ( ( b = fis.read() ) != -1) |
| fos.write( b ); |
| } |
| finally |
| { |
| if ( fis != null ) fis.close(); |
| if ( fos != null ) fos.close(); |
| } |
| } |
| |
| /** |
| * Create a zip file and add contents. |
| * @param zipPath the zip file |
| * @param input a map of root directories and corresponding filters. Each |
| * root directory will be searched, and any files that pass the filter will |
| * be added to the zip file. |
| * @throws IOException |
| */ |
| public static void zip(String zipPath, Map<File, FileFilter> input) |
| throws IOException |
| { |
| ZipOutputStream zip = null; |
| try |
| { |
| zip = new ZipOutputStream( new FileOutputStream( zipPath ) ); |
| // +1 for last slash |
| for (Map.Entry<File, FileFilter> e : input.entrySet()) { |
| zip( zip, e.getKey(), e.getKey().getPath().length() + 1, e.getValue() ); |
| } |
| } |
| finally |
| { |
| if( zip != null ) |
| { |
| zip.close(); |
| } |
| } |
| } |
| |
| private static void zip(ZipOutputStream zip, File dir, int rootPathLength, |
| FileFilter filter) throws IOException |
| { |
| String[] list = dir.list(); |
| if( list != null ) |
| { |
| for( int i = 0, length = list.length; i < length; i++ ) |
| { |
| String name = list[i]; |
| File file = new File( dir, name ); |
| if( filter == null || filter.accept( file ) ) |
| { |
| if( file.isDirectory() ) |
| { |
| zip( zip, file, rootPathLength, filter ); |
| } |
| else |
| { |
| String path = file.getPath(); |
| path = path.substring( rootPathLength ); |
| ZipEntry entry = new ZipEntry( path.replace( '\\', '/' ) ); |
| zip.putNextEntry( entry ); |
| zip.write( getBytesFromFile( file ) ); |
| zip.closeEntry(); |
| } |
| } |
| } |
| } |
| } |
| |
| private static byte[] getBytesFromFile( File f ) |
| throws IOException |
| { |
| FileInputStream fis = null; |
| ByteArrayOutputStream baos = null; |
| byte[] rtrn = new byte[0]; |
| try |
| { |
| fis = new FileInputStream( f ); |
| baos = new ByteArrayOutputStream(); |
| int b; |
| while ( ( b = fis.read() ) != -1) |
| baos.write( b ); |
| rtrn = baos.toByteArray(); |
| } |
| finally |
| { |
| if ( fis != null ) fis.close(); |
| if ( baos != null ) baos.close(); |
| } |
| return rtrn; |
| |
| } |
| |
| public static void unzip (File srcZip, File destDir) throws IOException { |
| ZipFile zf = new ZipFile(srcZip); |
| for (Enumeration<? extends ZipEntry> entries = zf.entries(); entries.hasMoreElements();) { |
| ZipEntry entry = entries.nextElement(); |
| String name = entry.getName(); |
| File dest = new File(destDir, name); |
| if (entry.isDirectory()) { |
| FileSystemUtil.mkdirs(dest); |
| } |
| else { |
| File parent = dest.getParentFile(); |
| FileSystemUtil.mkdirs(parent); |
| InputStream from = null; |
| OutputStream to = null; |
| try { |
| from = zf.getInputStream(entry); |
| to = new FileOutputStream(dest); |
| byte[] buffer = new byte[4096]; |
| int bytesRead; |
| while ((bytesRead = from.read(buffer)) != -1) { |
| to.write(buffer, 0, bytesRead); |
| } |
| } |
| finally { |
| if (from != null) try {from.close();} catch (IOException ioe){} |
| if (to != null) try {to.close();} catch (IOException ioe) {} |
| } |
| } |
| } |
| } |
| |
| public static void unzip (ZipInputStream srcZip, File destDir) throws IOException { |
| ZipEntry entry; |
| while ((entry = srcZip.getNextEntry()) != null) { |
| String name = entry.getName(); |
| File dest = new File(destDir, name); |
| if (entry.isDirectory()) { |
| FileSystemUtil.mkdirs(dest); |
| } |
| else { |
| File parent = dest.getParentFile(); |
| FileSystemUtil.mkdirs(parent); |
| OutputStream to = null; |
| try { |
| to = new FileOutputStream(dest); |
| byte[] buffer = new byte[4096]; |
| int bytesRead; |
| while ((bytesRead = srcZip.read(buffer)) != -1) { |
| to.write(buffer, 0, bytesRead); |
| } |
| } |
| finally { |
| srcZip.closeEntry(); |
| if (to != null) try {to.close();} catch (IOException ioe) {} |
| } |
| } |
| } |
| } |
| |
| |
| public static void addLibraryEntry(IJavaProject project, IPath path, IPath srcAttachmentPath, IPath srcAttachmentPathRoot, boolean exported) throws JavaModelException{ |
| IClasspathEntry[] entries = project.getRawClasspath(); |
| int length = entries.length; |
| IClasspathEntry newPathEntry = JavaCore.newLibraryEntry( |
| path, |
| srcAttachmentPath, |
| srcAttachmentPathRoot, |
| exported); |
| for(int i = 0; i < length; i++) { |
| //check for duplicates (Causes JavaModelException) - return if path already exists |
| if(newPathEntry.equals(entries[i])) |
| return; |
| } |
| System.arraycopy(entries, 0, entries = new IClasspathEntry[length + 1], 1, length); |
| entries[0] = newPathEntry; |
| project.setRawClasspath(entries, null); |
| } |
| |
| |
| private static class PackageFileFilter implements FileFilter { |
| private final String[] _packageParts; |
| private final Path _binDir; |
| |
| /** |
| * Select only those files under a certain package. |
| * @param packageSubset a partial package name, such as |
| * "org.eclipse.jdt.apt.tests.annotations". |
| * @param binDir the absolute path of the directory |
| * in which the compiled classes are to be found. |
| */ |
| public PackageFileFilter(String packageSubset, String binDir) { |
| _packageParts = packageSubset.split("\\."); //$NON-NLS-1$ |
| _binDir = new Path(binDir); |
| } |
| |
| public boolean accept(File pathname) |
| { |
| IPath f = new Path( pathname.getAbsolutePath() ); |
| |
| int nsegments = f.matchingFirstSegments( _binDir ); |
| boolean ok = true; |
| int min = Math.min( f.segmentCount() - nsegments, |
| _packageParts.length ); |
| for( int i = nsegments, j = 0; j < min; i++, j++ ) |
| { |
| if( !f.segment( i ).equals( _packageParts[j] ) ) |
| { |
| ok = false; |
| break; |
| } |
| } |
| return ok; |
| } |
| } |
| |
| public static final String ANNOTATIONS_PKG = |
| "org.eclipse.jdt.apt.tests.annotations"; //$NON-NLS-1$ |
| |
| public static final String EXTANNOTATIONS_PKG = |
| "org.eclipse.jdt.apt.tests.external.annotations"; //$NON-NLS-1$ |
| |
| } |