blob: c469598378d1f32ba43e62894fddcca3acfea81c [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2000, 2005 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.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.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;
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;
}
/**
* 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$
}