Java tutorial
/******************************************************************************* * Copyright (c) 2007, 2013 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: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.pde.api.tools.internal.util; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; 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.FileWriter; import java.io.FilenameFilter; import java.io.IOException; import java.io.InputStream; import java.io.LineNumberReader; import java.io.PrintWriter; import java.io.StringReader; import java.io.UnsupportedEncodingException; import java.lang.reflect.Field; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CodingErrorAction; import java.nio.charset.IllegalCharsetNameException; import java.nio.charset.UnsupportedCharsetException; import java.util.ArrayList; import java.util.Arrays; import java.util.Comparator; import java.util.Enumeration; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.Set; import java.util.StringTokenizer; import java.util.jar.JarFile; import java.util.regex.Pattern; import java.util.regex.PatternSyntaxException; import java.util.zip.ZipEntry; import java.util.zip.ZipException; import java.util.zip.ZipFile; import java.util.zip.ZipInputStream; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.FactoryConfigurationError; import javax.xml.parsers.ParserConfigurationException; import javax.xml.transform.OutputKeys; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; import org.eclipse.core.filebuffers.FileBuffers; import org.eclipse.core.filebuffers.ITextFileBufferManager; import org.eclipse.core.filebuffers.LocationKind; import org.eclipse.core.resources.IFile; import org.eclipse.core.resources.IMarker; import org.eclipse.core.resources.IProject; import org.eclipse.core.resources.IResource; import org.eclipse.core.resources.IncrementalProjectBuilder; import org.eclipse.core.resources.ResourcesPlugin; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.AssertionFailedException; 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.OperationCanceledException; import org.eclipse.core.runtime.Path; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.SubMonitor; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.ICompilationUnit; import org.eclipse.jdt.core.IField; import org.eclipse.jdt.core.IJavaProject; import org.eclipse.jdt.core.IMember; import org.eclipse.jdt.core.IMethod; import org.eclipse.jdt.core.IType; import org.eclipse.jdt.core.JavaCore; import org.eclipse.jdt.core.JavaModelException; import org.eclipse.jdt.core.Signature; import org.eclipse.jdt.internal.compiler.codegen.ConstantPool; import org.eclipse.jdt.launching.IVMInstall; import org.eclipse.jdt.launching.JavaRuntime; import org.eclipse.jdt.launching.LibraryLocation; import org.eclipse.jdt.launching.environments.ExecutionEnvironmentDescription; import org.eclipse.jface.text.IDocument; import org.eclipse.osgi.util.NLS; import org.eclipse.pde.api.tools.internal.FilterStore; import org.eclipse.pde.api.tools.internal.IApiCoreConstants; import org.eclipse.pde.api.tools.internal.builder.BuildState; import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin; import org.eclipse.pde.api.tools.internal.provisional.Factory; import org.eclipse.pde.api.tools.internal.provisional.IApiMarkerConstants; import org.eclipse.pde.api.tools.internal.provisional.IRequiredComponentDescription; import org.eclipse.pde.api.tools.internal.provisional.VisibilityModifiers; import org.eclipse.pde.api.tools.internal.provisional.comparator.DeltaVisitor; import org.eclipse.pde.api.tools.internal.provisional.comparator.IDelta; import org.eclipse.pde.api.tools.internal.provisional.descriptors.IReferenceTypeDescriptor; import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline; import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent; import org.eclipse.pde.api.tools.internal.provisional.model.IApiElement; import org.eclipse.pde.api.tools.internal.provisional.model.IApiType; import org.eclipse.pde.api.tools.internal.provisional.model.IApiTypeRoot; import org.eclipse.pde.api.tools.internal.search.SkippedComponent; import org.objectweb.asm.Opcodes; import org.osgi.framework.Version; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; import org.xml.sax.helpers.DefaultHandler; /** * A Utility class to use for API tools * * @since 1.0.0 */ public final class Util { public static final String DOT_TGZ = ".tgz"; //$NON-NLS-1$ public static final String DOT_TAR_GZ = ".tar.gz"; //$NON-NLS-1$ public static final String DOT_JAR = ".jar"; //$NON-NLS-1$ public static final String DOT_ZIP = ".zip"; //$NON-NLS-1$ public static final char VERSION_SEPARATOR = '('; /** * Class that runs a build in the workspace or the given project */ private static final class BuildJob extends Job { private final IProject[] fProjects; private int fBuildType; /** * Constructor * * @param name * @param project */ BuildJob(String name, IProject[] projects) { this(name, projects, IncrementalProjectBuilder.FULL_BUILD); } BuildJob(String name, IProject[] projects, int buildType) { super(name); fProjects = projects; this.fBuildType = buildType; } @Override public boolean belongsTo(Object family) { return ResourcesPlugin.FAMILY_MANUAL_BUILD == family; } /** * Returns if this build job is covered by another build job * * @param other * @return true if covered by another build job, false otherwise */ public boolean isCoveredBy(BuildJob other) { if (other.fProjects == null) { return true; } if (this.fProjects != null) { for (int i = 0, max = this.fProjects.length; i < max; i++) { if (!other.contains(this.fProjects[i])) { return false; } } return true; } return false; } public boolean contains(IProject project) { if (project == null) { return false; } for (int i = 0, max = this.fProjects.length; i < max; i++) { if (project.equals(this.fProjects[i])) { return true; } } return false; } /* * (non-Javadoc) * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime. * IProgressMonitor) */ @Override protected IStatus run(IProgressMonitor monitor) { synchronized (getClass()) { if (monitor.isCanceled()) { return Status.CANCEL_STATUS; } // cancelBuild(ResourcesPlugin.FAMILY_AUTO_BUILD); cancelBuild(ResourcesPlugin.FAMILY_MANUAL_BUILD); } try { if (fProjects != null) { SubMonitor localmonitor = SubMonitor.convert(monitor, UtilMessages.Util_0, fProjects.length); for (int i = 0, max = fProjects.length; i < max; i++) { // clear last build state for project to force a full // build using our builder // This makes it possible to have only an incremental // build from the java builder IProject currentProject = fProjects[i]; if (this.fBuildType == IncrementalProjectBuilder.FULL_BUILD) { BuildState.setLastBuiltState(currentProject, null); } localmonitor.subTask(NLS.bind(UtilMessages.Util_5, currentProject.getName())); if (ResourcesPlugin.getWorkspace().isAutoBuilding()) { currentProject.touch(null); } else { currentProject.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, localmonitor.newChild(1)); } } } } catch (CoreException e) { return new Status(e.getStatus().getSeverity(), ApiPlugin.PLUGIN_ID, ApiPlugin.INTERNAL_ERROR, UtilMessages.Util_builder_errorMessage, e); } catch (OperationCanceledException e) { return Status.CANCEL_STATUS; } finally { monitor.done(); } return Status.OK_STATUS; } private void cancelBuild(Object jobfamily) { Job[] buildJobs = Job.getJobManager().find(jobfamily); for (int i = 0; i < buildJobs.length; i++) { Job curr = buildJobs[i]; if (curr != this && curr instanceof BuildJob) { BuildJob job = (BuildJob) curr; if (job.isCoveredBy(this)) { curr.cancel(); // cancel all other build jobs of our // kind } } } } } public static final String EMPTY_STRING = "";//$NON-NLS-1$ public static final String DEFAULT_PACKAGE_NAME = EMPTY_STRING; public static final String MANIFEST_NAME = "MANIFEST.MF"; //$NON-NLS-1$ public static final String DOT_CLASS_SUFFIX = ".class"; //$NON-NLS-1$ public static final String DOT_JAVA_SUFFIX = ".java"; //$NON-NLS-1$ /** * Constant representing the default size to read from an input stream */ private static final int DEFAULT_READING_SIZE = 8192; private static final String JAVA_LANG_OBJECT = "java.lang.Object"; //$NON-NLS-1$ private static final String JAVA_LANG_RUNTIMEEXCEPTION = "java.lang.RuntimeException"; //$NON-NLS-1$ public static final String LINE_DELIMITER = System.getProperty("line.separator"); //$NON-NLS-1$ public static final String UNKNOWN_ELEMENT_KIND = "UNKNOWN_ELEMENT_KIND"; //$NON-NLS-1$ public static final String UNKNOWN_FLAGS = "UNKNOWN_FLAGS"; //$NON-NLS-1$ public static final String UNKNOWN_KIND = "UNKNOWN_KIND"; //$NON-NLS-1$ public static final String UNKNOWN_VISIBILITY = "UNKNOWN_VISIBILITY"; //$NON-NLS-1$ public static final String ISO_8859_1 = "ISO-8859-1"; //$NON-NLS-1$ public static final String REGULAR_EXPRESSION_START = "R:"; //$NON-NLS-1$ // Trace for delete operation /* * Maximum time wasted repeating delete operations while running JDT/Core * tests. */ private static int DELETE_MAX_TIME = 0; /** * Trace deletion operations while running JDT/Core tests. */ private static boolean DELETE_DEBUG = false; /** * Maximum of time in milliseconds to wait in deletion operation while * running JDT/Core tests. Default is 10 seconds. This number cannot exceed * 1 minute (i.e. 60000). <br> * To avoid too many loops while waiting, the ten first ones are done * waiting 10ms before repeating, the ten loops after are done waiting 100ms * and the other loops are done waiting 1s... */ private static int DELETE_MAX_WAIT = 10000; public static final IPath MANIFEST_PROJECT_RELATIVE_PATH = new Path(JarFile.MANIFEST_NAME); public static final String ORG_ECLIPSE_SWT = "org.eclipse.swt"; //$NON-NLS-1$ /** * Throws an exception with the given message and underlying exception. * * @param message error message * @param exception underlying exception, or <code>null</code> * @throws CoreException */ private static void abort(String message, Throwable exception) throws CoreException { IStatus status = new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, message, exception); throw new CoreException(status); } /** * Appends a property to the given string buffer with the given key and * value in the format "key=value\n". * * @param buffer buffer to append to * @param key key * @param value value */ private static void appendProperty(StringBuffer buffer, String key, String value) { buffer.append(key); buffer.append('='); buffer.append(value); buffer.append('\n'); } /** * Collects all of the deltas from the given parent delta * * @param delta * @return */ public static List<IDelta> collectAllDeltas(IDelta delta) { final List<IDelta> list = new ArrayList<IDelta>(); delta.accept(new DeltaVisitor() { @Override public void endVisit(IDelta localDelta) { if (localDelta.getChildren().length == 0) { list.add(localDelta); } super.endVisit(localDelta); } }); return list; } /** * Collects files into the collector array list * * @param root the root to collect the files from * @param collector the collector to place matches into * @param fileFilter the filter for files or <code>null</code> to accept all * files */ private static void collectAllFiles(File root, ArrayList<File> collector, FileFilter fileFilter) { File[] files = root.listFiles(fileFilter); for (int i = 0; i < files.length; i++) { final File currentFile = files[i]; if (currentFile.isDirectory()) { collectAllFiles(currentFile, collector, fileFilter); } else { collector.add(currentFile); } } } /** * Returns all of the API projects in the workspace * * @return all of the API projects in the workspace or <code>null</code> if * there are none. */ public static IProject[] getApiProjects() { IProject[] allProjects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); ArrayList<IProject> temp = new ArrayList<IProject>(); IProject project = null; for (int i = 0, max = allProjects.length; i < max; i++) { project = allProjects[i]; if (project.isAccessible()) { try { if (project.hasNature(org.eclipse.pde.api.tools.internal.provisional.ApiPlugin.NATURE_ID)) { temp.add(project); } } catch (CoreException e) { } } } IProject[] projects = null; if (temp.size() != 0) { projects = new IProject[temp.size()]; temp.toArray(projects); } return projects; } /** * Returns all of the API projects in the workspace * * @param sourcelevel * @return all of the API projects in the workspace or <code>null</code> if * there are none. */ public static IProject[] getApiProjectsMinSourceLevel(String sourcelevel) { IProject[] allProjects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); ArrayList<IProject> temp = new ArrayList<IProject>(); IProject project = null; for (int i = 0, max = allProjects.length; i < max; i++) { project = allProjects[i]; if (project.isAccessible()) { try { if (project.hasNature(org.eclipse.pde.api.tools.internal.provisional.ApiPlugin.NATURE_ID)) { IJavaProject jp = JavaCore.create(project); String src = jp.getOption(JavaCore.COMPILER_SOURCE, true); if (src != null && src.compareTo(sourcelevel) >= 0) { temp.add(project); } } } catch (CoreException e) { } } } IProject[] projects = null; if (temp.size() != 0) { projects = new IProject[temp.size()]; temp.toArray(projects); } return projects; } /** * Copies the given file to the new file * * @param file * @param newFile * @return if the copy succeeded */ public static boolean copy(File file, File newFile) { byte[] bytes = null; BufferedInputStream inputStream = null; try { inputStream = new BufferedInputStream(new FileInputStream(file)); bytes = Util.getInputStreamAsByteArray(inputStream, -1); } catch (FileNotFoundException e) { ApiPlugin.log(e); } catch (IOException e) { ApiPlugin.log(e); } finally { if (inputStream != null) { try { inputStream.close(); } catch (IOException e) { ApiPlugin.log(e); } } } if (bytes != null) { BufferedOutputStream outputStream = null; try { outputStream = new BufferedOutputStream(new FileOutputStream(newFile)); outputStream.write(bytes); outputStream.flush(); } catch (FileNotFoundException e) { ApiPlugin.log(e); } catch (IOException e) { ApiPlugin.log(e); } finally { if (outputStream != null) { try { outputStream.close(); } catch (IOException e) { // ignore } } } return true; } return false; } /** * Creates an EE file for the given JRE and specified EE id * * @param jre * @param eeid * @return * @throws IOException */ public static File createEEFile(IVMInstall jre, String eeid) throws IOException { String string = Util.generateEEContents(jre, eeid); File eeFile = createTempFile("eed", ".ee"); //$NON-NLS-1$ //$NON-NLS-2$ FileOutputStream outputStream = null; try { outputStream = new FileOutputStream(eeFile); outputStream.write(string.getBytes(IApiCoreConstants.UTF_8)); } finally { if (outputStream != null) { outputStream.close(); } } return eeFile; } /** * Returns whether the objects are equal, accounting for either one being * <code>null</code>. * * @param o1 * @param o2 * @return whether the objects are equal, or both are <code>null</code> */ public static boolean equalsOrNull(Object o1, Object o2) { if (o1 == null) { return o2 == null; } return o1.equals(o2); } /** * Returns an execution environment description for the given VM. * * @param vm JRE to create an definition for * @return an execution environment description for the given VM * @throws IOException if unable to generate description */ public static String generateEEContents(IVMInstall vm, String eeId) throws IOException { StringBuffer buffer = new StringBuffer(); appendProperty(buffer, ExecutionEnvironmentDescription.JAVA_HOME, vm.getInstallLocation().getCanonicalPath()); StringBuffer paths = new StringBuffer(); LibraryLocation[] libraryLocations = JavaRuntime.getLibraryLocations(vm); for (int i = 0; i < libraryLocations.length; i++) { LibraryLocation lib = libraryLocations[i]; paths.append(lib.getSystemLibraryPath().toOSString()); if (i < (libraryLocations.length - 1)) { paths.append(File.pathSeparatorChar); } } appendProperty(buffer, ExecutionEnvironmentDescription.BOOT_CLASS_PATH, paths.toString()); appendProperty(buffer, ExecutionEnvironmentDescription.CLASS_LIB_LEVEL, eeId); return buffer.toString(); } /** * Returns an array of all of the files from the given root that are * accepted by the given file filter. If the file filter is null all files * within the given root are returned. * * @param root * @param fileFilter * @return the list of files from within the given root */ public static File[] getAllFiles(File root, FileFilter fileFilter) { ArrayList<File> files = new ArrayList<File>(); if (root.isDirectory()) { collectAllFiles(root, files, fileFilter); File[] result = new File[files.size()]; files.toArray(result); return result; } return null; } /** * Returns a build job that will perform a full build on the given projects. * * If <code>projects</code> are null, then an AssertionFailedException is * thrown * * @param projects the projects to build * @return the build job * @throws AssertionFailedException if the given projects are null */ public static Job getBuildJob(final IProject[] projects) { Assert.isNotNull(projects); Job buildJob = new BuildJob(UtilMessages.Util_4, projects); buildJob.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().buildRule()); buildJob.setUser(true); return buildJob; } /** * Returns a build job that will return the build that corresponds to the * given build kind on the given projects. * * If <code>projects</code> are null, then an AssertionFailedException is * thrown * * @param projects the projects to build * @param buildKind the given build kind * @return the build job * @throws AssertionFailedException if the given projects are null */ public static Job getBuildJob(final IProject[] projects, int buildKind) { Assert.isNotNull(projects); Job buildJob = new BuildJob(UtilMessages.Util_4, projects, buildKind); buildJob.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().buildRule()); buildJob.setUser(true); return buildJob; } /** * Returns a result of searching the given components for class file with * the given type name. * * @param components API components to search or <code>null</code> if none * @param typeName type to search for * @return class file or <code>null</code> if none found */ public static IApiTypeRoot getClassFile(IApiComponent[] components, String typeName) { if (components == null) { return null; } for (int i = 0, max = components.length; i < max; i++) { IApiComponent apiComponent = components[i]; if (apiComponent != null) { try { IApiTypeRoot classFile = apiComponent.findTypeRoot(typeName); if (classFile != null) { return classFile; } } catch (CoreException e) { // ignore } } } return null; } /** * Return a string that represents the element type of the given delta. * Returns {@link #UNKNOWN_ELEMENT_KIND} if the element type cannot be * determined. * * @param delta the given delta * @return a string that represents the element type of the given delta. */ public static String getDeltaElementType(IDelta delta) { return getDeltaElementType(delta.getElementType()); } /** * Returns a text representation of a marker severity level * * @param severity * @return text of a marker severity level */ public static String getSeverity(int severity) { switch (severity) { case IMarker.SEVERITY_ERROR: { return "ERROR"; //$NON-NLS-1$ } case IMarker.SEVERITY_INFO: { return "INFO"; //$NON-NLS-1$ } case IMarker.SEVERITY_WARNING: { return "WARNING"; //$NON-NLS-1$ } default: { return "UNKNOWN_SEVERITY"; //$NON-NLS-1$ } } } /** * Return an int value that represents the given element type Returns -1 if * the element type cannot be determined. * * @param elementType the given element type * @return an int that represents the given element type constant. */ public static int getDeltaElementTypeValue(String elementType) { Class<IDelta> IDeltaClass = IDelta.class; try { Field field = IDeltaClass.getField(elementType); return field.getInt(null); } catch (SecurityException e) { // ignore } catch (IllegalArgumentException e) { // ignore } catch (NoSuchFieldException e) { // ignore } catch (IllegalAccessException e) { // ignore } return -1; } /** * Return a string that represents the given element type Returns * {@link #UNKNOWN_ELEMENT_KIND} if the element type cannot be determined. * * @param elementType the given element type * @return a string that represents the given element type. */ public static String getDeltaElementType(int elementType) { switch (elementType) { case IDelta.ANNOTATION_ELEMENT_TYPE: return "ANNOTATION_ELEMENT_TYPE"; //$NON-NLS-1$ case IDelta.INTERFACE_ELEMENT_TYPE: return "INTERFACE_ELEMENT_TYPE"; //$NON-NLS-1$ case IDelta.ENUM_ELEMENT_TYPE: return "ENUM_ELEMENT_TYPE"; //$NON-NLS-1$ case IDelta.API_COMPONENT_ELEMENT_TYPE: return "API_COMPONENT_ELEMENT_TYPE"; //$NON-NLS-1$ case IDelta.API_BASELINE_ELEMENT_TYPE: return "API_BASELINE_ELEMENT_TYPE"; //$NON-NLS-1$ case IDelta.CONSTRUCTOR_ELEMENT_TYPE: return "CONSTRUCTOR_ELEMENT_TYPE"; //$NON-NLS-1$ case IDelta.METHOD_ELEMENT_TYPE: return "METHOD_ELEMENT_TYPE"; //$NON-NLS-1$ case IDelta.FIELD_ELEMENT_TYPE: return "FIELD_ELEMENT_TYPE"; //$NON-NLS-1$ case IDelta.CLASS_ELEMENT_TYPE: return "CLASS_ELEMENT_TYPE"; //$NON-NLS-1$ case IDelta.TYPE_PARAMETER_ELEMENT_TYPE: return "TYPE_PARAMETER_ELEMENT_TYPE"; //$NON-NLS-1$ default: break; } return UNKNOWN_ELEMENT_KIND; } /** * Return a string that represents the given flags Returns * {@link #UNKNOWN_FLAGS} if the flags cannot be determined. * * @param flags the given delta's flags * @return a string that represents the given flags. */ public static String getDeltaFlagsName(int flags) { switch (flags) { case IDelta.ABSTRACT_TO_NON_ABSTRACT: return "ABSTRACT_TO_NON_ABSTRACT"; //$NON-NLS-1$ case IDelta.ANNOTATION_DEFAULT_VALUE: return "ANNOTATION_DEFAULT_VALUE"; //$NON-NLS-1$ case IDelta.API_COMPONENT: return "API_COMPONENT"; //$NON-NLS-1$ case IDelta.ARRAY_TO_VARARGS: return "ARRAY_TO_VARARGS"; //$NON-NLS-1$ case IDelta.CHECKED_EXCEPTION: return "CHECKED_EXCEPTION"; //$NON-NLS-1$ case IDelta.CLASS_BOUND: return "CLASS_BOUND"; //$NON-NLS-1$ case IDelta.CLINIT: return "CLINIT"; //$NON-NLS-1$ case IDelta.CONSTRUCTOR: return "CONSTRUCTOR"; //$NON-NLS-1$ case IDelta.CONTRACTED_SUPERINTERFACES_SET: return "CONTRACTED_SUPERINTERFACES_SET"; //$NON-NLS-1$ case IDelta.DECREASE_ACCESS: return "DECREASE_ACCESS"; //$NON-NLS-1$ case IDelta.ENUM_CONSTANT: return "ENUM_CONSTANT"; //$NON-NLS-1$ case IDelta.EXECUTION_ENVIRONMENT: return "EXECUTION_ENVIRONMENT"; //$NON-NLS-1$ case IDelta.EXPANDED_SUPERINTERFACES_SET: return "EXPANDED_SUPERINTERFACES_SET"; //$NON-NLS-1$ case IDelta.FIELD: return "FIELD"; //$NON-NLS-1$ case IDelta.FIELD_MOVED_UP: return "FIELD_MOVED_UP"; //$NON-NLS-1$ case IDelta.FINAL_TO_NON_FINAL: return "FINAL_TO_NON_FINAL"; //$NON-NLS-1$ case IDelta.FINAL_TO_NON_FINAL_NON_STATIC: return "FINAL_TO_NON_FINAL_NON_STATIC"; //$NON-NLS-1$ case IDelta.FINAL_TO_NON_FINAL_STATIC_CONSTANT: return "FINAL_TO_NON_FINAL_STATIC_CONSTANT"; //$NON-NLS-1$ case IDelta.FINAL_TO_NON_FINAL_STATIC_NON_CONSTANT: return "FINAL_TO_NON_FINAL_STATIC_NON_CONSTANT"; //$NON-NLS-1$ case IDelta.INCREASE_ACCESS: return "INCREASE_ACCESS"; //$NON-NLS-1$ case IDelta.INTERFACE_BOUND: return "INTERFACE_BOUND"; //$NON-NLS-1$ case IDelta.METHOD: return "METHOD"; //$NON-NLS-1$ case IDelta.METHOD_MOVED_UP: return "METHOD_MOVED_UP"; //$NON-NLS-1$ case IDelta.METHOD_WITH_DEFAULT_VALUE: return "METHOD_WITH_DEFAULT_VALUE"; //$NON-NLS-1$ case IDelta.METHOD_WITHOUT_DEFAULT_VALUE: return "METHOD_WITHOUT_DEFAULT_VALUE"; //$NON-NLS-1$ case IDelta.NATIVE_TO_NON_NATIVE: return "NATIVE_TO_NON_NATIVE"; //$NON-NLS-1$ case IDelta.NON_ABSTRACT_TO_ABSTRACT: return "NON_ABSTRACT_TO_ABSTRACT"; //$NON-NLS-1$ case IDelta.NON_FINAL_TO_FINAL: return "NON_FINAL_TO_FINAL"; //$NON-NLS-1$ case IDelta.NON_NATIVE_TO_NATIVE: return "NON_NATIVE_TO_NATIVE"; //$NON-NLS-1$ case IDelta.NON_STATIC_TO_STATIC: return "NON_STATIC_TO_STATIC"; //$NON-NLS-1$ case IDelta.NON_SYNCHRONIZED_TO_SYNCHRONIZED: return "NON_SYNCHRONIZED_TO_SYNCHRONIZED"; //$NON-NLS-1$ case IDelta.NON_TRANSIENT_TO_TRANSIENT: return "NON_TRANSIENT_TO_TRANSIENT"; //$NON-NLS-1$ case IDelta.OVERRIDEN_METHOD: return "OVERRIDEN_METHOD"; //$NON-NLS-1$ case IDelta.STATIC_TO_NON_STATIC: return "STATIC_TO_NON_STATIC"; //$NON-NLS-1$ case IDelta.SUPERCLASS: return "SUPERCLASS"; //$NON-NLS-1$ case IDelta.SYNCHRONIZED_TO_NON_SYNCHRONIZED: return "SYNCHRONIZED_TO_NON_SYNCHRONIZED"; //$NON-NLS-1$ case IDelta.TYPE_CONVERSION: return "TYPE_CONVERSION"; //$NON-NLS-1$ case IDelta.TRANSIENT_TO_NON_TRANSIENT: return "TRANSIENT_TO_NON_TRANSIENT"; //$NON-NLS-1$ case IDelta.TYPE: return "TYPE"; //$NON-NLS-1$ case IDelta.TYPE_ARGUMENTS: return "TYPE_ARGUMENTS"; //$NON-NLS-1$ case IDelta.TYPE_MEMBER: return "TYPE_MEMBER"; //$NON-NLS-1$ case IDelta.TYPE_PARAMETER: return "TYPE_PARAMETER"; //$NON-NLS-1$ case IDelta.TYPE_PARAMETER_NAME: return "TYPE_PARAMETER_NAME"; //$NON-NLS-1$ case IDelta.TYPE_PARAMETERS: return "TYPE_PARAMETERS"; //$NON-NLS-1$ case IDelta.TYPE_VISIBILITY: return "TYPE_VISIBILITY"; //$NON-NLS-1$ case IDelta.UNCHECKED_EXCEPTION: return "UNCHECKED_EXCEPTION"; //$NON-NLS-1$ case IDelta.VALUE: return "VALUE"; //$NON-NLS-1$ case IDelta.VARARGS_TO_ARRAY: return "VARARGS_TO_ARRAY"; //$NON-NLS-1$ case IDelta.RESTRICTIONS: return "RESTRICTIONS"; //$NON-NLS-1$ case IDelta.API_TYPE: return "API_TYPE"; //$NON-NLS-1$ case IDelta.NON_VOLATILE_TO_VOLATILE: return "NON_VOLATILE_TO_VOLATILE"; //$NON-NLS-1$ case IDelta.VOLATILE_TO_NON_VOLATILE: return "VOLATILE_TO_NON_VOLATILE"; //$NON-NLS-1$ case IDelta.MINOR_VERSION: return "MINOR_VERSION"; //$NON-NLS-1$ case IDelta.MAJOR_VERSION: return "MAJOR_VERSION"; //$NON-NLS-1$ case IDelta.API_FIELD: return "API_FIELD"; //$NON-NLS-1$ case IDelta.API_METHOD: return "API_METHOD"; //$NON-NLS-1$ case IDelta.API_CONSTRUCTOR: return "API_CONSTRUCTOR"; //$NON-NLS-1$ case IDelta.API_ENUM_CONSTANT: return "API_ENUM_CONSTANT"; //$NON-NLS-1$ case IDelta.API_METHOD_WITH_DEFAULT_VALUE: return "API_METHOD_WITH_DEFAULT_VALUE"; //$NON-NLS-1$ case IDelta.API_METHOD_WITHOUT_DEFAULT_VALUE: return "API_METHOD_WITHOUT_DEFAULT_VALUE"; //$NON-NLS-1$ case IDelta.TYPE_ARGUMENT: return "TYPE_ARGUMENT"; //$NON-NLS-1$ case IDelta.SUPER_INTERFACE_WITH_METHODS: return "SUPER_INTERFACE_WITH_METHODS"; //$NON-NLS-1$ case IDelta.REEXPORTED_API_TYPE: return "REEXPORTED_API_TYPE"; //$NON-NLS-1$ case IDelta.REEXPORTED_TYPE: return "REEXPORTED_TYPE"; //$NON-NLS-1$ case IDelta.METHOD_MOVED_DOWN: return "METHOD_MOVED_DOWN"; //$NON-NLS-1$ case IDelta.DEPRECATION: return "DEPRECATION"; //$NON-NLS-1$ default: break; } return UNKNOWN_FLAGS; } /** * Return a string that represents the kind of the given delta. Returns * {@link #UNKNOWN_KIND} if the kind cannot be determined. * * @param delta the given delta * @return a string that represents the kind of the given delta. */ public static String getDeltaKindName(IDelta delta) { return getDeltaKindName(delta.getKind()); } /** * Return a string that represents the given kind. Returns * {@link #UNKNOWN_KIND} if the kind cannot be determined. * * @param delta the given kind * @return a string that represents the given kind. */ public static String getDeltaKindName(int kind) { switch (kind) { case IDelta.ADDED: return "ADDED"; //$NON-NLS-1$ case IDelta.CHANGED: return "CHANGED"; //$NON-NLS-1$ case IDelta.REMOVED: return "REMOVED"; //$NON-NLS-1$ default: break; } return UNKNOWN_KIND; } /** * Returns the preference key for the given element type, the given kind and * the given flags. * * @param elementType the given element type (retrieved using * {@link IDelta#getElementType()} * @param kind the given kind (retrieved using {@link IDelta#getKind()} * @param flags the given flags (retrieved using {@link IDelta#getFlags()} * @return the preference key for the given element type, the given kind and * the given flags. */ public static String getDeltaPrefererenceKey(int elementType, int kind, int flags) { StringBuffer buffer = new StringBuffer(Util.getDeltaElementType(elementType)); buffer.append('_').append(Util.getDeltaKindName(kind)); if (flags != -1) { buffer.append('_'); switch (flags) { case IDelta.API_FIELD: buffer.append(Util.getDeltaFlagsName(IDelta.FIELD)); break; case IDelta.API_ENUM_CONSTANT: buffer.append(Util.getDeltaFlagsName(IDelta.ENUM_CONSTANT)); break; case IDelta.API_CONSTRUCTOR: buffer.append(Util.getDeltaFlagsName(IDelta.CONSTRUCTOR)); break; case IDelta.API_METHOD: buffer.append(Util.getDeltaFlagsName(IDelta.METHOD)); break; case IDelta.API_METHOD_WITH_DEFAULT_VALUE: if (kind == IDelta.REMOVED) { buffer.append(Util.getDeltaFlagsName(IDelta.METHOD)); } else { buffer.append(Util.getDeltaFlagsName(IDelta.METHOD_WITH_DEFAULT_VALUE)); } break; case IDelta.API_METHOD_WITHOUT_DEFAULT_VALUE: if (kind == IDelta.REMOVED) { buffer.append(Util.getDeltaFlagsName(IDelta.METHOD)); } else { buffer.append(Util.getDeltaFlagsName(IDelta.METHOD_WITHOUT_DEFAULT_VALUE)); } break; case IDelta.METHOD_WITH_DEFAULT_VALUE: if (kind == IDelta.REMOVED) { buffer.append(Util.getDeltaFlagsName(IDelta.METHOD)); } else { buffer.append(Util.getDeltaFlagsName(IDelta.METHOD_WITH_DEFAULT_VALUE)); } break; case IDelta.METHOD_WITHOUT_DEFAULT_VALUE: if (kind == IDelta.REMOVED) { buffer.append(Util.getDeltaFlagsName(IDelta.METHOD)); } else { buffer.append(Util.getDeltaFlagsName(IDelta.METHOD_WITHOUT_DEFAULT_VALUE)); } break; default: buffer.append(Util.getDeltaFlagsName(flags)); } } return String.valueOf(buffer); } /** * Returns the details of the API delta as a string * * @param delta * @return the details of the delta as a string */ public static String getDetail(IDelta delta) { StringBuffer buffer = new StringBuffer(); switch (delta.getElementType()) { case IDelta.CLASS_ELEMENT_TYPE: buffer.append("class"); //$NON-NLS-1$ break; case IDelta.ANNOTATION_ELEMENT_TYPE: buffer.append("annotation"); //$NON-NLS-1$ break; case IDelta.INTERFACE_ELEMENT_TYPE: buffer.append("interface"); //$NON-NLS-1$ break; case IDelta.API_COMPONENT_ELEMENT_TYPE: buffer.append("api component"); //$NON-NLS-1$ break; case IDelta.API_BASELINE_ELEMENT_TYPE: buffer.append("api baseline"); //$NON-NLS-1$ break; case IDelta.METHOD_ELEMENT_TYPE: buffer.append("method"); //$NON-NLS-1$ break; case IDelta.CONSTRUCTOR_ELEMENT_TYPE: buffer.append("constructor"); //$NON-NLS-1$ break; case IDelta.ENUM_ELEMENT_TYPE: buffer.append("enum"); //$NON-NLS-1$ break; case IDelta.FIELD_ELEMENT_TYPE: buffer.append("field"); //$NON-NLS-1$ break; default: break; } buffer.append(' '); switch (delta.getKind()) { case IDelta.ADDED: buffer.append("added"); //$NON-NLS-1$ break; case IDelta.REMOVED: buffer.append("removed"); //$NON-NLS-1$ break; case IDelta.CHANGED: buffer.append("changed"); //$NON-NLS-1$ break; default: buffer.append("unknown kind"); //$NON-NLS-1$ break; } buffer.append(' ').append(getDeltaFlagsName(delta.getFlags())).append(' ').append(delta.getTypeName()) .append("#").append(delta.getKey()); //$NON-NLS-1$ return String.valueOf(buffer); } /** * Returns the {@link IDocument} for the specified {@link ICompilationUnit} * * @param cu * @return the {@link IDocument} for the specified {@link ICompilationUnit} * @throws CoreException */ public static IDocument getDocument(ICompilationUnit cu) throws CoreException { if (cu.getOwner() == null) { IFile file = (IFile) cu.getResource(); if (file.exists()) { ITextFileBufferManager bufferManager = FileBuffers.getTextFileBufferManager(); IPath path = cu.getPath(); bufferManager.connect(path, LocationKind.IFILE, new NullProgressMonitor()); try { return bufferManager.getTextFileBuffer(path, LocationKind.IFILE).getDocument(); } finally { bufferManager.disconnect(path, LocationKind.IFILE, null); } } } return new org.eclipse.jface.text.Document(cu.getSource()); } /** * Returns the OSGi profile properties corresponding to the given execution * environment id, or <code>null</code> if none. * * @param eeId OSGi profile identifier * * @return the corresponding properties or <code>null</code> if none */ public static Properties getEEProfile(String eeId) { String profileName = eeId + ".profile"; //$NON-NLS-1$ InputStream stream = Util.class.getResourceAsStream("profiles/" + profileName); //$NON-NLS-1$ if (stream != null) { try { Properties profile = new Properties(); profile.load(stream); return profile; } catch (IOException e) { ApiPlugin.log(e); } finally { try { stream.close(); } catch (IOException e) { ApiPlugin.log(e); } } } return null; } /** * Returns the number of fragments for the given version value, -1 if the * format is unknown. The version is formed like: [optional plug-in name] * major.minor.micro.qualifier. * * @param version the given version value * @return the number of fragments for the given version value or -1 if the * format is unknown * @throws IllegalArgumentException if version is null */ public static final int getFragmentNumber(String version) { if (version == null) { throw new IllegalArgumentException("The given version should not be null"); //$NON-NLS-1$ } int index = version.indexOf(' '); char[] charArray = version.toCharArray(); int length = charArray.length; if (index + 1 >= length) { return -1; } int counter = 1; for (int i = index + 1; i < length; i++) { switch (charArray[i]) { case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': continue; case '.': counter++; break; default: return -1; } } return counter; } public static IMember getIMember(IDelta delta, IJavaProject javaProject) { String typeName = delta.getTypeName(); if (typeName == null) { return null; } IType type = null; try { type = javaProject.findType(typeName.replace('$', '.')); } catch (JavaModelException e) { // ignore } if (type == null) { return null; } String key = delta.getKey(); switch (delta.getElementType()) { case IDelta.FIELD_ELEMENT_TYPE: { IField field = type.getField(key); if (field.exists()) { return field; } } break; case IDelta.CLASS_ELEMENT_TYPE: case IDelta.ANNOTATION_ELEMENT_TYPE: case IDelta.INTERFACE_ELEMENT_TYPE: case IDelta.ENUM_ELEMENT_TYPE: // we report the marker on the type switch (delta.getKind()) { case IDelta.ADDED: switch (delta.getFlags()) { case IDelta.FIELD: case IDelta.ENUM_CONSTANT: IField field = type.getField(key); if (field.exists()) { return field; } break; case IDelta.METHOD_WITH_DEFAULT_VALUE: case IDelta.METHOD_WITHOUT_DEFAULT_VALUE: case IDelta.METHOD: case IDelta.CONSTRUCTOR: return getMethod(type, key); case IDelta.TYPE_MEMBER: IType type2 = type.getType(key); if (type2.exists()) { return type2; } break; default: break; } break; case IDelta.REMOVED: switch (delta.getFlags()) { case IDelta.API_FIELD: case IDelta.API_ENUM_CONSTANT: IField field = type.getField(key); if (field.exists()) { return field; } break; case IDelta.API_METHOD_WITH_DEFAULT_VALUE: case IDelta.API_METHOD_WITHOUT_DEFAULT_VALUE: case IDelta.API_METHOD: case IDelta.API_CONSTRUCTOR: return getMethod(type, key); default: break; } break; default: break; } return type; case IDelta.METHOD_ELEMENT_TYPE: case IDelta.CONSTRUCTOR_ELEMENT_TYPE: { return getMethod(type, key); } case IDelta.API_COMPONENT_ELEMENT_TYPE: return type; default: break; } return null; } /** * Updates a given progress monitor the given amount of work. Throws an * {@link OperationCanceledException} if the monitor has been canceled. * * @param monitor * @param work * @throws OperationCanceledException */ public static void updateMonitor(IProgressMonitor monitor, int work) throws OperationCanceledException { if (monitor == null) { return; } if (monitor.isCanceled()) { throw new OperationCanceledException(); } monitor.worked(work); } /** * Updates the given monitor 0 work ticks. This method is used to poll for * cancellation without advancing the work done. * * @param monitor * @throws OperationCanceledException */ public static void updateMonitor(IProgressMonitor monitor) throws OperationCanceledException { updateMonitor(monitor, 0); } private static IMember getMethod(IType type, String key) { boolean isGeneric = false; int indexOfTypeVariable = key.indexOf('<'); int index = 0; if (indexOfTypeVariable == -1) { int indexOfParen = key.indexOf('('); if (indexOfParen == -1) { return null; } index = indexOfParen; } else { int indexOfParen = key.indexOf('('); if (indexOfParen == -1) { return null; } if (indexOfParen < indexOfTypeVariable) { index = indexOfParen; } else { index = indexOfTypeVariable; isGeneric = true; } } String selector = key.substring(0, index); String descriptor = key.substring(index, key.length()); IMethod method = null; String signature = descriptor.replace('/', '.'); String[] parameterTypes = null; if (isGeneric) { // remove all type variables first signature = signature.substring(signature.indexOf('(')); parameterTypes = Signature.getParameterTypes(signature); } else { parameterTypes = Signature.getParameterTypes(signature); } try { method = type.getMethod(selector, parameterTypes); } catch (IllegalArgumentException e) { ApiPlugin.log(e); } if (method == null) { return null; } if (method.exists()) { return method; } else { // if the method is not null and it doesn't exist, it might be the // default constructor if (selector.equals(type.getElementName()) && parameterTypes.length == 0) { return null; } // try to check by selector IMethod[] methods = null; try { methods = type.getMethods(); } catch (JavaModelException e) { ApiPlugin.log(e); // do not default to the enclosing type - see bug 224713 ApiPlugin.log(new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, NLS.bind(UtilMessages.Util_6, new String[] { selector, descriptor }))); return null; } List<IMethod> list = new ArrayList<IMethod>(); for (int i = 0, max = methods.length; i < max; i++) { IMethod method2 = methods[i]; if (selector.equals(method2.getElementName())) { list.add(method2); } } switch (list.size()) { case 0: // do not default to the enclosing type - see bug 224713 ApiPlugin.log(new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, NLS.bind(UtilMessages.Util_6, new String[] { selector, descriptor }))); return null; case 1: return list.get(0); default: // need to find a matching parameters for (Iterator<IMethod> iterator = list.iterator(); iterator.hasNext();) { IMethod method2 = iterator.next(); try { if (Signatures.matchesSignatures(method2.getSignature(), signature)) { return method2; } } catch (JavaModelException e) { // ignore } } } } // do not default to the enclosing type - see bug 224713 ApiPlugin.log(new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, NLS.bind(UtilMessages.Util_6, new String[] { selector, descriptor }))); return null; } /** * Returns the given input stream as a byte array * * @param stream the stream to get as a byte array * @param length the length to read from the stream or -1 for unknown * @return the given input stream as a byte array * @throws IOException */ public static byte[] getInputStreamAsByteArray(InputStream stream, int length) throws IOException { byte[] contents; if (length == -1) { contents = new byte[0]; int contentsLength = 0; int amountRead = -1; do { // read at least 8K int amountRequested = Math.max(stream.available(), DEFAULT_READING_SIZE); // resize contents if needed if (contentsLength + amountRequested > contents.length) { System.arraycopy(contents, 0, contents = new byte[contentsLength + amountRequested], 0, contentsLength); } // read as many bytes as possible amountRead = stream.read(contents, contentsLength, amountRequested); if (amountRead > 0) { // remember length of contents contentsLength += amountRead; } } while (amountRead != -1); // resize contents if necessary if (contentsLength < contents.length) { System.arraycopy(contents, 0, contents = new byte[contentsLength], 0, contentsLength); } } else { contents = new byte[length]; int len = 0; int readSize = 0; while ((readSize != -1) && (len != length)) { // See PR 1FMS89U // We record first the read size. In this case length is the // actual // read size. len += readSize; readSize = stream.read(contents, len, length - len); } } return contents; } /** * Returns the given input stream's contents as a character array. If a * length is specified (i.e. if length != -1), this represents the number of * bytes in the stream. Note the specified stream is not closed in this * method * * @param stream the stream to get convert to the char array * @param length the length of the input stream, or -1 if unknown * @param encoding the encoding to use when reading the stream * @return the given input stream's contents as a character array. * @throws IOException if a problem occurred reading the stream. */ public static char[] getInputStreamAsCharArray(InputStream stream, int length, String encoding) throws IOException { Charset charset = null; try { charset = Charset.forName(encoding); } catch (IllegalCharsetNameException e) { System.err.println("Illegal charset name : " + encoding); //$NON-NLS-1$ return null; } catch (UnsupportedCharsetException e) { System.err.println("Unsupported charset : " + encoding); //$NON-NLS-1$ return null; } CharsetDecoder charsetDecoder = charset.newDecoder(); charsetDecoder.onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE); byte[] contents = getInputStreamAsByteArray(stream, length); ByteBuffer byteBuffer = ByteBuffer.allocate(contents.length); byteBuffer.put(contents); byteBuffer.flip(); CharBuffer charBuffer = charsetDecoder.decode(byteBuffer); charBuffer.compact(); // ensure pay-load starting at 0 char[] array = charBuffer.array(); int lengthToBe = charBuffer.position(); if (array.length > lengthToBe) { System.arraycopy(array, 0, (array = new char[lengthToBe]), 0, lengthToBe); } return array; } /** * Tries to find the 'MANIFEST.MF' file with in the given project in the * 'META-INF folder'. * * @param currentProject * @return a handle to the manifest file or <code>null</code> if not found */ public static IResource getManifestFile(IProject currentProject) { return currentProject.findMember("META-INF/MANIFEST.MF"); //$NON-NLS-1$ } /** * Returns if the given {@link IMarker} is representing an * {@link org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem} * or not * * @param marker the marker to check * @return true if the marker is for an * {@link org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem} * false otherwise * @throws CoreException */ public static boolean isApiProblemMarker(IMarker marker) { return marker.getAttribute(IApiMarkerConstants.API_MARKER_ATTR_ID, -1) > 0; } /** * Returns a reference type for the given fully qualified type name. * * @param fullyQualifiedName type name * @return reference type */ public static IReferenceTypeDescriptor getType(String fullyQualifiedName) { int index = fullyQualifiedName.lastIndexOf('.'); String pkg = index == -1 ? DEFAULT_PACKAGE_NAME : fullyQualifiedName.substring(0, index); String type = index == -1 ? fullyQualifiedName : fullyQualifiedName.substring(index + 1); return Factory.packageDescriptor(pkg).getType(type); } /** * Returns if the given project is API enabled * * @param project the given project * @return true if the project is API enabled, false otherwise */ public static boolean isApiProject(IProject project) { try { return project.hasNature(ApiPlugin.NATURE_ID); } catch (CoreException e) { return false; } } /** * Returns if the given project is a java project * * @param project the given project * @return <code>true</code> if the project is a java project, * <code>false</code> otherwise */ public static boolean isJavaProject(IProject project) { try { return project.hasNature(JavaCore.NATURE_ID); } catch (CoreException e) { return false; } } /** * Returns if the given project is API enabled * * @param project the given project * @return <code>true</code> if the project is API enabled, * <code>false</code> otherwise */ public static boolean isApiProject(IJavaProject project) { if (project != null) { return isApiProject(project.getProject()); } return false; } /** * Returns if the given {@link IApiComponent} is a valid * {@link IApiComponent} * * @param apiComponent the given component * @return true if the given {@link IApiComponent} is valid, false otherwise */ public static boolean isApiToolsComponent(IApiComponent apiComponent) { File file = new File(apiComponent.getLocation()); if (file.exists()) { if (file.isDirectory()) { // directory binary bundle File apiDescription = new File(file, IApiCoreConstants.API_DESCRIPTION_XML_NAME); return apiDescription.exists(); } ZipFile zipFile = null; try { zipFile = new ZipFile(file); return zipFile.getEntry(IApiCoreConstants.API_DESCRIPTION_XML_NAME) != null; } catch (ZipException e) { // ignore } catch (IOException e) { // ignore } finally { try { if (zipFile != null) { zipFile.close(); } } catch (IOException e) { // ignore } } } return false; } /** * Returns if the specified file name is an archive name. A name is * considered to be an archive name if it ends with either '.zip' or '.jar' * * @param fileName * @return true if the file name is an archive name false otherwise */ public static boolean isArchive(String fileName) { return isZipJarFile(fileName) || isTGZFile(fileName); } /** * Returns if the given file name represents a 'standard' archive, where the * name has an extension of *.zip or *.jar * * @param fileName * @return true if the given file name is that of a 'standard' archive, * false otherwise */ public static boolean isZipJarFile(String fileName) { String normalizedFileName = fileName.toLowerCase(); return normalizedFileName.endsWith(DOT_ZIP) || normalizedFileName.endsWith(DOT_JAR); } /** * Returns if the given file name represents a G-zip file name, where the * name has an extension of *.tar.gz or *.tgz * * @param fileName * @return true if the given file name is that of a G-zip archive, false * otherwise */ public static boolean isTGZFile(String fileName) { String normalizedFileName = fileName.toLowerCase(); return normalizedFileName.endsWith(DOT_TAR_GZ) || normalizedFileName.endsWith(DOT_TGZ); } /** * Returns if the flags are for a class * * @param accessFlags the given access flags * @return */ public static boolean isClass(int accessFlags) { return (accessFlags & (Opcodes.ACC_ENUM | Opcodes.ACC_ANNOTATION | Opcodes.ACC_INTERFACE)) == 0; } /** * Returns if the specified file name is for a class file. A name is * considered to be a class file if it ends in '.class' * * @param fileName * @return true if the name is for a class file false otherwise */ public static boolean isClassFile(String fileName) { return fileName.toLowerCase().endsWith(DOT_CLASS_SUFFIX); } public static boolean isDefault(int accessFlags) { // none of the private, protected or public bit is set return (accessFlags & (Opcodes.ACC_PRIVATE | Opcodes.ACC_PROTECTED | Opcodes.ACC_PUBLIC)) == 0; } public static final boolean isDifferentVersion(String versionToBeChecked, String referenceVersion) { SinceTagVersion sinceTagVersion1 = null; SinceTagVersion sinceTagVersion2 = null; try { sinceTagVersion1 = new SinceTagVersion(versionToBeChecked); sinceTagVersion2 = new SinceTagVersion(referenceVersion); } catch (IllegalArgumentException e) { // We cannot compare the two versions as their format is unknown // TODO (olivier) should we report these as malformed tags? return false; } Version version1 = sinceTagVersion1.getVersion(); Version version2 = sinceTagVersion2.getVersion(); if (version1.getMajor() != version2.getMajor()) { return true; } if (version1.getMinor() != version2.getMinor()) { return true; } if (version1.getMicro() != version2.getMicro()) { return true; } return false; } /** * Returns if the specified file name is for a java source file. A name is * considered to be a java source file if it ends in '.java' * * @param fileName * @return true if the name is for a java source file, false otherwise */ public static boolean isJavaFileName(String fileName) { return fileName.toLowerCase().endsWith(DOT_JAVA_SUFFIX); } /** * Returns if the given name is {@link java.lang.Object} * * @param name * @return true if the name is java.lang.Object, false otherwise */ public static boolean isJavaLangObject(String name) { return name != null && name.equals(JAVA_LANG_OBJECT); } /** * Return if the name is {@link java.lang.RuntimeException} * * @param name * @return true if the name is java.lang.RuntimeException, false otherwise */ public static boolean isJavaLangRuntimeException(String name) { return name != null && name.equals(JAVA_LANG_RUNTIMEEXCEPTION); } public static boolean isVisible(int modifiers) { return Flags.isProtected(modifiers) || Flags.isPublic(modifiers); } public static boolean isBinaryProject(IProject project) { return org.eclipse.pde.internal.core.WorkspaceModelManager.isBinaryProject(project); } /** * Returns a new XML document. * * @return document * @throws CoreException if unable to create a new document */ public static Document newDocument() throws CoreException { DocumentBuilderFactory dfactory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = null; try { docBuilder = dfactory.newDocumentBuilder(); } catch (ParserConfigurationException e) { abort("Unable to create new XML document.", e); //$NON-NLS-1$ } Document doc = docBuilder.newDocument(); return doc; } /** * Parses the given string representing an XML document, returning its root * element. * * @param document XML document as a string * @return the document's root element * @throws CoreException if unable to parse the document */ public static Element parseDocument(String document) throws CoreException { Element root = null; InputStream stream = null; try { DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); parser.setErrorHandler(new DefaultHandler()); stream = new ByteArrayInputStream(document.getBytes(IApiCoreConstants.UTF_8)); root = parser.parse(stream).getDocumentElement(); } catch (ParserConfigurationException e) { abort("Unable to parse XML document.", e); //$NON-NLS-1$ } catch (FactoryConfigurationError e) { abort("Unable to parse XML document.", e); //$NON-NLS-1$ } catch (SAXException e) { abort("Unable to parse XML document.", e); //$NON-NLS-1$ } catch (IOException e) { abort("Unable to parse XML document.", e); //$NON-NLS-1$ } finally { try { if (stream != null) { stream.close(); } } catch (IOException e) { abort("Unable to parse XML document.", e); //$NON-NLS-1$ } } return root; } /** * Save the given contents into the given file. The file parent folder must * exist. * * @param file the given file target * @param contents the given contents * @throws IOException if an IOException occurs while saving the file */ public static void saveFile(File file, String contents) throws IOException { BufferedWriter writer = null; try { writer = new BufferedWriter(new FileWriter(file)); writer.write(contents); writer.flush(); } finally { if (writer != null) { try { writer.close(); } catch (IOException e) { // ignore } } } } /** * Returns the contents of the given file as a string, or <code>null</code> * * @param file the file to get the contents for * @return the contents of the file as a {@link String} or <code>null</code> */ public static String getFileContentAsString(File file) { String contents = null; FileInputStream stream = null; try { stream = new FileInputStream(file); char[] array = getInputStreamAsCharArray(stream, -1, IApiCoreConstants.UTF_8); contents = new String(array); } catch (IOException ioe) { ApiPlugin.log(ioe); } finally { if (stream != null) { try { stream.close(); } catch (IOException e) { // ignore } } } return contents; } /** * Returns the given string as an {@link InputStream}. It is up to the * caller to close the new stream. * * @param string the string to convert * @return the {@link InputStream} for the given string */ public static InputStream getInputStreamFromString(String string) { try { return new ByteArrayInputStream(string.getBytes(IApiCoreConstants.UTF_8)); } catch (UnsupportedEncodingException uee) { ApiPlugin.log(uee); } return null; } /** * Serializes the given XML document into a UTF-8 string. * * @param document XML document to serialize * @return a string representing the given document * @throws CoreException if unable to serialize the document */ public static String serializeDocument(Document document) throws CoreException { try { ByteArrayOutputStream s = new ByteArrayOutputStream(); TransformerFactory factory = TransformerFactory.newInstance(); Transformer transformer = factory.newTransformer(); transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4"); //$NON-NLS-1$ //$NON-NLS-2$ DOMSource source = new DOMSource(document); StreamResult outputTarget = new StreamResult(s); transformer.transform(source, outputTarget); return s.toString(IApiCoreConstants.UTF_8); } catch (TransformerException e) { abort("Unable to serialize XML document.", e); //$NON-NLS-1$ } catch (IOException e) { abort("Unable to serialize XML document.", e); //$NON-NLS-1$ } return null; } /** * Unzip the contents of the given zip in the given directory (create it if * it doesn't exist) */ public static void unzip(String zipPath, String destDirPath) throws IOException { InputStream zipIn = new FileInputStream(zipPath); byte[] buf = new byte[8192]; File destDir = new File(destDirPath); ZipInputStream zis = new ZipInputStream(new BufferedInputStream(zipIn)); BufferedOutputStream outputStream = null; try { ZipEntry zEntry; while ((zEntry = zis.getNextEntry()) != null) { // if it is empty directory, create it if (zEntry.isDirectory()) { new File(destDir, zEntry.getName()).mkdirs(); continue; } // if it is a file, extract it String filePath = zEntry.getName(); int lastSeparator = filePath.lastIndexOf("/"); //$NON-NLS-1$ String fileDir = ""; //$NON-NLS-1$ if (lastSeparator >= 0) { fileDir = filePath.substring(0, lastSeparator); } // create directory for a file new File(destDir, fileDir).mkdirs(); // write file File outFile = new File(destDir, filePath); outputStream = new BufferedOutputStream(new FileOutputStream(outFile)); int n = 0; while ((n = zis.read(buf)) >= 0) { outputStream.write(buf, 0, n); } outputStream.close(); } } catch (IOException ioe) { if (outputStream != null) { try { outputStream.close(); } catch (IOException ioe2) { } } } finally { try { zipIn.close(); zis.close(); } catch (IOException ioe) { } } } /** * Unzip the contents of the given zip in the given directory (create it if * it doesn't exist) */ public static void guntar(String zipPath, String destDirPath) throws TarException, IOException { TarFile tarFile = new TarFile(zipPath); Enumeration<?> entries = tarFile.entries(); byte[] buf = new byte[8192]; for (; entries.hasMoreElements();) { TarEntry zEntry; while ((zEntry = (TarEntry) entries.nextElement()) != null) { // if it is empty directory, create it if (zEntry.getFileType() == TarEntry.DIRECTORY) { new File(destDirPath, zEntry.getName()).mkdirs(); continue; } // if it is a file, extract it String filePath = zEntry.getName(); int lastSeparator = filePath.lastIndexOf("/"); //$NON-NLS-1$ String fileDir = ""; //$NON-NLS-1$ if (lastSeparator >= 0) { fileDir = filePath.substring(0, lastSeparator); } // create directory for a file new File(destDirPath, fileDir).mkdirs(); // write file File outFile = new File(destDirPath, filePath); BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(outFile)); int n = 0; InputStream inputStream = tarFile.getInputStream(zEntry); BufferedInputStream stream = new BufferedInputStream(inputStream); while ((n = stream.read(buf)) >= 0) { outputStream.write(buf, 0, n); } outputStream.close(); stream.close(); } } } /** * Gets the .ee file supplied to run tests based on system property. * * @return */ public static File getEEDescriptionFile() { // generate a fake 1.6 ee file File fakeEEFile = null; PrintWriter writer = null; try { fakeEEFile = createTempFile("eefile", ".ee"); //$NON-NLS-1$ //$NON-NLS-2$ writer = new PrintWriter(new BufferedWriter(new FileWriter(fakeEEFile))); writer.print("-Djava.home="); //$NON-NLS-1$ writer.println(System.getProperty("java.home")); //$NON-NLS-1$ writer.print("-Dee.bootclasspath="); //$NON-NLS-1$ writer.println(getJavaClassLibsAsString()); writer.println("-Dee.language.level=1.6"); //$NON-NLS-1$ writer.println("-Dee.class.library.level=JavaSE-1.6"); //$NON-NLS-1$ writer.flush(); } catch (IOException e) { // ignore } finally { if (writer != null) { writer.close(); } } return fakeEEFile; } /** * Creates a new file in the users' <code>temp</code> directory * * @param prefix * @param suffix * @return a new temp file * @throws IOException * @since 1.1 */ public static File createTempFile(String prefix, String suffix) throws IOException { File file = File.createTempFile(prefix, suffix); file.deleteOnExit(); FileManager.getManager().recordTempFileRoot(file.getCanonicalPath()); return file; } /** * @return a string representation of all of the libraries from the bootpath * of the current default system VM. */ public static String getJavaClassLibsAsString() { String[] libs = Util.getJavaClassLibs(); StringBuffer buffer = new StringBuffer(); for (int i = 0, max = libs.length; i < max; i++) { if (i > 0) { buffer.append(File.pathSeparatorChar); } buffer.append(libs[i]); } return String.valueOf(buffer); } /** * @return an array of the library names from the bootpath of the current * default system VM */ public static String[] getJavaClassLibs() { // check bootclasspath properties for Sun, JRockit and Harmony VMs String bootclasspathProperty = System.getProperty("sun.boot.class.path"); //$NON-NLS-1$ if ((bootclasspathProperty == null) || (bootclasspathProperty.length() == 0)) { // IBM J9 VMs bootclasspathProperty = System.getProperty("vm.boot.class.path"); //$NON-NLS-1$ if ((bootclasspathProperty == null) || (bootclasspathProperty.length() == 0)) { // Harmony using IBM VME bootclasspathProperty = System.getProperty("org.apache.harmony.boot.class.path"); //$NON-NLS-1$ } } String[] jars = null; if ((bootclasspathProperty != null) && (bootclasspathProperty.length() != 0)) { StringTokenizer tokenizer = new StringTokenizer(bootclasspathProperty, File.pathSeparator); final int size = tokenizer.countTokens(); jars = new String[size]; int i = 0; while (tokenizer.hasMoreTokens()) { final String fileName = toNativePath(tokenizer.nextToken()); if (new File(fileName).exists()) { jars[i] = fileName; i++; } } if (size != i) { // resize System.arraycopy(jars, 0, (jars = new String[i]), 0, i); } } else { String jreDir = System.getProperty("java.home"); //$NON-NLS-1$ final String osName = System.getProperty("os.name"); //$NON-NLS-1$ if (jreDir == null) { return new String[] {}; } if (osName.startsWith("Mac")) { //$NON-NLS-1$ return new String[] { toNativePath(jreDir + "/../Classes/classes.jar") //$NON-NLS-1$ }; } final String vmName = System.getProperty("java.vm.name"); //$NON-NLS-1$ if ("J9".equals(vmName)) { //$NON-NLS-1$ return new String[] { toNativePath(jreDir + "/lib/jclMax/classes.zip") //$NON-NLS-1$ }; } String[] jarsNames = null; ArrayList<String> paths = new ArrayList<String>(); if ("DRLVM".equals(vmName)) { //$NON-NLS-1$ FilenameFilter jarFilter = new FilenameFilter() { @Override public boolean accept(File dir, String name) { return name.endsWith(DOT_JAR) & !name.endsWith("-src.jar"); //$NON-NLS-1$ } }; jarsNames = new File(jreDir + "/lib/boot/").list(jarFilter); //$NON-NLS-1$ addJarEntries(jreDir + "/lib/boot/", jarsNames, paths); //$NON-NLS-1$ } else { jarsNames = new String[] { "/lib/vm.jar", //$NON-NLS-1$ "/lib/rt.jar", //$NON-NLS-1$ "/lib/core.jar", //$NON-NLS-1$ "/lib/security.jar", //$NON-NLS-1$ "/lib/xml.jar", //$NON-NLS-1$ "/lib/graphics.jar" //$NON-NLS-1$ }; addJarEntries(jreDir, jarsNames, paths); } jars = new String[paths.size()]; paths.toArray(jars); } return jars; } /** * Makes the given path a path using native path separators as returned by * File.getPath() and trimming any extra slash. */ public static String toNativePath(String path) { String nativePath = path.replace('\\', File.separatorChar).replace('/', File.separatorChar); return nativePath.endsWith("/") || nativePath.endsWith("\\") ? //$NON-NLS-1$ //$NON-NLS-2$ nativePath.substring(0, nativePath.length() - 1) : nativePath; } private static void addJarEntries(String jreDir, String[] jarNames, ArrayList<String> paths) { for (int i = 0, max = jarNames.length; i < max; i++) { final String currentName = jreDir + jarNames[i]; File f = new File(currentName); if (f.exists()) { paths.add(toNativePath(currentName)); } } } /** * Delete a file or directory and insure that the file is no longer present * on file system. In case of directory, delete all the hierarchy * underneath. * * @param file The file or directory to delete * @return true iff the file was really delete, false otherwise */ public static boolean delete(File file) { if (!file.exists()) { return true; } // flush all directory content if (file.isDirectory()) { flushDirectoryContent(file); } // remove file file.delete(); if (isFileDeleted(file)) { return true; } return waitUntilFileDeleted(file); } public static void flushDirectoryContent(File dir) { File[] files = dir.listFiles(); if (files == null) { return; } for (int i = 0, max = files.length; i < max; i++) { delete(files[i]); } } /** * Wait until the file is _really_ deleted on file system. * * @param file Deleted file * @return true if the file was finally deleted, false otherwise */ private static boolean waitUntilFileDeleted(File file) { int count = 0; int delay = 10; // ms int maxRetry = DELETE_MAX_WAIT / delay; int time = 0; while (count < maxRetry) { try { count++; Thread.sleep(delay); time += delay; if (time > DELETE_MAX_TIME) { DELETE_MAX_TIME = time; } if (DELETE_DEBUG) { System.out.print('.'); } if (file.exists()) { if (file.delete()) { // SUCCESS return true; } } if (isFileDeleted(file)) { // SUCCESS return true; } // Increment waiting delay exponentially if (count >= 10 && delay <= 100) { count = 1; delay *= 10; maxRetry = DELETE_MAX_WAIT / delay; if ((DELETE_MAX_WAIT % delay) != 0) { maxRetry++; } } } catch (InterruptedException ie) { break; // end loop } } System.err.println(); System.err.println(" !!! ERROR: " + file + " was never deleted even after having waited " //$NON-NLS-1$//$NON-NLS-2$ + DELETE_MAX_TIME + "ms!!!"); //$NON-NLS-1$ System.err.println(); return false; } /** * Returns whether a file is really deleted or not. Does not only rely on * {@link File#exists()} method but also look if it's not in its parent * children {@link #getParentChildFile(File)}. * * @param file The file to test if deleted * @return true if the file does not exist and was not found in its parent * children. */ public static boolean isFileDeleted(File file) { return !file.exists() && getParentChildFile(file) == null; } /** * Returns the parent's child file matching the given file or null if not * found. * * @param file The searched file in parent * @return The parent's child matching the given file or null if not found. */ private static File getParentChildFile(File file) { File parent = file.getParentFile(); if (parent == null || !parent.exists()) { return null; } File[] files = parent.listFiles(); if (files == null) { return null; } int length = files == null ? 0 : files.length; if (length > 0) { for (int i = 0; i < length; i++) { if (files[i] == file) { return files[i]; } else if (files[i].equals(file)) { return files[i]; } else if (files[i].getPath().equals(file.getPath())) { return files[i]; } } } return null; } /** * Turns the given array of strings into a {@link HashSet} * * @param values * @return a new {@link HashSet} of the string array */ public static Set<String> convertAsSet(String[] values) { Set<String> set = new HashSet<String>(); if (values != null && values.length != 0) { for (int i = 0, max = values.length; i < max; i++) { set.add(values[i]); } } return set; } /** * Returns an identifier for the given API component including its version * identifier (component id + '(' + major + . + minor + . + micro + ')' ) * * @param component API component * @return API component + version identifier */ public static String getDeltaComponentVersionsId(IApiComponent component) { StringBuffer buffer = new StringBuffer(component.getSymbolicName()); String version = component.getVersion(); // remove the qualifier part if (version != null) { buffer.append(Util.VERSION_SEPARATOR); try { Version version2 = new Version(version); buffer.append(version2.getMajor()).append('.').append(version2.getMinor()).append('.') .append(version2.getMicro()); } catch (IllegalArgumentException e) { // the version string doesn't follow the Eclipse pattern // we keep the version as is buffer.append(version); } buffer.append(')'); } return String.valueOf(buffer); } /** * Returns an identifier for the given API component including its version * identifier (component id + _ + major + _ + minor + _ + micro) * * @param component API component * @return API component + version identifier */ public static String getComponentVersionsId(IApiComponent component) { StringBuffer buffer = new StringBuffer(component.getSymbolicName()); String version = component.getVersion(); // remove the qualifier part if (version != null) { buffer.append('_'); try { Version version2 = new Version(version); buffer.append(version2.getMajor()).append('.').append(version2.getMinor()).append('.') .append(version2.getMicro()); } catch (IllegalArgumentException e) { // the version string doesn't follow the Eclipse pattern // we keep the version as is buffer.append(version); } } return String.valueOf(buffer); } public static String getDescriptorName(IApiType descriptor) { String typeName = descriptor.getName(); int index = typeName.lastIndexOf('$'); if (index != -1) { return typeName.replace('$', '.'); } return typeName; } public static String getDeltaArgumentString(IDelta delta) { String[] arguments = delta.getArguments(); switch (delta.getFlags()) { case IDelta.TYPE_MEMBER: case IDelta.TYPE: return arguments[0]; case IDelta.METHOD: case IDelta.CONSTRUCTOR: case IDelta.ENUM_CONSTANT: case IDelta.METHOD_WITH_DEFAULT_VALUE: case IDelta.METHOD_WITHOUT_DEFAULT_VALUE: case IDelta.FIELD: return arguments[1]; case IDelta.INCREASE_ACCESS: switch (delta.getElementType()) { case IDelta.FIELD_ELEMENT_TYPE: case IDelta.METHOD_ELEMENT_TYPE: case IDelta.CONSTRUCTOR_ELEMENT_TYPE: return arguments[1]; default: return arguments[0]; } default: break; } return EMPTY_STRING; } /** * Returns the string representation of the {@link IApiElement} type * * @param type * @return the string of the {@link IApiElement} type */ public static String getApiElementType(int type) { switch (type) { case IApiElement.API_TYPE_CONTAINER: return "API_TYPE_CONTAINER"; //$NON-NLS-1$ case IApiElement.API_TYPE_ROOT: return "API_TYPE_ROOT"; //$NON-NLS-1$ case IApiElement.BASELINE: return "BASELINE"; //$NON-NLS-1$ case IApiElement.COMPONENT: return "COMPONENT"; //$NON-NLS-1$ case IApiElement.FIELD: return "FIELD"; //$NON-NLS-1$ case IApiElement.METHOD: return "METHOD"; //$NON-NLS-1$ case IApiElement.TYPE: return "TYPE"; //$NON-NLS-1$ default: return "UNKNOWN"; //$NON-NLS-1$ } } public static boolean isConstructor(String referenceMemberName) { return Arrays.equals(ConstantPool.Init, referenceMemberName.toCharArray()); } public static boolean isManifest(IPath path) { return MANIFEST_PROJECT_RELATIVE_PATH.equals(path); } public static void touchCorrespondingResource(IProject project, IResource resource, String typeName) { if (typeName != null && typeName != FilterStore.GLOBAL) { if (Util.isManifest(resource.getProjectRelativePath())) { try { IJavaProject javaProject = JavaCore.create(project); IType findType = javaProject.findType(typeName); if (findType != null) { ICompilationUnit compilationUnit = findType.getCompilationUnit(); if (compilationUnit != null) { IResource cuResource = compilationUnit.getResource(); if (cuResource != null) { cuResource.touch(null); } } } } catch (JavaModelException e) { ApiPlugin.log(e); } catch (CoreException e) { ApiPlugin.log(e); } } else { try { resource.touch(null); } catch (CoreException e) { ApiPlugin.log(e); } } } } public static String getTypeNameFromMarker(IMarker marker) { return marker.getAttribute(IApiMarkerConstants.MARKER_ATTR_PROBLEM_TYPE_NAME, null); } public static IApiComponent[] getReexportedComponents(IApiComponent component) { try { IRequiredComponentDescription[] requiredComponents = component.getRequiredComponents(); int length = requiredComponents.length; if (length != 0) { List<IApiComponent> reexportedComponents = null; IApiBaseline baseline = component.getBaseline(); for (int i = 0; i < length; i++) { IRequiredComponentDescription description = requiredComponents[i]; if (description.isExported()) { String id = description.getId(); IApiComponent reexportedComponent = baseline.getApiComponent(id); if (reexportedComponent != null) { if (reexportedComponents == null) { reexportedComponents = new ArrayList<IApiComponent>(); } reexportedComponents.add(reexportedComponent); } } } if (reexportedComponents == null || reexportedComponents.size() == 0) { return null; } return reexportedComponents.toArray(new IApiComponent[reexportedComponents.size()]); } } catch (CoreException e) { ApiPlugin.log(e); } return null; } /** * Returns the {@link IResource} to create markers on when building. If the * {@link IType} is <code>null</code> or the type cannot be located (does * not exist) than the MANIFEST.MF will be returned. <code>null</code> can * be returned in the case that the project does not have a manifest file. * * @param project the project to look in for the {@link IResource} * @param type the type we are looking for the resource for, or * <code>null</code> * @return the {@link IResource} associated with the given {@link IType} or * the MANIFEST.MF file, or <code>null</code> if the project does * not have a manifest */ public static IResource getResource(IProject project, IType type) { try { if (type != null) { ICompilationUnit unit = type.getCompilationUnit(); if (unit != null) { IResource resource = unit.getCorrespondingResource(); if (resource != null && resource.exists()) { return resource; } } } } catch (JavaModelException e) { ApiPlugin.log(e); } return getManifestFile(project); } /** * Default comparator that orders {@link IApiComponent} by their ID */ public static final Comparator<Object> componentsorter = new Comparator<Object>() { @Override public int compare(Object o1, Object o2) { if (o1 instanceof IApiComponent && o2 instanceof IApiComponent) { return ((IApiComponent) o1).getSymbolicName().compareTo(((IApiComponent) o2).getSymbolicName()); } if (o1 instanceof SkippedComponent && o2 instanceof SkippedComponent) { return ((SkippedComponent) o1).getComponentId().compareTo(((SkippedComponent) o2).getComponentId()); } if (o1 instanceof String && o2 instanceof String) { return ((String) o1).compareTo((String) o2); } return -1; } }; /** * Initializes the exclude set with regex support. The API baseline is used * to determine which bundles should be added to the list when processing * regex expressions. * * @param location * @param baseline * @return the list of bundles to be excluded * @throws CoreException if the location does not describe a includes file * or an IOException occurs */ public static FilteredElements initializeRegexFilterList(String location, IApiBaseline baseline, boolean debug) throws CoreException { FilteredElements excludedElements = new FilteredElements(); if (location != null) { File file = new File(location); InputStream stream = null; char[] contents = null; try { stream = new BufferedInputStream(new FileInputStream(file)); contents = getInputStreamAsCharArray(stream, -1, ISO_8859_1); } catch (FileNotFoundException e) { abort(NLS.bind(UtilMessages.Util_couldNotFindFilterFile, location), e); } catch (IOException e) { abort(NLS.bind(UtilMessages.Util_problemWithFilterFile, location), e); } finally { if (stream != null) { try { stream.close(); } catch (IOException e) { } } } if (contents != null) { LineNumberReader reader = new LineNumberReader(new StringReader(new String(contents))); String line = null; try { while ((line = reader.readLine()) != null) { line = line.trim(); if (line.startsWith("#") || line.length() == 0) { //$NON-NLS-1$ continue; } if (line.startsWith(REGULAR_EXPRESSION_START)) { if (baseline != null) { Util.collectRegexIds(line, excludedElements, baseline.getApiComponents(), debug); } } else { excludedElements.addExactMatch(line); } } } catch (IOException e) { abort(NLS.bind(UtilMessages.Util_problemWithFilterFile, location), e); } finally { try { reader.close(); } catch (IOException e) { } } } } return excludedElements; } /** * Collects the set of component ids that match a given regex in the exclude * file * * @param line * @param list * @param components */ public static void collectRegexIds(String line, FilteredElements excludedElements, IApiComponent[] components, boolean debug) throws CoreException { if (line.startsWith(REGULAR_EXPRESSION_START)) { String componentname = line; // regular expression componentname = componentname.substring(2); Pattern pattern = null; try { if (debug) { System.out.println("Pattern to match : " + componentname); //$NON-NLS-1$ } pattern = Pattern.compile(componentname); String componentid = null; for (int j = 0, max2 = components.length; j < max2; j++) { componentid = components[j].getSymbolicName(); if (pattern.matcher(componentid).matches()) { if (debug) { System.out.println(componentid + " matched the pattern " + componentname); //$NON-NLS-1$ } excludedElements.addPartialMatch(componentid); } else if (debug) { System.out.println(componentid + " didn't match the pattern " + componentname); //$NON-NLS-1$ } } } catch (PatternSyntaxException e) { abort(NLS.bind(UtilMessages.comparison_invalidRegularExpression, componentname), e); } } } /** * Default comparator that orders {@link File}s by their name */ public static final Comparator<Object> filesorter = new Comparator<Object>() { @Override public int compare(Object o1, Object o2) { if (o1 instanceof File && o2 instanceof File) { return ((File) o1).getName().compareTo(((File) o2).getName()); } return 0; } }; /** * Returns true if the given {@link IApiType} is API or not, where API is * defined as having API visibility in an API description and having either * the public of protected Java flag set * * @param visibility * @param typeDescriptor * @return true if the given type is API, false otherwise */ public static boolean isAPI(int visibility, IApiType typeDescriptor) { int access = typeDescriptor.getModifiers(); return VisibilityModifiers.isAPI(visibility) && (Flags.isPublic(access) || Flags.isProtected(access)); } /** * Simple method to walk an array and call <code>toString()</code> on each * of the entries. Does not descend into sub-collections. * * @param array the array * @return the comma-separated string representation of the the array * @since 1.0.3 */ public static String deepToString(Object[] array) { StringBuffer buffer = new StringBuffer(); for (int i = 0; i < array.length; i++) { buffer.append(array[i].toString()); if (i < array.length - 1) { buffer.append(','); } } return buffer.toString(); } }