| 1 | /******************************************************************************* |
| 2 | * Copyright (c) 2007, 2009 IBM Corporation and others. |
| 3 | * All rights reserved. This program and the accompanying materials |
| 4 | * are made available under the terms of the Eclipse Public License v1.0 |
| 5 | * which accompanies this distribution, and is available at |
| 6 | * http://www.eclipse.org/legal/epl-v10.html |
| 7 | * |
| 8 | * Contributors: |
| 9 | * IBM Corporation - initial API and implementation |
| 10 | *******************************************************************************/ |
| 11 | package org.eclipse.pde.api.tools.internal.util; |
| 12 | |
| 13 | import java.io.BufferedInputStream; |
| 14 | import java.io.BufferedOutputStream; |
| 15 | import java.io.BufferedWriter; |
| 16 | import java.io.ByteArrayInputStream; |
| 17 | import java.io.ByteArrayOutputStream; |
| 18 | import java.io.File; |
| 19 | import java.io.FileFilter; |
| 20 | import java.io.FileInputStream; |
| 21 | import java.io.FileNotFoundException; |
| 22 | import java.io.FileOutputStream; |
| 23 | import java.io.FileWriter; |
| 24 | import java.io.FilenameFilter; |
| 25 | import java.io.IOException; |
| 26 | import java.io.InputStream; |
| 27 | import java.io.LineNumberReader; |
| 28 | import java.io.PrintWriter; |
| 29 | import java.io.StringReader; |
| 30 | import java.io.UnsupportedEncodingException; |
| 31 | import java.lang.reflect.Field; |
| 32 | import java.nio.ByteBuffer; |
| 33 | import java.nio.charset.Charset; |
| 34 | import java.nio.charset.CharsetDecoder; |
| 35 | import java.nio.charset.CodingErrorAction; |
| 36 | import java.nio.charset.IllegalCharsetNameException; |
| 37 | import java.nio.charset.UnsupportedCharsetException; |
| 38 | import java.util.ArrayList; |
| 39 | import java.util.Arrays; |
| 40 | import java.util.Comparator; |
| 41 | import java.util.Enumeration; |
| 42 | import java.util.HashSet; |
| 43 | import java.util.Iterator; |
| 44 | import java.util.List; |
| 45 | import java.util.Properties; |
| 46 | import java.util.Set; |
| 47 | import java.util.StringTokenizer; |
| 48 | import java.util.jar.JarFile; |
| 49 | import java.util.regex.Pattern; |
| 50 | import java.util.regex.PatternSyntaxException; |
| 51 | import java.util.zip.ZipEntry; |
| 52 | import java.util.zip.ZipException; |
| 53 | import java.util.zip.ZipFile; |
| 54 | import java.util.zip.ZipInputStream; |
| 55 | |
| 56 | import javax.xml.parsers.DocumentBuilder; |
| 57 | import javax.xml.parsers.DocumentBuilderFactory; |
| 58 | import javax.xml.parsers.FactoryConfigurationError; |
| 59 | import javax.xml.parsers.ParserConfigurationException; |
| 60 | import javax.xml.transform.OutputKeys; |
| 61 | import javax.xml.transform.Transformer; |
| 62 | import javax.xml.transform.TransformerException; |
| 63 | import javax.xml.transform.TransformerFactory; |
| 64 | import javax.xml.transform.dom.DOMSource; |
| 65 | import javax.xml.transform.stream.StreamResult; |
| 66 | |
| 67 | import org.eclipse.core.filebuffers.FileBuffers; |
| 68 | import org.eclipse.core.filebuffers.ITextFileBufferManager; |
| 69 | import org.eclipse.core.filebuffers.LocationKind; |
| 70 | import org.eclipse.core.resources.IFile; |
| 71 | import org.eclipse.core.resources.IMarker; |
| 72 | import org.eclipse.core.resources.IProject; |
| 73 | import org.eclipse.core.resources.IResource; |
| 74 | import org.eclipse.core.resources.IncrementalProjectBuilder; |
| 75 | import org.eclipse.core.resources.ResourcesPlugin; |
| 76 | import org.eclipse.core.runtime.Assert; |
| 77 | import org.eclipse.core.runtime.CoreException; |
| 78 | import org.eclipse.core.runtime.IPath; |
| 79 | import org.eclipse.core.runtime.IProgressMonitor; |
| 80 | import org.eclipse.core.runtime.IStatus; |
| 81 | import org.eclipse.core.runtime.NullProgressMonitor; |
| 82 | import org.eclipse.core.runtime.OperationCanceledException; |
| 83 | import org.eclipse.core.runtime.Path; |
| 84 | import org.eclipse.core.runtime.Status; |
| 85 | import org.eclipse.core.runtime.SubMonitor; |
| 86 | import org.eclipse.core.runtime.jobs.Job; |
| 87 | import org.eclipse.jdt.core.Flags; |
| 88 | import org.eclipse.jdt.core.ICompilationUnit; |
| 89 | import org.eclipse.jdt.core.IField; |
| 90 | import org.eclipse.jdt.core.IJavaProject; |
| 91 | import org.eclipse.jdt.core.IMember; |
| 92 | import org.eclipse.jdt.core.IMethod; |
| 93 | import org.eclipse.jdt.core.IType; |
| 94 | import org.eclipse.jdt.core.JavaCore; |
| 95 | import org.eclipse.jdt.core.JavaModelException; |
| 96 | import org.eclipse.jdt.core.Signature; |
| 97 | import org.eclipse.jdt.internal.compiler.codegen.ConstantPool; |
| 98 | import org.eclipse.jdt.launching.IVMInstall; |
| 99 | import org.eclipse.jdt.launching.JavaRuntime; |
| 100 | import org.eclipse.jdt.launching.LibraryLocation; |
| 101 | import org.eclipse.jdt.launching.environments.ExecutionEnvironmentDescription; |
| 102 | import org.eclipse.jface.text.IDocument; |
| 103 | import org.eclipse.osgi.util.NLS; |
| 104 | import org.eclipse.pde.api.tools.internal.ApiFilterStore; |
| 105 | import org.eclipse.pde.api.tools.internal.IApiCoreConstants; |
| 106 | import org.eclipse.pde.api.tools.internal.builder.BuildState; |
| 107 | import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin; |
| 108 | import org.eclipse.pde.api.tools.internal.provisional.Factory; |
| 109 | import org.eclipse.pde.api.tools.internal.provisional.IApiMarkerConstants; |
| 110 | import org.eclipse.pde.api.tools.internal.provisional.IRequiredComponentDescription; |
| 111 | import org.eclipse.pde.api.tools.internal.provisional.VisibilityModifiers; |
| 112 | import org.eclipse.pde.api.tools.internal.provisional.comparator.DeltaVisitor; |
| 113 | import org.eclipse.pde.api.tools.internal.provisional.comparator.IDelta; |
| 114 | import org.eclipse.pde.api.tools.internal.provisional.descriptors.IReferenceTypeDescriptor; |
| 115 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline; |
| 116 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent; |
| 117 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiElement; |
| 118 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiType; |
| 119 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiTypeRoot; |
| 120 | import org.eclipse.pde.api.tools.internal.search.SkippedComponent; |
| 121 | import org.objectweb.asm.Opcodes; |
| 122 | import org.osgi.framework.Version; |
| 123 | import org.w3c.dom.Document; |
| 124 | import org.w3c.dom.Element; |
| 125 | import org.xml.sax.SAXException; |
| 126 | import org.xml.sax.helpers.DefaultHandler; |
| 127 | |
| 128 | /** |
| 129 | * A Utility class to use for API tools |
| 130 | * |
| 131 | * @since 1.0.0 |
| 132 | */ |
| 133 | public final class Util { |
| 134 | |
| 135 | /** |
| 136 | * Class that runs a build in the workspace or the given project |
| 137 | */ |
| 138 | private static final class BuildJob extends Job { |
| 139 | private final IProject[] fProjects; |
| 140 | private int fBuildType; |
| 141 | |
| 142 | /** |
| 143 | * Constructor |
| 144 | * @param name |
| 145 | * @param project |
| 146 | */ |
| 147 | BuildJob(String name, IProject[] projects) { |
| 148 | this(name, projects, IncrementalProjectBuilder.FULL_BUILD); |
| 149 | } |
| 150 | BuildJob(String name, IProject[] projects, int buildType) { |
| 151 | super(name); |
| 152 | fProjects = projects; |
| 153 | this.fBuildType = buildType; |
| 154 | } |
| 155 | public boolean belongsTo(Object family) { |
| 156 | return ResourcesPlugin.FAMILY_MANUAL_BUILD == family; |
| 157 | } |
| 158 | |
| 159 | /** |
| 160 | * Returns if this build job is covered by another build job |
| 161 | * @param other |
| 162 | * @return true if covered by another build job, false otherwise |
| 163 | */ |
| 164 | public boolean isCoveredBy(BuildJob other) { |
| 165 | if (other.fProjects == null) { |
| 166 | return true; |
| 167 | } |
| 168 | if (this.fProjects != null) { |
| 169 | for (int i = 0, max = this.fProjects.length; i < max; i++) { |
| 170 | if (!other.contains(this.fProjects[i])) { |
| 171 | return false; |
| 172 | } |
| 173 | } |
| 174 | return true; |
| 175 | } |
| 176 | return false; |
| 177 | } |
| 178 | |
| 179 | public boolean contains(IProject project) { |
| 180 | if (project == null) return false; |
| 181 | for (int i = 0, max = this.fProjects.length; i < max; i++) { |
| 182 | if (project.equals(this.fProjects[i])) { |
| 183 | return true; |
| 184 | } |
| 185 | } |
| 186 | return false; |
| 187 | } |
| 188 | /* (non-Javadoc) |
| 189 | * @see org.eclipse.core.runtime.jobs.Job#run(org.eclipse.core.runtime.IProgressMonitor) |
| 190 | */ |
| 191 | protected IStatus run(IProgressMonitor monitor) { |
| 192 | synchronized (getClass()) { |
| 193 | if (monitor.isCanceled()) { |
| 194 | return Status.CANCEL_STATUS; |
| 195 | } |
| 196 | //cancelBuild(ResourcesPlugin.FAMILY_AUTO_BUILD); |
| 197 | cancelBuild(ResourcesPlugin.FAMILY_MANUAL_BUILD); |
| 198 | } |
| 199 | try { |
| 200 | if (fProjects != null) { |
| 201 | SubMonitor localmonitor = SubMonitor.convert(monitor, UtilMessages.Util_0, fProjects.length); |
| 202 | for (int i = 0, max = fProjects.length; i < max; i++) { |
| 203 | // clear last build state for project to force a full build using our builder |
| 204 | // This makes it possible to have only an incremental build from the java builder |
| 205 | IProject currentProject = fProjects[i]; |
| 206 | if (this.fBuildType == IncrementalProjectBuilder.FULL_BUILD) { |
| 207 | BuildState.setLastBuiltState(currentProject, null); |
| 208 | } |
| 209 | localmonitor.subTask(NLS.bind(UtilMessages.Util_5, currentProject.getName())); |
| 210 | if (ResourcesPlugin.getWorkspace().isAutoBuilding()) { |
| 211 | currentProject.touch(null); |
| 212 | } else { |
| 213 | currentProject.build(IncrementalProjectBuilder.INCREMENTAL_BUILD, localmonitor.newChild(1)); |
| 214 | } |
| 215 | } |
| 216 | } |
| 217 | } catch (CoreException e) { |
| 218 | return e.getStatus(); |
| 219 | } catch (OperationCanceledException e) { |
| 220 | return Status.CANCEL_STATUS; |
| 221 | } |
| 222 | finally { |
| 223 | monitor.done(); |
| 224 | } |
| 225 | return Status.OK_STATUS; |
| 226 | } |
| 227 | |
| 228 | private void cancelBuild(Object jobfamily) { |
| 229 | Job[] buildJobs = Job.getJobManager().find(jobfamily); |
| 230 | for (int i= 0; i < buildJobs.length; i++) { |
| 231 | Job curr = buildJobs[i]; |
| 232 | if (curr != this && curr instanceof BuildJob) { |
| 233 | BuildJob job = (BuildJob) curr; |
| 234 | if (job.isCoveredBy(this)) { |
| 235 | curr.cancel(); // cancel all other build jobs of our kind |
| 236 | } |
| 237 | } |
| 238 | } |
| 239 | } |
| 240 | } |
| 241 | |
| 242 | public static boolean DEBUG; |
| 243 | |
| 244 | public static final String EMPTY_STRING = "";//$NON-NLS-1$ |
| 245 | public static final String DEFAULT_PACKAGE_NAME = EMPTY_STRING; |
| 246 | public static final String MANIFEST_NAME = "MANIFEST.MF"; //$NON-NLS-1$ |
| 247 | |
| 248 | public static final String DOT_CLASS_SUFFIX = ".class"; //$NON-NLS-1$ |
| 249 | public static final String DOT_JAVA_SUFFIX = ".java"; //$NON-NLS-1$ |
| 250 | |
| 251 | /** |
| 252 | * Constant representing the default size to read from an input stream |
| 253 | */ |
| 254 | private static final int DEFAULT_READING_SIZE = 8192; |
| 255 | |
| 256 | private static final String JAVA_LANG_OBJECT = "java.lang.Object"; //$NON-NLS-1$ |
| 257 | private static final String JAVA_LANG_RUNTIMEEXCEPTION = "java.lang.RuntimeException"; //$NON-NLS-1$ |
| 258 | public static final String LINE_DELIMITER = System.getProperty("line.separator"); //$NON-NLS-1$ |
| 259 | |
| 260 | public static final String UNKNOWN_ELEMENT_KIND = "UNKNOWN_ELEMENT_KIND"; //$NON-NLS-1$ |
| 261 | |
| 262 | public static final String UNKNOWN_FLAGS = "UNKNOWN_FLAGS"; //$NON-NLS-1$ |
| 263 | public static final String UNKNOWN_KIND = "UNKNOWN_KIND"; //$NON-NLS-1$ |
| 264 | public static final String UNKNOWN_VISIBILITY = "UNKNOWN_VISIBILITY"; //$NON-NLS-1$ |
| 265 | public static final String ISO_8859_1 = "ISO-8859-1"; //$NON-NLS-1$ |
| 266 | public static final String REGULAR_EXPRESSION_START = "R:"; //$NON-NLS-1$ |
| 267 | |
| 268 | // Trace for delete operation |
| 269 | /* |
| 270 | * Maximum time wasted repeating delete operations while running JDT/Core tests. |
| 271 | */ |
| 272 | private static int DELETE_MAX_TIME = 0; |
| 273 | /** |
| 274 | * Trace deletion operations while running JDT/Core tests. |
| 275 | */ |
| 276 | private static boolean DELETE_DEBUG = false; |
| 277 | /** |
| 278 | * Maximum of time in ms to wait in deletion operation while running JDT/Core tests. |
| 279 | * Default is 10 seconds. This number cannot exceed 1 minute (i.e. 60000). |
| 280 | * <br> |
| 281 | * To avoid too many loops while waiting, the ten first ones are done waiting |
| 282 | * 10ms before repeating, the ten loops after are done waiting 100ms and |
| 283 | * the other loops are done waiting 1s... |
| 284 | */ |
| 285 | private static int DELETE_MAX_WAIT = 10000; |
| 286 | |
| 287 | public static final IPath MANIFEST_PROJECT_RELATIVE_PATH = new Path(JarFile.MANIFEST_NAME); |
| 288 | |
| 289 | public static final String ORG_ECLIPSE_SWT = "org.eclipse.swt"; //$NON-NLS-1$ |
| 290 | |
| 291 | static { |
| 292 | String property = System.getProperty("DEBUG"); //$NON-NLS-1$ |
| 293 | DEBUG = property != null && property.equalsIgnoreCase("TRUE"); //$NON-NLS-1$ |
| 294 | } |
| 295 | |
| 296 | /** |
| 297 | * Throws an exception with the given message and underlying exception. |
| 298 | * |
| 299 | * @param message error message |
| 300 | * @param exception underlying exception, or <code>null</code> |
| 301 | * @throws CoreException |
| 302 | */ |
| 303 | private static void abort(String message, Throwable exception) throws CoreException { |
| 304 | IStatus status = new Status(IStatus.ERROR, ApiPlugin.PLUGIN_ID, message, exception); |
| 305 | throw new CoreException(status); |
| 306 | } |
| 307 | |
| 308 | /** |
| 309 | * Appends a property to the given string buffer with the given key and value |
| 310 | * in the format "key=value\n". |
| 311 | * |
| 312 | * @param buffer buffer to append to |
| 313 | * @param key key |
| 314 | * @param value value |
| 315 | */ |
| 316 | private static void appendProperty(StringBuffer buffer, String key, String value) { |
| 317 | buffer.append(key); |
| 318 | buffer.append('='); |
| 319 | buffer.append(value); |
| 320 | buffer.append('\n'); |
| 321 | } |
| 322 | |
| 323 | /** |
| 324 | * Collects all of the deltas from the given parent delta |
| 325 | * @param delta |
| 326 | * @return |
| 327 | */ |
| 328 | public static List collectAllDeltas(IDelta delta) { |
| 329 | final List list = new ArrayList(); |
| 330 | delta.accept(new DeltaVisitor() { |
| 331 | public void endVisit(IDelta localDelta) { |
| 332 | if (localDelta.getChildren().length == 0) { |
| 333 | list.add(localDelta); |
| 334 | } |
| 335 | super.endVisit(localDelta); |
| 336 | } |
| 337 | }); |
| 338 | return list; |
| 339 | } |
| 340 | |
| 341 | /** |
| 342 | * Collects files into the collector array list |
| 343 | * |
| 344 | * @param root |
| 345 | * the root to collect the files from |
| 346 | * @param collector |
| 347 | * the collector to place matches into |
| 348 | * @param fileFilter |
| 349 | * the filter for files or <code>null</code> to accept all |
| 350 | * files |
| 351 | */ |
| 352 | private static void collectAllFiles(File root, ArrayList collector, FileFilter fileFilter) { |
| 353 | File[] files = root.listFiles(fileFilter); |
| 354 | for (int i = 0; i < files.length; i++) { |
| 355 | final File currentFile = files[i]; |
| 356 | if (currentFile.isDirectory()) { |
| 357 | collectAllFiles(currentFile, collector, fileFilter); |
| 358 | } else { |
| 359 | collector.add(currentFile); |
| 360 | } |
| 361 | } |
| 362 | } |
| 363 | |
| 364 | /** |
| 365 | * Returns all of the API projects in the workspace |
| 366 | * @return all of the API projects in the workspace or <code>null</code> if there are none. |
| 367 | */ |
| 368 | public static IProject[] getApiProjects() { |
| 369 | IProject[] allProjects = ResourcesPlugin.getWorkspace().getRoot().getProjects(); |
| 370 | ArrayList temp = new ArrayList(); |
| 371 | IProject project = null; |
| 372 | for (int i = 0, max = allProjects.length; i < max; i++) { |
| 373 | project = allProjects[i]; |
| 374 | if (project.isAccessible()) { |
| 375 | try { |
| 376 | if (project.hasNature(org.eclipse.pde.api.tools.internal.provisional.ApiPlugin.NATURE_ID)) { |
| 377 | temp.add(project); |
| 378 | } |
| 379 | } |
| 380 | catch (CoreException e) {} |
| 381 | } |
| 382 | } |
| 383 | IProject[] projects = null; |
| 384 | if (temp.size() != 0) { |
| 385 | projects = new IProject[temp.size()]; |
| 386 | temp.toArray(projects); |
| 387 | } |
| 388 | return projects; |
| 389 | } |
| 390 | |
| 391 | /** |
| 392 | * Copies the given file to the new file |
| 393 | * @param file |
| 394 | * @param newFile |
| 395 | * @return if the copy succeeded |
| 396 | */ |
| 397 | public static boolean copy(File file, File newFile) { |
| 398 | byte[] bytes = null; |
| 399 | BufferedInputStream inputStream = null; |
| 400 | try { |
| 401 | inputStream = new BufferedInputStream(new FileInputStream(file)); |
| 402 | bytes = Util.getInputStreamAsByteArray(inputStream, -1); |
| 403 | } catch (FileNotFoundException e) { |
| 404 | ApiPlugin.log(e); |
| 405 | } catch (IOException e) { |
| 406 | ApiPlugin.log(e); |
| 407 | } finally { |
| 408 | if (inputStream != null) { |
| 409 | try { |
| 410 | inputStream.close(); |
| 411 | } catch (IOException e) { |
| 412 | ApiPlugin.log(e); |
| 413 | } |
| 414 | } |
| 415 | } |
| 416 | if (bytes != null) { |
| 417 | BufferedOutputStream outputStream = null; |
| 418 | try { |
| 419 | outputStream = new BufferedOutputStream(new FileOutputStream(newFile)); |
| 420 | outputStream.write(bytes); |
| 421 | outputStream.flush(); |
| 422 | } catch (FileNotFoundException e) { |
| 423 | ApiPlugin.log(e); |
| 424 | } catch (IOException e) { |
| 425 | ApiPlugin.log(e); |
| 426 | } finally { |
| 427 | if (outputStream != null) { |
| 428 | try { |
| 429 | outputStream.close(); |
| 430 | } catch(IOException e) { |
| 431 | // ignore |
| 432 | } |
| 433 | } |
| 434 | } |
| 435 | return true; |
| 436 | } |
| 437 | return false; |
| 438 | } |
| 439 | |
| 440 | /** |
| 441 | * Creates an EE file for the given JRE and specified EE id |
| 442 | * @param jre |
| 443 | * @param eeid |
| 444 | * @return |
| 445 | * @throws IOException |
| 446 | */ |
| 447 | public static File createEEFile(IVMInstall jre, String eeid) throws IOException { |
| 448 | String string = Util.generateEEContents(jre, eeid); |
| 449 | File eeFile = File.createTempFile("eed", ".ee"); //$NON-NLS-1$ //$NON-NLS-2$ |
| 450 | eeFile.deleteOnExit(); |
| 451 | FileOutputStream outputStream = null; |
| 452 | try { |
| 453 | outputStream = new FileOutputStream(eeFile); |
| 454 | outputStream.write(string.getBytes(IApiCoreConstants.UTF_8)); |
| 455 | } finally { |
| 456 | if (outputStream != null) { |
| 457 | outputStream.close(); |
| 458 | } |
| 459 | } |
| 460 | return eeFile; |
| 461 | } |
| 462 | |
| 463 | /** |
| 464 | * Returns whether the objects are equal, accounting for either one being <code>null</code>. |
| 465 | * |
| 466 | * @param o1 |
| 467 | * @param o2 |
| 468 | * @return whether the objects are equal, or both are <code>null</code> |
| 469 | */ |
| 470 | public static boolean equalsOrNull(Object o1, Object o2) { |
| 471 | if (o1 == null) { |
| 472 | return o2 == null; |
| 473 | } |
| 474 | return o1.equals(o2); |
| 475 | } |
| 476 | |
| 477 | /** |
| 478 | * Returns an execution environment description for the given VM. |
| 479 | * |
| 480 | * @param vm JRE to create an definition for |
| 481 | * @return an execution environment description for the given VM |
| 482 | * @throws IOException if unable to generate description |
| 483 | */ |
| 484 | public static String generateEEContents(IVMInstall vm, String eeId) throws IOException { |
| 485 | StringBuffer buffer = new StringBuffer(); |
| 486 | appendProperty(buffer, ExecutionEnvironmentDescription.JAVA_HOME, vm.getInstallLocation().getCanonicalPath()); |
| 487 | StringBuffer paths = new StringBuffer(); |
| 488 | LibraryLocation[] libraryLocations = JavaRuntime.getLibraryLocations(vm); |
| 489 | for (int i = 0; i < libraryLocations.length; i++) { |
| 490 | LibraryLocation lib = libraryLocations[i]; |
| 491 | paths.append(lib.getSystemLibraryPath().toOSString()); |
| 492 | if (i < (libraryLocations.length - 1)) { |
| 493 | paths.append(File.pathSeparatorChar); |
| 494 | } |
| 495 | } |
| 496 | appendProperty(buffer, ExecutionEnvironmentDescription.BOOT_CLASS_PATH, paths.toString()); |
| 497 | appendProperty(buffer, ExecutionEnvironmentDescription.CLASS_LIB_LEVEL, eeId); |
| 498 | return buffer.toString(); |
| 499 | } |
| 500 | |
| 501 | /** |
| 502 | * Returns an array of all of the files from the given root that are |
| 503 | * accepted by the given file filter. If the file filter is null all files |
| 504 | * within the given root are returned. |
| 505 | * |
| 506 | * @param root |
| 507 | * @param fileFilter |
| 508 | * @return the list of files from within the given root |
| 509 | */ |
| 510 | public static File[] getAllFiles(File root, FileFilter fileFilter) { |
| 511 | ArrayList files = new ArrayList(); |
| 512 | if (root.isDirectory()) { |
| 513 | collectAllFiles(root, files, fileFilter); |
| 514 | File[] result = new File[files.size()]; |
| 515 | files.toArray(result); |
| 516 | return result; |
| 517 | } |
| 518 | return null; |
| 519 | } |
| 520 | |
| 521 | /** |
| 522 | * Returns a build job that will perform a full build on the given projects. |
| 523 | * |
| 524 | * If <code>projects</code> are null, then an AssertionFailedException is thrown |
| 525 | * @param projects the projects to build |
| 526 | * @return the build job |
| 527 | * @throws AssertionFailedException if the given projects are null |
| 528 | */ |
| 529 | public static Job getBuildJob(final IProject[] projects) { |
| 530 | Assert.isNotNull(projects); |
| 531 | Job buildJob = new BuildJob(UtilMessages.Util_4, projects); |
| 532 | buildJob.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().buildRule()); |
| 533 | buildJob.setUser(true); |
| 534 | return buildJob; |
| 535 | } |
| 536 | |
| 537 | /** |
| 538 | * Returns a build job that will return the build that corresponds to the given |
| 539 | * build kind on the given projects. |
| 540 | * |
| 541 | * If <code>projects</code> are null, then an AssertionFailedException is thrown |
| 542 | * @param projects the projects to build |
| 543 | * @param buildKind the given build kind |
| 544 | * @return the build job |
| 545 | * @throws AssertionFailedException if the given projects are null |
| 546 | */ |
| 547 | public static Job getBuildJob(final IProject[] projects, int buildKind) { |
| 548 | Assert.isNotNull(projects); |
| 549 | Job buildJob = new BuildJob(UtilMessages.Util_4, projects, buildKind); |
| 550 | buildJob.setRule(ResourcesPlugin.getWorkspace().getRuleFactory().buildRule()); |
| 551 | buildJob.setUser(true); |
| 552 | return buildJob; |
| 553 | } |
| 554 | |
| 555 | /** |
| 556 | * Returns a result of searching the given components for class file with the |
| 557 | * given type name. |
| 558 | * |
| 559 | * @param components API components to search or <code>null</code> if none |
| 560 | * @param typeName type to search for |
| 561 | * @return class file or <code>null</code> if none found |
| 562 | */ |
| 563 | public static IApiTypeRoot getClassFile(IApiComponent[] components, String typeName) { |
| 564 | if (components == null) { |
| 565 | return null; |
| 566 | } |
| 567 | for (int i = 0, max = components.length; i < max; i++) { |
| 568 | IApiComponent apiComponent = components[i]; |
| 569 | if (apiComponent != null) { |
| 570 | try { |
| 571 | IApiTypeRoot classFile = apiComponent.findTypeRoot(typeName); |
| 572 | if (classFile != null) return classFile; |
| 573 | } catch (CoreException e) { |
| 574 | // ignore |
| 575 | } |
| 576 | } |
| 577 | } |
| 578 | return null; |
| 579 | } |
| 580 | |
| 581 | /** |
| 582 | * Return a string that represents the element type of the given delta. |
| 583 | * Returns {@link #UNKNOWN_ELEMENT_KIND} if the element type cannot be determined. |
| 584 | * |
| 585 | * @param delta the given delta |
| 586 | * @return a string that represents the element type of the given delta. |
| 587 | */ |
| 588 | public static String getDeltaElementType(IDelta delta) { |
| 589 | return getDeltaElementType(delta.getElementType()); |
| 590 | } |
| 591 | |
| 592 | /** |
| 593 | * Returns a text representation of a marker severity level |
| 594 | * @param severity |
| 595 | * @return text of a marker severity level |
| 596 | */ |
| 597 | public static String getSeverity(int severity) { |
| 598 | switch(severity) { |
| 599 | case IMarker.SEVERITY_ERROR: { |
| 600 | return "ERROR"; //$NON-NLS-1$ |
| 601 | } |
| 602 | case IMarker.SEVERITY_INFO: { |
| 603 | return "INFO"; //$NON-NLS-1$ |
| 604 | } |
| 605 | case IMarker.SEVERITY_WARNING: { |
| 606 | return "WARNING"; //$NON-NLS-1$ |
| 607 | } |
| 608 | default: { |
| 609 | return "UNKNOWN_SEVERITY"; //$NON-NLS-1$ |
| 610 | } |
| 611 | } |
| 612 | } |
| 613 | /** |
| 614 | * Return an int value that represents the given element type |
| 615 | * Returns -1 if the element type cannot be determined. |
| 616 | * |
| 617 | * @param elementType the given element type |
| 618 | * @return an int that represents the given element type constant. |
| 619 | */ |
| 620 | public static int getDeltaElementTypeValue(String elementType) { |
| 621 | Class IDeltaClass = IDelta.class; |
| 622 | try { |
| 623 | Field field = IDeltaClass.getField(elementType); |
| 624 | return field.getInt(null); |
| 625 | } catch (SecurityException e) { |
| 626 | // ignore |
| 627 | } catch (IllegalArgumentException e) { |
| 628 | // ignore |
| 629 | } catch (NoSuchFieldException e) { |
| 630 | // ignore |
| 631 | } catch (IllegalAccessException e) { |
| 632 | // ignore |
| 633 | } |
| 634 | return -1; |
| 635 | } |
| 636 | /** |
| 637 | * Return a string that represents the given element type |
| 638 | * Returns {@link #UNKNOWN_ELEMENT_KIND} if the element type cannot be determined. |
| 639 | * |
| 640 | * @param elementType the given element type |
| 641 | * @return a string that represents the given element type. |
| 642 | */ |
| 643 | public static String getDeltaElementType(int elementType) { |
| 644 | switch(elementType) { |
| 645 | case IDelta.ANNOTATION_ELEMENT_TYPE : |
| 646 | return "ANNOTATION_ELEMENT_TYPE"; //$NON-NLS-1$ |
| 647 | case IDelta.INTERFACE_ELEMENT_TYPE : |
| 648 | return "INTERFACE_ELEMENT_TYPE"; //$NON-NLS-1$ |
| 649 | case IDelta.ENUM_ELEMENT_TYPE : |
| 650 | return "ENUM_ELEMENT_TYPE"; //$NON-NLS-1$ |
| 651 | case IDelta.API_COMPONENT_ELEMENT_TYPE : |
| 652 | return "API_COMPONENT_ELEMENT_TYPE"; //$NON-NLS-1$ |
| 653 | case IDelta.API_PROFILE_ELEMENT_TYPE : |
| 654 | return "API_PROFILE_ELEMENT_TYPE"; //$NON-NLS-1$ |
| 655 | case IDelta.CONSTRUCTOR_ELEMENT_TYPE : |
| 656 | return "CONSTRUCTOR_ELEMENT_TYPE"; //$NON-NLS-1$ |
| 657 | case IDelta.METHOD_ELEMENT_TYPE : |
| 658 | return "METHOD_ELEMENT_TYPE"; //$NON-NLS-1$ |
| 659 | case IDelta.FIELD_ELEMENT_TYPE : |
| 660 | return "FIELD_ELEMENT_TYPE"; //$NON-NLS-1$ |
| 661 | case IDelta.CLASS_ELEMENT_TYPE : |
| 662 | return "CLASS_ELEMENT_TYPE"; //$NON-NLS-1$ |
| 663 | case IDelta.TYPE_PARAMETER_ELEMENT_TYPE : |
| 664 | return "TYPE_PARAMETER_ELEMENT_TYPE"; //$NON-NLS-1$ |
| 665 | } |
| 666 | return UNKNOWN_ELEMENT_KIND; |
| 667 | } |
| 668 | |
| 669 | /** |
| 670 | * Return a string that represents the given flags |
| 671 | * Returns {@link #UNKNOWN_FLAGS} if the flags cannot be determined. |
| 672 | * |
| 673 | * @param flags the given delta's flags |
| 674 | * @return a string that represents the given flags. |
| 675 | */ |
| 676 | public static String getDeltaFlagsName(int flags) { |
| 677 | switch(flags) { |
| 678 | case IDelta.ABSTRACT_TO_NON_ABSTRACT : return "ABSTRACT_TO_NON_ABSTRACT"; //$NON-NLS-1$ |
| 679 | case IDelta.ANNOTATION_DEFAULT_VALUE : return "ANNOTATION_DEFAULT_VALUE"; //$NON-NLS-1$ |
| 680 | case IDelta.API_COMPONENT : return "API_COMPONENT"; //$NON-NLS-1$ |
| 681 | case IDelta.ARRAY_TO_VARARGS : return "ARRAY_TO_VARARGS"; //$NON-NLS-1$ |
| 682 | case IDelta.CHECKED_EXCEPTION : return "CHECKED_EXCEPTION"; //$NON-NLS-1$ |
| 683 | case IDelta.CLASS_BOUND : return "CLASS_BOUND"; //$NON-NLS-1$ |
| 684 | case IDelta.CLINIT : return "CLINIT"; //$NON-NLS-1$ |
| 685 | case IDelta.CONSTRUCTOR : return "CONSTRUCTOR"; //$NON-NLS-1$ |
| 686 | case IDelta.CONTRACTED_SUPERINTERFACES_SET : return "CONTRACTED_SUPERINTERFACES_SET"; //$NON-NLS-1$ |
| 687 | case IDelta.DECREASE_ACCESS : return "DECREASE_ACCESS"; //$NON-NLS-1$ |
| 688 | case IDelta.ENUM_CONSTANT : return "ENUM_CONSTANT"; //$NON-NLS-1$ |
| 689 | case IDelta.EXECUTION_ENVIRONMENT : return "EXECUTION_ENVIRONMENT"; //$NON-NLS-1$ |
| 690 | case IDelta.EXPANDED_SUPERINTERFACES_SET : return "EXPANDED_SUPERINTERFACES_SET"; //$NON-NLS-1$ |
| 691 | case IDelta.FIELD : return "FIELD"; //$NON-NLS-1$ |
| 692 | case IDelta.FIELD_MOVED_UP : return "FIELD_MOVED_UP"; //$NON-NLS-1$ |
| 693 | case IDelta.FINAL_TO_NON_FINAL : return "FINAL_TO_NON_FINAL"; //$NON-NLS-1$ |
| 694 | case IDelta.FINAL_TO_NON_FINAL_NON_STATIC : return "FINAL_TO_NON_FINAL_NON_STATIC"; //$NON-NLS-1$ |
| 695 | case IDelta.FINAL_TO_NON_FINAL_STATIC_CONSTANT : return "FINAL_TO_NON_FINAL_STATIC_CONSTANT"; //$NON-NLS-1$ |
| 696 | case IDelta.FINAL_TO_NON_FINAL_STATIC_NON_CONSTANT : return "FINAL_TO_NON_FINAL_STATIC_NON_CONSTANT"; //$NON-NLS-1$ |
| 697 | case IDelta.INCREASE_ACCESS : return "INCREASE_ACCESS"; //$NON-NLS-1$ |
| 698 | case IDelta.INTERFACE_BOUND : return "INTERFACE_BOUND"; //$NON-NLS-1$ |
| 699 | case IDelta.METHOD : return "METHOD"; //$NON-NLS-1$ |
| 700 | case IDelta.METHOD_MOVED_UP : return "METHOD_MOVED_UP"; //$NON-NLS-1$ |
| 701 | case IDelta.METHOD_WITH_DEFAULT_VALUE : return "METHOD_WITH_DEFAULT_VALUE"; //$NON-NLS-1$ |
| 702 | case IDelta.METHOD_WITHOUT_DEFAULT_VALUE : return "METHOD_WITHOUT_DEFAULT_VALUE"; //$NON-NLS-1$ |
| 703 | case IDelta.NATIVE_TO_NON_NATIVE : return "NATIVE_TO_NON_NATIVE"; //$NON-NLS-1$ |
| 704 | case IDelta.NON_ABSTRACT_TO_ABSTRACT : return "NON_ABSTRACT_TO_ABSTRACT"; //$NON-NLS-1$ |
| 705 | case IDelta.NON_FINAL_TO_FINAL : return "NON_FINAL_TO_FINAL"; //$NON-NLS-1$ |
| 706 | case IDelta.NON_NATIVE_TO_NATIVE : return "NON_NATIVE_TO_NATIVE"; //$NON-NLS-1$ |
| 707 | case IDelta.NON_STATIC_TO_STATIC : return "NON_STATIC_TO_STATIC"; //$NON-NLS-1$ |
| 708 | case IDelta.NON_SYNCHRONIZED_TO_SYNCHRONIZED : return "NON_SYNCHRONIZED_TO_SYNCHRONIZED"; //$NON-NLS-1$ |
| 709 | case IDelta.NON_TRANSIENT_TO_TRANSIENT : return "NON_TRANSIENT_TO_TRANSIENT"; //$NON-NLS-1$ |
| 710 | case IDelta.OVERRIDEN_METHOD : return "OVERRIDEN_METHOD"; //$NON-NLS-1$ |
| 711 | case IDelta.STATIC_TO_NON_STATIC : return "STATIC_TO_NON_STATIC"; //$NON-NLS-1$ |
| 712 | case IDelta.SUPERCLASS : return "SUPERCLASS"; //$NON-NLS-1$ |
| 713 | case IDelta.SYNCHRONIZED_TO_NON_SYNCHRONIZED : return "SYNCHRONIZED_TO_NON_SYNCHRONIZED"; //$NON-NLS-1$ |
| 714 | case IDelta.TYPE_CONVERSION : return "TYPE_CONVERSION"; //$NON-NLS-1$ |
| 715 | case IDelta.TRANSIENT_TO_NON_TRANSIENT : return "TRANSIENT_TO_NON_TRANSIENT"; //$NON-NLS-1$ |
| 716 | case IDelta.TYPE : return "TYPE"; //$NON-NLS-1$ |
| 717 | case IDelta.TYPE_ARGUMENTS : return "TYPE_ARGUMENTS"; //$NON-NLS-1$ |
| 718 | case IDelta.TYPE_MEMBER : return "TYPE_MEMBER"; //$NON-NLS-1$ |
| 719 | case IDelta.TYPE_PARAMETER : return "TYPE_PARAMETER"; //$NON-NLS-1$ |
| 720 | case IDelta.TYPE_PARAMETER_NAME : return "TYPE_PARAMETER_NAME"; //$NON-NLS-1$ |
| 721 | case IDelta.TYPE_PARAMETERS : return "TYPE_PARAMETERS"; //$NON-NLS-1$ |
| 722 | case IDelta.TYPE_VISIBILITY : return "TYPE_VISIBILITY"; //$NON-NLS-1$ |
| 723 | case IDelta.UNCHECKED_EXCEPTION : return "UNCHECKED_EXCEPTION"; //$NON-NLS-1$ |
| 724 | case IDelta.VALUE : return "VALUE"; //$NON-NLS-1$ |
| 725 | case IDelta.VARARGS_TO_ARRAY : return "VARARGS_TO_ARRAY"; //$NON-NLS-1$ |
| 726 | case IDelta.RESTRICTIONS : return "RESTRICTIONS"; //$NON-NLS-1$ |
| 727 | case IDelta.API_TYPE : return "API_TYPE"; //$NON-NLS-1$ |
| 728 | case IDelta.NON_VOLATILE_TO_VOLATILE : return "NON_VOLATILE_TO_VOLATILE"; //$NON-NLS-1$ |
| 729 | case IDelta.VOLATILE_TO_NON_VOLATILE : return "VOLATILE_TO_NON_VOLATILE"; //$NON-NLS-1$ |
| 730 | case IDelta.MINOR_VERSION : return "MINOR_VERSION"; //$NON-NLS-1$ |
| 731 | case IDelta.MAJOR_VERSION : return "MAJOR_VERSION"; //$NON-NLS-1$ |
| 732 | case IDelta.API_FIELD : return "API_FIELD"; //$NON-NLS-1$ |
| 733 | case IDelta.API_METHOD : return "API_METHOD"; //$NON-NLS-1$ |
| 734 | case IDelta.API_CONSTRUCTOR : return "API_CONSTRUCTOR"; //$NON-NLS-1$ |
| 735 | case IDelta.API_ENUM_CONSTANT : return "API_ENUM_CONSTANT"; //$NON-NLS-1$ |
| 736 | case IDelta.API_METHOD_WITH_DEFAULT_VALUE : return "API_METHOD_WITH_DEFAULT_VALUE"; //$NON-NLS-1$ |
| 737 | case IDelta.API_METHOD_WITHOUT_DEFAULT_VALUE : return "API_METHOD_WITHOUT_DEFAULT_VALUE"; //$NON-NLS-1$ |
| 738 | case IDelta.TYPE_ARGUMENT : return "TYPE_ARGUMENT"; //$NON-NLS-1$ |
| 739 | case IDelta.SUPER_INTERFACE_WITH_METHODS : return "SUPER_INTERFACE_WITH_METHODS"; //$NON-NLS-1$ |
| 740 | case IDelta.REEXPORTED_API_TYPE : return "REEXPORTED_API_TYPE"; //$NON-NLS-1$ |
| 741 | case IDelta.REEXPORTED_TYPE : return "REEXPORTED_TYPE"; //$NON-NLS-1$ |
| 742 | case IDelta.METHOD_MOVED_DOWN : return "METHOD_MOVED_DOWN"; //$NON-NLS-1$ |
| 743 | case IDelta.DEPRECATION : return "DEPRECATION"; //$NON-NLS-1$ |
| 744 | } |
| 745 | return UNKNOWN_FLAGS; |
| 746 | } |
| 747 | |
| 748 | /** |
| 749 | * Return a string that represents the kind of the given delta. |
| 750 | * Returns {@link #UNKNOWN_KIND} if the kind cannot be determined. |
| 751 | * |
| 752 | * @param delta the given delta |
| 753 | * @return a string that represents the kind of the given delta. |
| 754 | */ |
| 755 | public static String getDeltaKindName(IDelta delta) { |
| 756 | return getDeltaKindName(delta.getKind()); |
| 757 | } |
| 758 | |
| 759 | /** |
| 760 | * Return a string that represents the given kind. |
| 761 | * Returns {@link #UNKNOWN_KIND} if the kind cannot be determined. |
| 762 | * |
| 763 | * @param delta the given kind |
| 764 | * @return a string that represents the given kind. |
| 765 | */ |
| 766 | public static String getDeltaKindName(int kind) { |
| 767 | switch(kind) { |
| 768 | case IDelta.ADDED : |
| 769 | return "ADDED"; //$NON-NLS-1$ |
| 770 | case IDelta.CHANGED : |
| 771 | return "CHANGED"; //$NON-NLS-1$ |
| 772 | case IDelta.REMOVED : |
| 773 | return "REMOVED"; //$NON-NLS-1$ |
| 774 | } |
| 775 | return UNKNOWN_KIND; |
| 776 | } |
| 777 | |
| 778 | /** |
| 779 | * Returns the preference key for the given element type, the given kind and the given flags. |
| 780 | * |
| 781 | * @param elementType the given element type (retrieved using {@link IDelta#getElementType()} |
| 782 | * @param kind the given kind (retrieved using {@link IDelta#getKind()} |
| 783 | * @param flags the given flags (retrieved using {@link IDelta#getFlags()} |
| 784 | * @return the preference key for the given element type, the given kind and the given flags. |
| 785 | */ |
| 786 | public static String getDeltaPrefererenceKey(int elementType, int kind, int flags) { |
| 787 | StringBuffer buffer = new StringBuffer(Util.getDeltaElementType(elementType)); |
| 788 | buffer.append('_').append(Util.getDeltaKindName(kind)); |
| 789 | if (flags != -1) { |
| 790 | buffer.append('_'); |
| 791 | switch(flags) { |
| 792 | case IDelta.API_FIELD : |
| 793 | buffer.append(Util.getDeltaFlagsName(IDelta.FIELD)); |
| 794 | break; |
| 795 | case IDelta.API_ENUM_CONSTANT : |
| 796 | buffer.append(Util.getDeltaFlagsName(IDelta.ENUM_CONSTANT)); |
| 797 | break; |
| 798 | case IDelta.API_CONSTRUCTOR : |
| 799 | buffer.append(Util.getDeltaFlagsName(IDelta.CONSTRUCTOR)); |
| 800 | break; |
| 801 | case IDelta.API_METHOD : |
| 802 | buffer.append(Util.getDeltaFlagsName(IDelta.METHOD)); |
| 803 | break; |
| 804 | case IDelta.API_METHOD_WITH_DEFAULT_VALUE : |
| 805 | if (kind == IDelta.REMOVED) { |
| 806 | buffer.append(Util.getDeltaFlagsName(IDelta.METHOD)); |
| 807 | } else { |
| 808 | buffer.append(Util.getDeltaFlagsName(IDelta.METHOD_WITH_DEFAULT_VALUE)); |
| 809 | } |
| 810 | break; |
| 811 | case IDelta.API_METHOD_WITHOUT_DEFAULT_VALUE : |
| 812 | if (kind == IDelta.REMOVED) { |
| 813 | buffer.append(Util.getDeltaFlagsName(IDelta.METHOD)); |
| 814 | } else { |
| 815 | buffer.append(Util.getDeltaFlagsName(IDelta.METHOD_WITHOUT_DEFAULT_VALUE)); |
| 816 | } |
| 817 | break; |
| 818 | case IDelta.METHOD_WITH_DEFAULT_VALUE : |
| 819 | if (kind == IDelta.REMOVED) { |
| 820 | buffer.append(Util.getDeltaFlagsName(IDelta.METHOD)); |
| 821 | } else { |
| 822 | buffer.append(Util.getDeltaFlagsName(IDelta.METHOD_WITH_DEFAULT_VALUE)); |
| 823 | } |
| 824 | break; |
| 825 | case IDelta.METHOD_WITHOUT_DEFAULT_VALUE : |
| 826 | if (kind == IDelta.REMOVED) { |
| 827 | buffer.append(Util.getDeltaFlagsName(IDelta.METHOD)); |
| 828 | } else { |
| 829 | buffer.append(Util.getDeltaFlagsName(IDelta.METHOD_WITHOUT_DEFAULT_VALUE)); |
| 830 | } |
| 831 | break; |
| 832 | default: |
| 833 | buffer.append(Util.getDeltaFlagsName(flags)); |
| 834 | } |
| 835 | } |
| 836 | return String.valueOf(buffer); |
| 837 | } |
| 838 | |
| 839 | /** |
| 840 | * Returns the details of the api delta as a string |
| 841 | * @param delta |
| 842 | * @return the details of the delta as a string |
| 843 | */ |
| 844 | public static String getDetail(IDelta delta) { |
| 845 | StringBuffer buffer = new StringBuffer(); |
| 846 | switch(delta.getElementType()) { |
| 847 | case IDelta.CLASS_ELEMENT_TYPE : |
| 848 | buffer.append("class"); //$NON-NLS-1$ |
| 849 | break; |
| 850 | case IDelta.ANNOTATION_ELEMENT_TYPE : |
| 851 | buffer.append("annotation"); //$NON-NLS-1$ |
| 852 | break; |
| 853 | case IDelta.INTERFACE_ELEMENT_TYPE : |
| 854 | buffer.append("interface"); //$NON-NLS-1$ |
| 855 | break; |
| 856 | case IDelta.API_COMPONENT_ELEMENT_TYPE : |
| 857 | buffer.append("api component"); //$NON-NLS-1$ |
| 858 | break; |
| 859 | case IDelta.API_PROFILE_ELEMENT_TYPE : |
| 860 | buffer.append("api profile"); //$NON-NLS-1$ |
| 861 | break; |
| 862 | case IDelta.METHOD_ELEMENT_TYPE: |
| 863 | buffer.append("method"); //$NON-NLS-1$ |
| 864 | break; |
| 865 | case IDelta.CONSTRUCTOR_ELEMENT_TYPE : |
| 866 | buffer.append("constructor"); //$NON-NLS-1$ |
| 867 | break; |
| 868 | case IDelta.ENUM_ELEMENT_TYPE : |
| 869 | buffer.append("enum"); //$NON-NLS-1$ |
| 870 | break; |
| 871 | case IDelta.FIELD_ELEMENT_TYPE : |
| 872 | buffer.append("field"); //$NON-NLS-1$ |
| 873 | break; |
| 874 | } |
| 875 | buffer.append(' '); |
| 876 | switch(delta.getKind()) { |
| 877 | case IDelta.ADDED : |
| 878 | buffer.append("added"); //$NON-NLS-1$ |
| 879 | break; |
| 880 | case IDelta.REMOVED : |
| 881 | buffer.append("removed"); //$NON-NLS-1$ |
| 882 | break; |
| 883 | case IDelta.CHANGED : |
| 884 | buffer.append("changed"); //$NON-NLS-1$ |
| 885 | break; |
| 886 | default: |
| 887 | buffer.append("unknown kind"); //$NON-NLS-1$ |
| 888 | break; |
| 889 | } |
| 890 | buffer.append(' ').append(getDeltaFlagsName(delta.getFlags())).append(' ').append(delta.getTypeName()).append("#").append(delta.getKey()); //$NON-NLS-1$ |
| 891 | return String.valueOf(buffer); |
| 892 | } |
| 893 | |
| 894 | /** |
| 895 | * Returns the {@link IDocument} for the specified {@link ICompilationUnit} |
| 896 | * @param cu |
| 897 | * @return the {@link IDocument} for the specified {@link ICompilationUnit} |
| 898 | * @throws CoreException |
| 899 | */ |
| 900 | public static IDocument getDocument(ICompilationUnit cu) throws CoreException { |
| 901 | if (cu.getOwner() == null) { |
| 902 | IFile file= (IFile) cu.getResource(); |
| 903 | if (file.exists()) { |
| 904 | ITextFileBufferManager bufferManager= FileBuffers.getTextFileBufferManager(); |
| 905 | IPath path= cu.getPath(); |
| 906 | bufferManager.connect(path, LocationKind.IFILE, new NullProgressMonitor()); |
| 907 | try { |
| 908 | return bufferManager.getTextFileBuffer(path, LocationKind.IFILE).getDocument(); |
| 909 | } finally { |
| 910 | bufferManager.disconnect(path, LocationKind.IFILE, null); |
| 911 | } |
| 912 | } |
| 913 | } |
| 914 | return new org.eclipse.jface.text.Document(cu.getSource()); |
| 915 | } |
| 916 | |
| 917 | /** |
| 918 | * Returns the OSGi profile properties corresponding to the given execution |
| 919 | * environment id, or <code>null</code> if none. |
| 920 | * |
| 921 | * @param eeId OSGi profile identifier |
| 922 | * |
| 923 | * @return the corresponding properties or <code>null</code> if none |
| 924 | */ |
| 925 | public static Properties getEEProfile(String eeId) { |
| 926 | String profileName = eeId + ".profile"; //$NON-NLS-1$ |
| 927 | InputStream stream = Util.class.getResourceAsStream("profiles/" + profileName); //$NON-NLS-1$ |
| 928 | if (stream != null) { |
| 929 | try { |
| 930 | Properties profile = new Properties(); |
| 931 | profile.load(stream); |
| 932 | return profile; |
| 933 | } catch (IOException e) { |
| 934 | ApiPlugin.log(e); |
| 935 | } finally { |
| 936 | try { |
| 937 | stream.close(); |
| 938 | } catch(IOException e) { |
| 939 | ApiPlugin.log(e); |
| 940 | } |
| 941 | } |
| 942 | } |
| 943 | return null; |
| 944 | } |
| 945 | |
| 946 | /** |
| 947 | * Returns the number of fragments for the given version value, -1 if the format is unknown. |
| 948 | * The version is formed like: [optional plugin name] major.minor.micro.qualifier. |
| 949 | * |
| 950 | * @param version the given version value |
| 951 | * @return the number of fragments for the given version value or -1 if the format is unknown |
| 952 | * @throws IllegalArgumentException if version is null |
| 953 | */ |
| 954 | public static final int getFragmentNumber(String version) { |
| 955 | if (version == null) throw new IllegalArgumentException("The given version should not be null"); //$NON-NLS-1$ |
| 956 | int index = version.indexOf(' '); |
| 957 | char[] charArray = version.toCharArray(); |
| 958 | int length = charArray.length; |
| 959 | if (index + 1 >= length) { |
| 960 | return -1; |
| 961 | } |
| 962 | int counter = 1; |
| 963 | for (int i = index + 1; i < length; i++) { |
| 964 | switch(charArray[i]) { |
| 965 | case '0' : |
| 966 | case '1' : |
| 967 | case '2' : |
| 968 | case '3' : |
| 969 | case '4' : |
| 970 | case '5' : |
| 971 | case '6' : |
| 972 | case '7' : |
| 973 | case '8' : |
| 974 | case '9' : |
| 975 | continue; |
| 976 | case '.' : |
| 977 | counter++; |
| 978 | break; |
| 979 | default : |
| 980 | return -1; |
| 981 | } |
| 982 | } |
| 983 | return counter; |
| 984 | } |
| 985 | |
| 986 | public static IMember getIMember(IDelta delta, IJavaProject javaProject) { |
| 987 | String typeName = delta.getTypeName(); |
| 988 | if (typeName == null) return null; |
| 989 | IType type = null; |
| 990 | try { |
| 991 | type = javaProject.findType(typeName.replace('$', '.')); |
| 992 | } catch (JavaModelException e) { |
| 993 | // ignore |
| 994 | } |
| 995 | if (type == null) return null; |
| 996 | String key = delta.getKey(); |
| 997 | switch(delta.getElementType()) { |
| 998 | case IDelta.FIELD_ELEMENT_TYPE : { |
| 999 | IField field = type.getField(key); |
| 1000 | if (field.exists()) { |
| 1001 | return field; |
| 1002 | } |
| 1003 | } |
| 1004 | break; |
| 1005 | case IDelta.CLASS_ELEMENT_TYPE : |
| 1006 | case IDelta.ANNOTATION_ELEMENT_TYPE : |
| 1007 | case IDelta.INTERFACE_ELEMENT_TYPE : |
| 1008 | case IDelta.ENUM_ELEMENT_TYPE : |
| 1009 | // we report the marker on the type |
| 1010 | switch(delta.getKind()) { |
| 1011 | case IDelta.ADDED : |
| 1012 | switch(delta.getFlags()) { |
| 1013 | case IDelta.FIELD : |
| 1014 | case IDelta.ENUM_CONSTANT : |
| 1015 | IField field = type.getField(key); |
| 1016 | if (field.exists()) { |
| 1017 | return field; |
| 1018 | } |
| 1019 | break; |
| 1020 | case IDelta.METHOD_WITH_DEFAULT_VALUE : |
| 1021 | case IDelta.METHOD_WITHOUT_DEFAULT_VALUE : |
| 1022 | case IDelta.METHOD : |
| 1023 | case IDelta.CONSTRUCTOR : |
| 1024 | return getMethod(type, key); |
| 1025 | case IDelta.TYPE_MEMBER : |
| 1026 | IType type2 = type.getType(key); |
| 1027 | if (type2.exists()) { |
| 1028 | return type2; |
| 1029 | } |
| 1030 | } |
| 1031 | break; |
| 1032 | case IDelta.REMOVED : |
| 1033 | switch(delta.getFlags()) { |
| 1034 | case IDelta.API_FIELD : |
| 1035 | case IDelta.API_ENUM_CONSTANT : |
| 1036 | IField field = type.getField(key); |
| 1037 | if (field.exists()) { |
| 1038 | return field; |
| 1039 | } |
| 1040 | break; |
| 1041 | case IDelta.API_METHOD_WITH_DEFAULT_VALUE : |
| 1042 | case IDelta.API_METHOD_WITHOUT_DEFAULT_VALUE : |
| 1043 | case IDelta.API_METHOD : |
| 1044 | case IDelta.API_CONSTRUCTOR : |
| 1045 | return getMethod(type, key); |
| 1046 | } |
| 1047 | } |
| 1048 | return type; |
| 1049 | case IDelta.METHOD_ELEMENT_TYPE : |
| 1050 | case IDelta.CONSTRUCTOR_ELEMENT_TYPE : { |
| 1051 | return getMethod(type, key); |
| 1052 | } |
| 1053 | case IDelta.API_COMPONENT_ELEMENT_TYPE : |
| 1054 | return type; |
| 1055 | } |
| 1056 | return null; |
| 1057 | } |
| 1058 | |
| 1059 | /** |
| 1060 | * Updates a given progress monitor the given amount of work. |
| 1061 | * Throws an {@link OperationCanceledException} if the monitor has been canceled. |
| 1062 | * |
| 1063 | * @param monitor |
| 1064 | * @param work |
| 1065 | * @throws OperationCanceledException |
| 1066 | */ |
| 1067 | public static void updateMonitor(IProgressMonitor monitor, int work) throws OperationCanceledException { |
| 1068 | if(monitor == null) { |
| 1069 | return; |
| 1070 | } |
| 1071 | if(monitor.isCanceled()) { |
| 1072 | throw new OperationCanceledException(); |
| 1073 | } |
| 1074 | monitor.worked(work); |
| 1075 | } |
| 1076 | |
| 1077 | /** |
| 1078 | * Updates the given monitor 0 work ticks. This method is used to poll for cancellation |
| 1079 | * without advancing the work done. |
| 1080 | * |
| 1081 | * @param monitor |
| 1082 | * @throws OperationCanceledException |
| 1083 | */ |
| 1084 | public static void updateMonitor(IProgressMonitor monitor) throws OperationCanceledException { |
| 1085 | updateMonitor(monitor, 0); |
| 1086 | } |
| 1087 | |
| 1088 | private static IMember getMethod(IType type, String key) { |
| 1089 | boolean isGeneric = false; |
| 1090 | int indexOfTypeVariable = key.indexOf('<'); |
| 1091 | int index = 0; |
| 1092 | if (indexOfTypeVariable == -1) { |
| 1093 | int indexOfParen = key.indexOf('('); |
| 1094 | if (indexOfParen == -1) { |
| 1095 | return null; |
| 1096 | } |
| 1097 | index = indexOfParen; |
| 1098 | } else { |
| 1099 | int indexOfParen = key.indexOf('('); |
| 1100 | if (indexOfParen == -1) { |
| 1101 | return null; |
| 1102 | } |
| 1103 | if (indexOfParen < indexOfTypeVariable) { |
| 1104 | index = indexOfParen; |
| 1105 | } else { |
| 1106 | index = indexOfTypeVariable; |
| 1107 | isGeneric = true; |
| 1108 | } |
| 1109 | } |
| 1110 | String selector = key.substring(0, index); |
| 1111 | String descriptor = key.substring(index, key.length()); |
| 1112 | IMethod method = null; |
| 1113 | String signature = descriptor.replace('/', '.'); |
| 1114 | String[] parameterTypes = null; |
| 1115 | if (isGeneric) { |
| 1116 | // remove all type variables first |
| 1117 | signature = signature.substring(signature.indexOf('(')); |
| 1118 | parameterTypes = Signature.getParameterTypes(signature); |
| 1119 | } else { |
| 1120 | parameterTypes = Signature.getParameterTypes(signature); |
| 1121 | } |
| 1122 | |
| 1123 | try { |
| 1124 | method = type.getMethod(selector, parameterTypes); |
| 1125 | } catch (IllegalArgumentException e) { |
| 1126 | ApiPlugin.log(e); |
| 1127 | } |
| 1128 | if (method == null) { |
| 1129 | return null; |
| 1130 | } |
| 1131 | if (method.exists()) { |
| 1132 | return method; |
| 1133 | } else { |
| 1134 | // if the method is not null and it doesn't exist, it might be the default constructor |
| 1135 | if (selector.equals(type.getElementName()) && parameterTypes.length == 0) { |
| 1136 | return null; |
| 1137 | } |
| 1138 | // try to check by selector |
| 1139 | IMethod[] methods = null; |
| 1140 | try { |
| 1141 | methods = type.getMethods(); |
| 1142 | } catch (JavaModelException e) { |
| 1143 | ApiPlugin.log(e); |
| 1144 | // do not default to the enclosing type - see bug 224713 |
| 1145 | ApiPlugin.log( |
| 1146 | new Status(IStatus.ERROR, |
| 1147 | ApiPlugin.PLUGIN_ID, |
| 1148 | NLS.bind(UtilMessages.Util_6, new String[] { selector, descriptor }))); |
| 1149 | return null; |
| 1150 | } |
| 1151 | List list = new ArrayList(); |
| 1152 | for (int i = 0, max = methods.length; i < max; i++) { |
| 1153 | IMethod method2 = methods[i]; |
| 1154 | if (selector.equals(method2.getElementName())) { |
| 1155 | list.add(method2); |
| 1156 | } |
| 1157 | } |
| 1158 | switch(list.size()) { |
| 1159 | case 0 : |
| 1160 | // do not default to the enclosing type - see bug 224713 |
| 1161 | ApiPlugin.log( |
| 1162 | new Status(IStatus.ERROR, |
| 1163 | ApiPlugin.PLUGIN_ID, |
| 1164 | NLS.bind(UtilMessages.Util_6, new String[] { selector, descriptor }))); |
| 1165 | return null; |
| 1166 | case 1 : |
| 1167 | return (IMember) list.get(0); |
| 1168 | default: |
| 1169 | // need to find a matching parameters |
| 1170 | for (Iterator iterator = list.iterator(); iterator.hasNext(); ) { |
| 1171 | IMethod method2 = (IMethod) iterator.next(); |
| 1172 | try { |
| 1173 | if (Signatures.matchesSignatures(method2.getSignature(), signature)) { |
| 1174 | return method2; |
| 1175 | } |
| 1176 | } catch (JavaModelException e) { |
| 1177 | // ignore |
| 1178 | } |
| 1179 | } |
| 1180 | } |
| 1181 | } |
| 1182 | // do not default to the enclosing type - see bug 224713 |
| 1183 | ApiPlugin.log( |
| 1184 | new Status(IStatus.ERROR, |
| 1185 | ApiPlugin.PLUGIN_ID, |
| 1186 | NLS.bind(UtilMessages.Util_6, new String[] { selector, descriptor }))); |
| 1187 | return null; |
| 1188 | } |
| 1189 | |
| 1190 | /** |
| 1191 | * Returns the given input stream as a byte array |
| 1192 | * @param stream the stream to get as a byte array |
| 1193 | * @param length the length to read from the stream or -1 for unknown |
| 1194 | * @return the given input stream as a byte array |
| 1195 | * @throws IOException |
| 1196 | */ |
| 1197 | public static byte[] getInputStreamAsByteArray(InputStream stream, int length) throws IOException { |
| 1198 | byte[] contents; |
| 1199 | if (length == -1) { |
| 1200 | contents = new byte[0]; |
| 1201 | int contentsLength = 0; |
| 1202 | int amountRead = -1; |
| 1203 | do { |
| 1204 | // read at least 8K |
| 1205 | int amountRequested = Math.max(stream.available(), DEFAULT_READING_SIZE); |
| 1206 | // resize contents if needed |
| 1207 | if (contentsLength + amountRequested > contents.length) { |
| 1208 | System.arraycopy(contents, |
| 1209 | 0, |
| 1210 | contents = new byte[contentsLength + amountRequested], |
| 1211 | 0, |
| 1212 | contentsLength); |
| 1213 | } |
| 1214 | // read as many bytes as possible |
| 1215 | amountRead = stream.read(contents, contentsLength, amountRequested); |
| 1216 | if (amountRead > 0) { |
| 1217 | // remember length of contents |
| 1218 | contentsLength += amountRead; |
| 1219 | } |
| 1220 | } while (amountRead != -1); |
| 1221 | // resize contents if necessary |
| 1222 | if (contentsLength < contents.length) { |
| 1223 | System.arraycopy(contents, 0, contents = new byte[contentsLength], 0, contentsLength); |
| 1224 | } |
| 1225 | } else { |
| 1226 | contents = new byte[length]; |
| 1227 | int len = 0; |
| 1228 | int readSize = 0; |
| 1229 | while ((readSize != -1) && (len != length)) { |
| 1230 | // See PR 1FMS89U |
| 1231 | // We record first the read size. In this case length is the actual |
| 1232 | // read size. |
| 1233 | len += readSize; |
| 1234 | readSize = stream.read(contents, len, length - len); |
| 1235 | } |
| 1236 | } |
| 1237 | return contents; |
| 1238 | } |
| 1239 | |
| 1240 | /** |
| 1241 | * Returns the given input stream's contents as a character array. |
| 1242 | * If a length is specified (i.e. if length != -1), this represents the number of bytes in the stream. |
| 1243 | * Note the specified stream is not closed in this method |
| 1244 | * @param stream the stream to get convert to the char array |
| 1245 | * @param length the length of the input stream, or -1 if unknown |
| 1246 | * @param encoding the encoding to use when reading the stream |
| 1247 | * @return the given input stream's contents as a character array. |
| 1248 | * @throws IOException if a problem occurred reading the stream. |
| 1249 | */ |
| 1250 | public static char[] getInputStreamAsCharArray(InputStream stream, int length, String encoding) throws IOException { |
| 1251 | Charset charset = null; |
| 1252 | try { |
| 1253 | charset = Charset.forName(encoding); |
| 1254 | } catch (IllegalCharsetNameException e) { |
| 1255 | System.err.println("Illegal charset name : " + encoding); //$NON-NLS-1$ |
| 1256 | return null; |
| 1257 | } catch(UnsupportedCharsetException e) { |
| 1258 | System.err.println("Unsupported charset : " + encoding); //$NON-NLS-1$ |
| 1259 | return null; |
| 1260 | } |
| 1261 | CharsetDecoder charsetDecoder = charset.newDecoder(); |
| 1262 | charsetDecoder.onMalformedInput(CodingErrorAction.REPLACE).onUnmappableCharacter(CodingErrorAction.REPLACE); |
| 1263 | byte[] contents = getInputStreamAsByteArray(stream, length); |
| 1264 | ByteBuffer byteBuffer = ByteBuffer.allocate(contents.length); |
| 1265 | byteBuffer.put(contents); |
| 1266 | byteBuffer.flip(); |
| 1267 | return charsetDecoder.decode(byteBuffer).array(); |
| 1268 | } |
| 1269 | |
| 1270 | /** |
| 1271 | * Tries to find the 'MANIFEST.MF' file with in the given project in the |
| 1272 | * 'META-INF folder'. |
| 1273 | * |
| 1274 | * @param currentProject |
| 1275 | * @return a handle to the manifest file or <code>null</code> if not found |
| 1276 | */ |
| 1277 | public static IResource getManifestFile(IProject currentProject) { |
| 1278 | return currentProject.findMember("META-INF/MANIFEST.MF"); //$NON-NLS-1$ |
| 1279 | } |
| 1280 | |
| 1281 | /** |
| 1282 | * Returns if the given {@link IMarker} is representing an {@link org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem} |
| 1283 | * or not |
| 1284 | * @param marker the marker to check |
| 1285 | * @return true if the marker is for an {@link org.eclipse.pde.api.tools.internal.provisional.problems.IApiProblem} false otherwise |
| 1286 | * @throws CoreException |
| 1287 | */ |
| 1288 | public static boolean isApiProblemMarker(IMarker marker) { |
| 1289 | return marker.getAttribute(IApiMarkerConstants.API_MARKER_ATTR_ID, -1) > 0; |
| 1290 | } |
| 1291 | |
| 1292 | /** |
| 1293 | * Returns a reference type for the given fully qualified type name. |
| 1294 | * |
| 1295 | * @param fullyQualifiedName type name |
| 1296 | * @return reference type |
| 1297 | */ |
| 1298 | public static IReferenceTypeDescriptor getType(String fullyQualifiedName) { |
| 1299 | int index = fullyQualifiedName.lastIndexOf('.'); |
| 1300 | String pkg = index == -1 ? DEFAULT_PACKAGE_NAME : fullyQualifiedName.substring(0, index); |
| 1301 | String type = index == -1 ? fullyQualifiedName : fullyQualifiedName.substring(index + 1); |
| 1302 | return Factory.packageDescriptor(pkg).getType(type); |
| 1303 | } |
| 1304 | /** |
| 1305 | * Returns if the given project is API enabled |
| 1306 | * @param project |
| 1307 | * @return true if the project is API enabled, false otherwise |
| 1308 | */ |
| 1309 | public static boolean isApiProject(IProject project) { |
| 1310 | try { |
| 1311 | return project.hasNature(ApiPlugin.NATURE_ID); |
| 1312 | } catch (CoreException e) { |
| 1313 | return false; |
| 1314 | } |
| 1315 | } |
| 1316 | |
| 1317 | /** |
| 1318 | * Returns if the given project is API enabled |
| 1319 | * @param project |
| 1320 | * @return true if the project is API enabled, false otherwise |
| 1321 | */ |
| 1322 | public static boolean isApiProject(IJavaProject project) { |
| 1323 | return isApiProject(project.getProject()); |
| 1324 | } |
| 1325 | |
| 1326 | /** |
| 1327 | * Returns if the given {@link IApiComponent} is a valid {@link IApiComponent} |
| 1328 | * @param apiComponent |
| 1329 | * @return true if the given {@link IApiComponent} is valid, false otherwise |
| 1330 | */ |
| 1331 | public static boolean isApiToolsComponent(IApiComponent apiComponent) { |
| 1332 | File file = new File(apiComponent.getLocation()); |
| 1333 | if (file.exists()) { |
| 1334 | if (file.isDirectory()) { |
| 1335 | // directory binary bundle |
| 1336 | File apiDescription = new File(file, IApiCoreConstants.API_DESCRIPTION_XML_NAME); |
| 1337 | return apiDescription.exists(); |
| 1338 | } |
| 1339 | ZipFile zipFile = null; |
| 1340 | try { |
| 1341 | zipFile = new ZipFile(file); |
| 1342 | return zipFile.getEntry(IApiCoreConstants.API_DESCRIPTION_XML_NAME) != null; |
| 1343 | } catch (ZipException e) { |
| 1344 | // ignore |
| 1345 | } catch (IOException e) { |
| 1346 | // ignore |
| 1347 | } finally { |
| 1348 | try { |
| 1349 | if (zipFile != null) zipFile.close(); |
| 1350 | } catch (IOException e) { |
| 1351 | // ignore |
| 1352 | } |
| 1353 | } |
| 1354 | } |
| 1355 | return false; |
| 1356 | } |
| 1357 | |
| 1358 | /** |
| 1359 | * Returns if the specified file name is an archive name. A name is |
| 1360 | * considered to be an archive name if it ends with either '.zip' or '.jar' |
| 1361 | * |
| 1362 | * @param fileName |
| 1363 | * @return true if the file name is an archive name false otherwise |
| 1364 | */ |
| 1365 | public static boolean isArchive(String fileName) { |
| 1366 | String normalizedFileName = fileName.toLowerCase(); |
| 1367 | return normalizedFileName.endsWith(".zip") || normalizedFileName.endsWith(".jar"); //$NON-NLS-1$ //$NON-NLS-2$ |
| 1368 | } |
| 1369 | |
| 1370 | /** |
| 1371 | * Returns if the flags are for a class |
| 1372 | * @param accessFlags |
| 1373 | * @return |
| 1374 | */ |
| 1375 | public static boolean isClass(int accessFlags) { |
| 1376 | return (accessFlags & (Opcodes.ACC_ENUM | Opcodes.ACC_ANNOTATION | Opcodes.ACC_INTERFACE)) == 0; |
| 1377 | } |
| 1378 | |
| 1379 | /** |
| 1380 | * Returns if the specified file name is for a class file. A name is |
| 1381 | * considered to be a class file if it ends in '.class' |
| 1382 | * |
| 1383 | * @param fileName |
| 1384 | * @return true if the name is for a class file false otherwise |
| 1385 | */ |
| 1386 | public static boolean isClassFile(String fileName) { |
| 1387 | return fileName.toLowerCase().endsWith(DOT_CLASS_SUFFIX); |
| 1388 | } |
| 1389 | |
| 1390 | public static boolean isDefault(int accessFlags) { |
| 1391 | // none of the private, protected or public bit is set |
| 1392 | return (accessFlags & (Opcodes.ACC_PRIVATE |
| 1393 | | Opcodes.ACC_PROTECTED |
| 1394 | | Opcodes.ACC_PUBLIC)) == 0; |
| 1395 | } |
| 1396 | |
| 1397 | public static final boolean isDifferentVersion(String versionToBeChecked, String referenceVersion) { |
| 1398 | SinceTagVersion sinceTagVersion1 = null; |
| 1399 | SinceTagVersion sinceTagVersion2 = null; |
| 1400 | try { |
| 1401 | sinceTagVersion1 = new SinceTagVersion(versionToBeChecked); |
| 1402 | sinceTagVersion2 = new SinceTagVersion(referenceVersion); |
| 1403 | } catch (IllegalArgumentException e) { |
| 1404 | // We cannot compare the two versions as their format is unknown |
| 1405 | // TODO (olivier) should we report these as malformed tags? |
| 1406 | return false; |
| 1407 | } |
| 1408 | Version version1 = sinceTagVersion1.getVersion(); |
| 1409 | Version version2 = sinceTagVersion2.getVersion(); |
| 1410 | if (version1.getMajor() != version2.getMajor()) { |
| 1411 | return true; |
| 1412 | } |
| 1413 | if (version1.getMinor() != version2.getMinor()) { |
| 1414 | return true; |
| 1415 | } |
| 1416 | if (version1.getMicro() != version2.getMicro()) { |
| 1417 | return true; |
| 1418 | } |
| 1419 | return false; |
| 1420 | } |
| 1421 | |
| 1422 | /** |
| 1423 | * Returns if the specified file name is for a java source file. A name is |
| 1424 | * considered to be a java source file if it ends in '.java' |
| 1425 | * |
| 1426 | * @param fileName |
| 1427 | * @return true if the name is for a java source file, false otherwise |
| 1428 | */ |
| 1429 | public static boolean isJavaFileName(String fileName) { |
| 1430 | return fileName.toLowerCase().endsWith(DOT_JAVA_SUFFIX); |
| 1431 | } |
| 1432 | |
| 1433 | /** |
| 1434 | * Returns if the given name is {@link java.lang.Object} |
| 1435 | * @param name |
| 1436 | * @return true if the name is java.lang.Object, false otherwise |
| 1437 | */ |
| 1438 | public static boolean isJavaLangObject(String name) { |
| 1439 | return name != null && name.equals(JAVA_LANG_OBJECT); |
| 1440 | } |
| 1441 | |
| 1442 | /** |
| 1443 | * Return if the name is {@link java.lang.RuntimeException} |
| 1444 | * @param name |
| 1445 | * @return true if the name is java.lang.RuntimeException, false otherwise |
| 1446 | */ |
| 1447 | public static boolean isJavaLangRuntimeException(String name) { |
| 1448 | return name != null && name.equals(JAVA_LANG_RUNTIMEEXCEPTION); |
| 1449 | } |
| 1450 | public static boolean isVisible(int modifiers) { |
| 1451 | return Flags.isProtected(modifiers) || Flags.isPublic(modifiers); |
| 1452 | } |
| 1453 | public static boolean isBinaryProject(IProject project) { |
| 1454 | return org.eclipse.pde.internal.core.WorkspaceModelManager.isBinaryProject(project); |
| 1455 | } |
| 1456 | /** |
| 1457 | * Returns a new XML document. |
| 1458 | * |
| 1459 | * @return document |
| 1460 | * @throws CoreException if unable to create a new document |
| 1461 | */ |
| 1462 | public static Document newDocument() throws CoreException { |
| 1463 | DocumentBuilderFactory dfactory= DocumentBuilderFactory.newInstance(); |
| 1464 | DocumentBuilder docBuilder = null; |
| 1465 | try { |
| 1466 | docBuilder = dfactory.newDocumentBuilder(); |
| 1467 | } catch (ParserConfigurationException e) { |
| 1468 | abort("Unable to create new XML document.", e); //$NON-NLS-1$ |
| 1469 | } |
| 1470 | Document doc= docBuilder.newDocument(); |
| 1471 | return doc; |
| 1472 | } |
| 1473 | |
| 1474 | /** |
| 1475 | * Parses the given string representing an XML document, returning its |
| 1476 | * root element. |
| 1477 | * |
| 1478 | * @param document XML document as a string |
| 1479 | * @return the document's root element |
| 1480 | * @throws CoreException if unable to parse the document |
| 1481 | */ |
| 1482 | public static Element parseDocument(String document) throws CoreException { |
| 1483 | Element root = null; |
| 1484 | InputStream stream = null; |
| 1485 | try{ |
| 1486 | DocumentBuilder parser = DocumentBuilderFactory.newInstance().newDocumentBuilder(); |
| 1487 | parser.setErrorHandler(new DefaultHandler()); |
| 1488 | stream = new ByteArrayInputStream(document.getBytes()); |
| 1489 | root = parser.parse(stream).getDocumentElement(); |
| 1490 | } catch (ParserConfigurationException e) { |
| 1491 | abort("Unable to parse XML document.", e); //$NON-NLS-1$ |
| 1492 | } catch (FactoryConfigurationError e) { |
| 1493 | abort("Unable to parse XML document.", e); //$NON-NLS-1$ |
| 1494 | } catch (SAXException e) { |
| 1495 | abort("Unable to parse XML document.", e); //$NON-NLS-1$ |
| 1496 | } catch (IOException e) { |
| 1497 | abort("Unable to parse XML document.", e); //$NON-NLS-1$ |
| 1498 | } finally { |
| 1499 | try{ |
| 1500 | if (stream != null) { |
| 1501 | stream.close(); |
| 1502 | } |
| 1503 | } catch(IOException e) { |
| 1504 | abort("Unable to parse XML document.", e); //$NON-NLS-1$ |
| 1505 | } |
| 1506 | } |
| 1507 | return root; |
| 1508 | } |
| 1509 | |
| 1510 | /** |
| 1511 | * Save the given contents into the given file. The file parent folder must exist. |
| 1512 | * |
| 1513 | * @param file the given file target |
| 1514 | * @param contents the given contents |
| 1515 | * @throws IOException if an IOException occurs while saving the file |
| 1516 | */ |
| 1517 | public static void saveFile(File file, String contents) throws IOException { |
| 1518 | BufferedWriter writer = null; |
| 1519 | try { |
| 1520 | writer = new BufferedWriter(new FileWriter(file)); |
| 1521 | writer.write(contents); |
| 1522 | writer.flush(); |
| 1523 | } finally { |
| 1524 | if (writer != null) { |
| 1525 | try { |
| 1526 | writer.close(); |
| 1527 | } catch(IOException e) { |
| 1528 | // ignore |
| 1529 | } |
| 1530 | } |
| 1531 | } |
| 1532 | } |
| 1533 | |
| 1534 | /** |
| 1535 | * Returns the contents of the given file as a string, or <code>null</code> |
| 1536 | * @param file the file to get the contents for |
| 1537 | * @return the contents of the file as a {@link String} or <code>null</code> |
| 1538 | */ |
| 1539 | public static String getFileContentAsString(File file) { |
| 1540 | String contents = null; |
| 1541 | FileInputStream stream = null; |
| 1542 | try { |
| 1543 | stream = new FileInputStream(file); |
| 1544 | char[] array = getInputStreamAsCharArray(stream, -1, IApiCoreConstants.UTF_8); |
| 1545 | contents = new String(array); |
| 1546 | } |
| 1547 | catch(IOException ioe) { |
| 1548 | ApiPlugin.log(ioe); |
| 1549 | } finally { |
| 1550 | if (stream != null) { |
| 1551 | try { |
| 1552 | stream.close(); |
| 1553 | } catch (IOException e) { |
| 1554 | // ignore |
| 1555 | } |
| 1556 | } |
| 1557 | } |
| 1558 | return contents; |
| 1559 | } |
| 1560 | |
| 1561 | /** |
| 1562 | * Returns the given string as an {@link InputStream}. It is up to the caller to close |
| 1563 | * the new stream. |
| 1564 | * @param string the string to convert |
| 1565 | * @return the {@link InputStream} for the given string |
| 1566 | */ |
| 1567 | public static InputStream getInputStreamFromString(String string) { |
| 1568 | try { |
| 1569 | return new ByteArrayInputStream(string.getBytes(IApiCoreConstants.UTF_8)); |
| 1570 | } |
| 1571 | catch(UnsupportedEncodingException uee) { |
| 1572 | ApiPlugin.log(uee); |
| 1573 | } |
| 1574 | return null; |
| 1575 | } |
| 1576 | |
| 1577 | /** |
| 1578 | * Serializes the given XML document into a UTF-8 string. |
| 1579 | * |
| 1580 | * @param document XML document to serialize |
| 1581 | * @return a string representing the given document |
| 1582 | * @throws CoreException if unable to serialize the document |
| 1583 | */ |
| 1584 | public static String serializeDocument(Document document) throws CoreException { |
| 1585 | try { |
| 1586 | ByteArrayOutputStream s = new ByteArrayOutputStream(); |
| 1587 | TransformerFactory factory = TransformerFactory.newInstance(); |
| 1588 | Transformer transformer = factory.newTransformer(); |
| 1589 | transformer.setOutputProperty(OutputKeys.METHOD, "xml"); //$NON-NLS-1$ |
| 1590 | transformer.setOutputProperty(OutputKeys.INDENT, "yes"); //$NON-NLS-1$ |
| 1591 | transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount","4"); //$NON-NLS-1$ //$NON-NLS-2$ |
| 1592 | DOMSource source = new DOMSource(document); |
| 1593 | StreamResult outputTarget = new StreamResult(s); |
| 1594 | transformer.transform(source, outputTarget); |
| 1595 | return s.toString(IApiCoreConstants.UTF_8); |
| 1596 | } catch (TransformerException e) { |
| 1597 | abort("Unable to serialize XML document.", e); //$NON-NLS-1$ |
| 1598 | } catch (IOException e) { |
| 1599 | abort("Unable to serialize XML document.",e); //$NON-NLS-1$ |
| 1600 | } |
| 1601 | return null; |
| 1602 | } |
| 1603 | /** |
| 1604 | * Unzip the contents of the given zip in the given directory (create it if it doesn't exist) |
| 1605 | */ |
| 1606 | public static void unzip(String zipPath, String destDirPath) throws IOException { |
| 1607 | InputStream zipIn = new FileInputStream(zipPath); |
| 1608 | byte[] buf = new byte[8192]; |
| 1609 | File destDir = new File(destDirPath); |
| 1610 | ZipInputStream zis = new ZipInputStream(new BufferedInputStream(zipIn)); |
| 1611 | BufferedOutputStream outputStream = null; |
| 1612 | try { |
| 1613 | ZipEntry zEntry; |
| 1614 | while ((zEntry = zis.getNextEntry()) != null) { |
| 1615 | // if it is empty directory, create it |
| 1616 | if (zEntry.isDirectory()) { |
| 1617 | new File(destDir, zEntry.getName()).mkdirs(); |
| 1618 | continue; |
| 1619 | } |
| 1620 | // if it is a file, extract it |
| 1621 | String filePath = zEntry.getName(); |
| 1622 | int lastSeparator = filePath.lastIndexOf("/"); //$NON-NLS-1$ |
| 1623 | String fileDir = ""; //$NON-NLS-1$ |
| 1624 | if (lastSeparator >= 0) { |
| 1625 | fileDir = filePath.substring(0, lastSeparator); |
| 1626 | } |
| 1627 | //create directory for a file |
| 1628 | new File(destDir, fileDir).mkdirs(); |
| 1629 | //write file |
| 1630 | File outFile = new File(destDir, filePath); |
| 1631 | outputStream = new BufferedOutputStream(new FileOutputStream(outFile)); |
| 1632 | int n = 0; |
| 1633 | while ((n = zis.read(buf)) >= 0) { |
| 1634 | outputStream.write(buf, 0, n); |
| 1635 | } |
| 1636 | outputStream.close(); |
| 1637 | } |
| 1638 | } catch (IOException ioe) { |
| 1639 | if (outputStream != null) { |
| 1640 | try { |
| 1641 | outputStream.close(); |
| 1642 | } catch (IOException ioe2) { |
| 1643 | } |
| 1644 | } |
| 1645 | } finally { |
| 1646 | try { |
| 1647 | zipIn.close(); |
| 1648 | zis.close(); |
| 1649 | } catch (IOException ioe) { |
| 1650 | } |
| 1651 | } |
| 1652 | } |
| 1653 | /** |
| 1654 | * Unzip the contents of the given zip in the given directory (create it if it doesn't exist) |
| 1655 | */ |
| 1656 | public static void guntar(String zipPath, String destDirPath) throws TarException, IOException { |
| 1657 | TarFile tarFile = new TarFile(zipPath); |
| 1658 | Enumeration entries = tarFile.entries(); |
| 1659 | byte[] buf = new byte[8192]; |
| 1660 | for (;entries.hasMoreElements(); ) { |
| 1661 | TarEntry zEntry; |
| 1662 | while ((zEntry = (TarEntry) entries.nextElement()) != null) { |
| 1663 | // if it is empty directory, create it |
| 1664 | if (zEntry.getFileType() == TarEntry.DIRECTORY) { |
| 1665 | new File(destDirPath, zEntry.getName()).mkdirs(); |
| 1666 | continue; |
| 1667 | } |
| 1668 | // if it is a file, extract it |
| 1669 | String filePath = zEntry.getName(); |
| 1670 | int lastSeparator = filePath.lastIndexOf("/"); //$NON-NLS-1$ |
| 1671 | String fileDir = ""; //$NON-NLS-1$ |
| 1672 | if (lastSeparator >= 0) { |
| 1673 | fileDir = filePath.substring(0, lastSeparator); |
| 1674 | } |
| 1675 | //create directory for a file |
| 1676 | new File(destDirPath, fileDir).mkdirs(); |
| 1677 | //write file |
| 1678 | File outFile = new File(destDirPath, filePath); |
| 1679 | BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(outFile)); |
| 1680 | int n = 0; |
| 1681 | InputStream inputStream = tarFile.getInputStream(zEntry); |
| 1682 | BufferedInputStream stream = new BufferedInputStream(inputStream); |
| 1683 | while ((n = stream.read(buf)) >= 0) { |
| 1684 | outputStream.write(buf, 0, n); |
| 1685 | } |
| 1686 | outputStream.close(); |
| 1687 | stream.close(); |
| 1688 | } |
| 1689 | } |
| 1690 | } |
| 1691 | /** |
| 1692 | * Gets the .ee file supplied to run tests based on system |
| 1693 | * property. |
| 1694 | * |
| 1695 | * @return |
| 1696 | */ |
| 1697 | public static File getEEDescriptionFile() { |
| 1698 | // generate a fake 1.6 ee file |
| 1699 | File fakeEEFile = null; |
| 1700 | PrintWriter writer = null; |
| 1701 | try { |
| 1702 | fakeEEFile = File.createTempFile("eefile", ".ee"); //$NON-NLS-1$ //$NON-NLS-2$ |
| 1703 | fakeEEFile.deleteOnExit(); |
| 1704 | writer = new PrintWriter(new BufferedWriter(new FileWriter(fakeEEFile))); |
| 1705 | writer.print("-Djava.home="); //$NON-NLS-1$ |
| 1706 | writer.println(System.getProperty("java.home")); //$NON-NLS-1$ |
| 1707 | writer.print("-Dee.bootclasspath="); //$NON-NLS-1$ |
| 1708 | writer.println(getJavaClassLibsAsString()); |
| 1709 | writer.println("-Dee.language.level=1.6"); //$NON-NLS-1$ |
| 1710 | writer.println("-Dee.class.library.level=JavaSE-1.6"); //$NON-NLS-1$ |
| 1711 | writer.flush(); |
| 1712 | } catch (IOException e) { |
| 1713 | // ignore |
| 1714 | } finally { |
| 1715 | if (writer != null) { |
| 1716 | writer.close(); |
| 1717 | } |
| 1718 | } |
| 1719 | return fakeEEFile; |
| 1720 | } |
| 1721 | |
| 1722 | /** |
| 1723 | * @return a string representation of all of the libraries from the bootpath |
| 1724 | * of the current default system VM. |
| 1725 | */ |
| 1726 | public static String getJavaClassLibsAsString() { |
| 1727 | String[] libs = Util.getJavaClassLibs(); |
| 1728 | StringBuffer buffer = new StringBuffer(); |
| 1729 | for (int i = 0, max = libs.length; i < max; i++) { |
| 1730 | if (i > 0) { |
| 1731 | buffer.append(File.pathSeparatorChar); |
| 1732 | } |
| 1733 | buffer.append(libs[i]); |
| 1734 | } |
| 1735 | return String.valueOf(buffer); |
| 1736 | } |
| 1737 | |
| 1738 | /** |
| 1739 | * @return an array of the library names from the bootpath of the current default system VM |
| 1740 | */ |
| 1741 | public static String[] getJavaClassLibs() { |
| 1742 | // check bootclasspath properties for Sun, JRockit and Harmony VMs |
| 1743 | String bootclasspathProperty = System.getProperty("sun.boot.class.path"); //$NON-NLS-1$ |
| 1744 | if ((bootclasspathProperty == null) || (bootclasspathProperty.length() == 0)) { |
| 1745 | // IBM J9 VMs |
| 1746 | bootclasspathProperty = System.getProperty("vm.boot.class.path"); //$NON-NLS-1$ |
| 1747 | if ((bootclasspathProperty == null) || (bootclasspathProperty.length() == 0)) { |
| 1748 | // Harmony using IBM VME |
| 1749 | bootclasspathProperty = System.getProperty("org.apache.harmony.boot.class.path"); //$NON-NLS-1$ |
| 1750 | } |
| 1751 | } |
| 1752 | String[] jars = null; |
| 1753 | if ((bootclasspathProperty != null) && (bootclasspathProperty.length() != 0)) { |
| 1754 | StringTokenizer tokenizer = new StringTokenizer(bootclasspathProperty, File.pathSeparator); |
| 1755 | final int size = tokenizer.countTokens(); |
| 1756 | jars = new String[size]; |
| 1757 | int i = 0; |
| 1758 | while (tokenizer.hasMoreTokens()) { |
| 1759 | final String fileName = toNativePath(tokenizer.nextToken()); |
| 1760 | if (new File(fileName).exists()) { |
| 1761 | jars[i] = fileName; |
| 1762 | i++; |
| 1763 | } |
| 1764 | } |
| 1765 | if (size != i) { |
| 1766 | // resize |
| 1767 | System.arraycopy(jars, 0, (jars = new String[i]), 0, i); |
| 1768 | } |
| 1769 | } else { |
| 1770 | String jreDir = System.getProperty("java.home"); //$NON-NLS-1$ |
| 1771 | final String osName = System.getProperty("os.name"); //$NON-NLS-1$ |
| 1772 | if (jreDir == null) { |
| 1773 | return new String[] {}; |
| 1774 | } |
| 1775 | if (osName.startsWith("Mac")) { //$NON-NLS-1$ |
| 1776 | return new String[] { |
| 1777 | toNativePath(jreDir + "/../Classes/classes.jar") //$NON-NLS-1$ |
| 1778 | }; |
| 1779 | } |
| 1780 | final String vmName = System.getProperty("java.vm.name"); //$NON-NLS-1$ |
| 1781 | if ("J9".equals(vmName)) { //$NON-NLS-1$ |
| 1782 | return new String[] { |
| 1783 | toNativePath(jreDir + "/lib/jclMax/classes.zip") //$NON-NLS-1$ |
| 1784 | }; |
| 1785 | } |
| 1786 | String[] jarsNames = null; |
| 1787 | ArrayList paths = new ArrayList(); |
| 1788 | if ("DRLVM".equals(vmName)) { //$NON-NLS-1$ |
| 1789 | FilenameFilter jarFilter = new FilenameFilter() { |
| 1790 | public boolean accept(File dir, String name) { |
| 1791 | return name.endsWith(".jar") & !name.endsWith("-src.jar"); //$NON-NLS-1$//$NON-NLS-2$ |
| 1792 | } |
| 1793 | }; |
| 1794 | jarsNames = new File(jreDir + "/lib/boot/").list(jarFilter); //$NON-NLS-1$ |
| 1795 | addJarEntries(jreDir + "/lib/boot/", jarsNames, paths); //$NON-NLS-1$ |
| 1796 | } else { |
| 1797 | jarsNames = new String[] { |
| 1798 | "/lib/vm.jar", //$NON-NLS-1$ |
| 1799 | "/lib/rt.jar", //$NON-NLS-1$ |
| 1800 | "/lib/core.jar", //$NON-NLS-1$ |
| 1801 | "/lib/security.jar", //$NON-NLS-1$ |
| 1802 | "/lib/xml.jar", //$NON-NLS-1$ |
| 1803 | "/lib/graphics.jar" //$NON-NLS-1$ |
| 1804 | }; |
| 1805 | addJarEntries(jreDir, jarsNames, paths); |
| 1806 | } |
| 1807 | jars = new String[paths.size()]; |
| 1808 | paths.toArray(jars); |
| 1809 | } |
| 1810 | return jars; |
| 1811 | } |
| 1812 | /** |
| 1813 | * Makes the given path a path using native path separators as returned by File.getPath() |
| 1814 | * and trimming any extra slash. |
| 1815 | */ |
| 1816 | public static String toNativePath(String path) { |
| 1817 | String nativePath = path.replace('\\', File.separatorChar).replace('/', File.separatorChar); |
| 1818 | return |
| 1819 | nativePath.endsWith("/") || nativePath.endsWith("\\") ? //$NON-NLS-1$ //$NON-NLS-2$ |
| 1820 | nativePath.substring(0, nativePath.length() - 1) : |
| 1821 | nativePath; |
| 1822 | } |
| 1823 | |
| 1824 | private static void addJarEntries(String jreDir, String[] jarNames, ArrayList paths) { |
| 1825 | for (int i = 0, max = jarNames.length; i < max; i++) { |
| 1826 | final String currentName = jreDir + jarNames[i]; |
| 1827 | File f = new File(currentName); |
| 1828 | if (f.exists()) { |
| 1829 | paths.add(toNativePath(currentName)); |
| 1830 | } |
| 1831 | } |
| 1832 | } |
| 1833 | /** |
| 1834 | * Delete a file or directory and insure that the file is no longer present |
| 1835 | * on file system. In case of directory, delete all the hierarchy underneath. |
| 1836 | * |
| 1837 | * @param file The file or directory to delete |
| 1838 | * @return true iff the file was really delete, false otherwise |
| 1839 | */ |
| 1840 | public static boolean delete(File file) { |
| 1841 | if (!file.exists()) { |
| 1842 | return true; |
| 1843 | } |
| 1844 | // flush all directory content |
| 1845 | if (file.isDirectory()) { |
| 1846 | flushDirectoryContent(file); |
| 1847 | } |
| 1848 | // remove file |
| 1849 | file.delete(); |
| 1850 | if (isFileDeleted(file)) { |
| 1851 | return true; |
| 1852 | } |
| 1853 | return waitUntilFileDeleted(file); |
| 1854 | } |
| 1855 | public static void flushDirectoryContent(File dir) { |
| 1856 | File[] files = dir.listFiles(); |
| 1857 | if (files == null) return; |
| 1858 | for (int i = 0, max = files.length; i < max; i++) { |
| 1859 | delete(files[i]); |
| 1860 | } |
| 1861 | } |
| 1862 | /** |
| 1863 | * Wait until the file is _really_ deleted on file system. |
| 1864 | * |
| 1865 | * @param file Deleted file |
| 1866 | * @return true if the file was finally deleted, false otherwise |
| 1867 | */ |
| 1868 | private static boolean waitUntilFileDeleted(File file) { |
| 1869 | int count = 0; |
| 1870 | int delay = 10; // ms |
| 1871 | int maxRetry = DELETE_MAX_WAIT / delay; |
| 1872 | int time = 0; |
| 1873 | while (count < maxRetry) { |
| 1874 | try { |
| 1875 | count++; |
| 1876 | Thread.sleep(delay); |
| 1877 | time += delay; |
| 1878 | if (time > DELETE_MAX_TIME) DELETE_MAX_TIME = time; |
| 1879 | if (DELETE_DEBUG) System.out.print('.'); |
| 1880 | if (file.exists()) { |
| 1881 | if (file.delete()) { |
| 1882 | // SUCCESS |
| 1883 | return true; |
| 1884 | } |
| 1885 | } |
| 1886 | if (isFileDeleted(file)) { |
| 1887 | // SUCCESS |
| 1888 | return true; |
| 1889 | } |
| 1890 | // Increment waiting delay exponentially |
| 1891 | if (count >= 10 && delay <= 100) { |
| 1892 | count = 1; |
| 1893 | delay *= 10; |
| 1894 | maxRetry = DELETE_MAX_WAIT / delay; |
| 1895 | if ((DELETE_MAX_WAIT%delay) != 0) { |
| 1896 | maxRetry++; |
| 1897 | } |
| 1898 | } |
| 1899 | } |
| 1900 | catch (InterruptedException ie) { |
| 1901 | break; // end loop |
| 1902 | } |
| 1903 | } |
| 1904 | System.err.println(); |
| 1905 | System.err.println(" !!! ERROR: "+file+" was never deleted even after having waited "+DELETE_MAX_TIME+"ms!!!"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ |
| 1906 | System.err.println(); |
| 1907 | return false; |
| 1908 | } |
| 1909 | /** |
| 1910 | * Returns whether a file is really deleted or not. |
| 1911 | * Does not only rely on {@link File#exists()} method but also |
| 1912 | * look if it's not in its parent children {@link #getParentChildFile(File)}. |
| 1913 | * |
| 1914 | * @param file The file to test if deleted |
| 1915 | * @return true if the file does not exist and was not found in its parent children. |
| 1916 | */ |
| 1917 | public static boolean isFileDeleted(File file) { |
| 1918 | return !file.exists() && getParentChildFile(file) == null; |
| 1919 | } |
| 1920 | /** |
| 1921 | * Returns the parent's child file matching the given file or null if not found. |
| 1922 | * |
| 1923 | * @param file The searched file in parent |
| 1924 | * @return The parent's child matching the given file or null if not found. |
| 1925 | */ |
| 1926 | private static File getParentChildFile(File file) { |
| 1927 | File parent = file.getParentFile(); |
| 1928 | if (parent == null || !parent.exists()) return null; |
| 1929 | File[] files = parent.listFiles(); |
| 1930 | int length = files==null ? 0 : files.length; |
| 1931 | if (length > 0) { |
| 1932 | for (int i=0; i<length; i++) { |
| 1933 | if (files[i] == file) { |
| 1934 | return files[i]; |
| 1935 | } else if (files[i].equals(file)) { |
| 1936 | return files[i]; |
| 1937 | } else if (files[i].getPath().equals(file.getPath())) { |
| 1938 | return files[i]; |
| 1939 | } |
| 1940 | } |
| 1941 | } |
| 1942 | return null; |
| 1943 | } |
| 1944 | |
| 1945 | /** |
| 1946 | * Turns the given array of strings into a {@link HashSet} |
| 1947 | * @param values |
| 1948 | * @return a new {@link HashSet} of the string array |
| 1949 | */ |
| 1950 | public static Set convertAsSet(String[] values) { |
| 1951 | Set set = new HashSet(); |
| 1952 | if (values != null && values.length != 0) { |
| 1953 | for (int i = 0, max = values.length; i < max; i++) { |
| 1954 | set.add(values[i]); |
| 1955 | } |
| 1956 | } |
| 1957 | return set; |
| 1958 | } |
| 1959 | |
| 1960 | /** |
| 1961 | * Returns an identifier for the given API component including its version identifier |
| 1962 | * (component id + '(' + major + . + minor + . + micro + ')' ) |
| 1963 | * |
| 1964 | * @param component API component |
| 1965 | * @return API component + version identifier |
| 1966 | */ |
| 1967 | public static String getDeltaComponentVersionsId(IApiComponent component) { |
| 1968 | StringBuffer buffer = new StringBuffer(component.getId()); |
| 1969 | String version = component.getVersion(); |
| 1970 | // remove the qualifier part |
| 1971 | if (version != null) { |
| 1972 | buffer.append('('); |
| 1973 | try { |
| 1974 | Version version2 = new Version(version); |
| 1975 | buffer |
| 1976 | .append(version2.getMajor()) |
| 1977 | .append('.') |
| 1978 | .append(version2.getMinor()) |
| 1979 | .append('.') |
| 1980 | .append(version2.getMicro()); |
| 1981 | } catch (IllegalArgumentException e) { |
| 1982 | // the version string doesn't follow the Eclipse pattern |
| 1983 | // we keep the version as is |
| 1984 | buffer.append(version); |
| 1985 | } |
| 1986 | buffer.append(')'); |
| 1987 | } |
| 1988 | return String.valueOf(buffer); |
| 1989 | } |
| 1990 | /** |
| 1991 | * Returns an identifier for the given API component including its version identifier |
| 1992 | * (component id + _ + major + _ + minor + _ + micro) |
| 1993 | * |
| 1994 | * @param component API component |
| 1995 | * @return API component + version identifier |
| 1996 | */ |
| 1997 | public static String getComponentVersionsId(IApiComponent component) { |
| 1998 | StringBuffer buffer = new StringBuffer(component.getId()); |
| 1999 | String version = component.getVersion(); |
| 2000 | // remove the qualifier part |
| 2001 | if (version != null) { |
| 2002 | buffer.append('_'); |
| 2003 | try { |
| 2004 | Version version2 = new Version(version); |
| 2005 | buffer |
| 2006 | .append(version2.getMajor()) |
| 2007 | .append('.') |
| 2008 | .append(version2.getMinor()) |
| 2009 | .append('.') |
| 2010 | .append(version2.getMicro()); |
| 2011 | } catch (IllegalArgumentException e) { |
| 2012 | // the version string doesn't follow the Eclipse pattern |
| 2013 | // we keep the version as is |
| 2014 | buffer.append(version); |
| 2015 | } |
| 2016 | } |
| 2017 | return String.valueOf(buffer); |
| 2018 | } |
| 2019 | public static String getDescriptorName(IApiType descriptor) { |
| 2020 | String typeName = descriptor.getName(); |
| 2021 | int index = typeName.lastIndexOf('$'); |
| 2022 | if (index != -1) { |
| 2023 | return typeName.replace('$', '.'); |
| 2024 | } |
| 2025 | return typeName; |
| 2026 | } |
| 2027 | |
| 2028 | public static String getDeltaArgumentString(IDelta delta) { |
| 2029 | String[] arguments = delta.getArguments(); |
| 2030 | switch(delta.getFlags()) { |
| 2031 | case IDelta.TYPE_MEMBER : |
| 2032 | case IDelta.TYPE : |
| 2033 | return arguments[0]; |
| 2034 | case IDelta.METHOD : |
| 2035 | case IDelta.CONSTRUCTOR : |
| 2036 | case IDelta.ENUM_CONSTANT : |
| 2037 | case IDelta.METHOD_WITH_DEFAULT_VALUE : |
| 2038 | case IDelta.METHOD_WITHOUT_DEFAULT_VALUE : |
| 2039 | case IDelta.FIELD : |
| 2040 | return arguments[1]; |
| 2041 | case IDelta.INCREASE_ACCESS : |
| 2042 | switch(delta.getElementType()) { |
| 2043 | case IDelta.FIELD_ELEMENT_TYPE : |
| 2044 | case IDelta.METHOD_ELEMENT_TYPE : |
| 2045 | case IDelta.CONSTRUCTOR_ELEMENT_TYPE : |
| 2046 | return arguments[1]; |
| 2047 | default: |
| 2048 | return arguments[0]; |
| 2049 | } |
| 2050 | } |
| 2051 | return EMPTY_STRING; |
| 2052 | } |
| 2053 | |
| 2054 | /** |
| 2055 | * Returns the string representation of the {@link IApiElement} type |
| 2056 | * @param type |
| 2057 | * @return the string of the {@link IApiElement} type |
| 2058 | */ |
| 2059 | public static String getApiElementType(int type) { |
| 2060 | switch(type) { |
| 2061 | case IApiElement.API_TYPE_CONTAINER : |
| 2062 | return "API_TYPE_CONTAINER"; //$NON-NLS-1$ |
| 2063 | case IApiElement.API_TYPE_ROOT : |
| 2064 | return "API_TYPE_ROOT"; //$NON-NLS-1$ |
| 2065 | case IApiElement.BASELINE : |
| 2066 | return "BASELINE"; //$NON-NLS-1$ |
| 2067 | case IApiElement.COMPONENT : |
| 2068 | return "COMPONENT"; //$NON-NLS-1$ |
| 2069 | case IApiElement.FIELD : |
| 2070 | return "FIELD"; //$NON-NLS-1$ |
| 2071 | case IApiElement.METHOD : |
| 2072 | return "METHOD"; //$NON-NLS-1$ |
| 2073 | case IApiElement.TYPE : |
| 2074 | return "TYPE"; //$NON-NLS-1$ |
| 2075 | default: |
| 2076 | return "UNKNOWN"; //$NON-NLS-1$ |
| 2077 | } |
| 2078 | } |
| 2079 | |
| 2080 | public static boolean isConstructor(String referenceMemberName) { |
| 2081 | return Arrays.equals(ConstantPool.Init, referenceMemberName.toCharArray()); |
| 2082 | } |
| 2083 | |
| 2084 | public static boolean isManifest(IPath path) { |
| 2085 | return MANIFEST_PROJECT_RELATIVE_PATH.equals(path); |
| 2086 | } |
| 2087 | public static void touchCorrespondingResource(IProject project, IResource resource, String typeName) { |
| 2088 | if (typeName != null && typeName != ApiFilterStore.GLOBAL) { |
| 2089 | if (Util.isManifest(resource.getProjectRelativePath())) { |
| 2090 | try { |
| 2091 | IJavaProject javaProject = JavaCore.create(project); |
| 2092 | IType findType = javaProject.findType(typeName); |
| 2093 | if (findType != null) { |
| 2094 | ICompilationUnit compilationUnit = findType.getCompilationUnit(); |
| 2095 | if (compilationUnit != null) { |
| 2096 | IResource cuResource = compilationUnit.getResource(); |
| 2097 | if (cuResource != null) { |
| 2098 | cuResource.touch(null); |
| 2099 | } |
| 2100 | } |
| 2101 | } |
| 2102 | } catch (JavaModelException e) { |
| 2103 | ApiPlugin.log(e); |
| 2104 | } catch (CoreException e) { |
| 2105 | ApiPlugin.log(e); |
| 2106 | } |
| 2107 | } else { |
| 2108 | try { |
| 2109 | resource.touch(null); |
| 2110 | } catch (CoreException e) { |
| 2111 | ApiPlugin.log(e); |
| 2112 | } |
| 2113 | } |
| 2114 | } |
| 2115 | } |
| 2116 | public static String getTypeNameFromMarker(IMarker marker) { |
| 2117 | return marker.getAttribute(IApiMarkerConstants.MARKER_ATTR_PROBLEM_TYPE_NAME, null); |
| 2118 | } |
| 2119 | |
| 2120 | public static IApiComponent[] getReexportedComponents(IApiComponent component) { |
| 2121 | try { |
| 2122 | IRequiredComponentDescription[] requiredComponents = component.getRequiredComponents(); |
| 2123 | int length = requiredComponents.length; |
| 2124 | if (length != 0) { |
| 2125 | List reexportedComponents = null; |
| 2126 | IApiBaseline baseline = component.getBaseline(); |
| 2127 | for (int i = 0; i < length; i++) { |
| 2128 | IRequiredComponentDescription description = requiredComponents[i]; |
| 2129 | if (description.isExported()) { |
| 2130 | String id = description.getId(); |
| 2131 | IApiComponent reexportedComponent = baseline.getApiComponent(id); |
| 2132 | if (reexportedComponent != null) { |
| 2133 | if (reexportedComponents == null) { |
| 2134 | reexportedComponents = new ArrayList(); |
| 2135 | } |
| 2136 | reexportedComponents.add(reexportedComponent); |
| 2137 | } |
| 2138 | } |
| 2139 | } |
| 2140 | if (reexportedComponents == null || reexportedComponents.size() == 0) { |
| 2141 | return null; |
| 2142 | } |
| 2143 | return (IApiComponent[]) reexportedComponents.toArray(new IApiComponent[reexportedComponents.size()]); |
| 2144 | } |
| 2145 | } catch (CoreException e) { |
| 2146 | ApiPlugin.log(e); |
| 2147 | } |
| 2148 | return null; |
| 2149 | } |
| 2150 | |
| 2151 | /** |
| 2152 | * Returns the {@link IResource} to create markers on when building. If the {@link IType} is <code>null</code> |
| 2153 | * or the type cannot be located (does not exist) than the MANIFEST.MF will be returned. |
| 2154 | * @param project the project to look in for the {@link IResource} |
| 2155 | * @param type the type we are looking for the resource for, or <code>null</code> |
| 2156 | * @return the {@link IResource} associated with the given {@link IType} or the MANIFEST.MF file |
| 2157 | */ |
| 2158 | public static IResource getResource(IProject project, IType type) { |
| 2159 | IResource resource = null; |
| 2160 | try { |
| 2161 | if (type == null) { |
| 2162 | IResource manifestFile = Util.getManifestFile(project); |
| 2163 | if (manifestFile == null) { |
| 2164 | // Cannot retrieve the manifest.mf file |
| 2165 | return null; |
| 2166 | } |
| 2167 | resource = manifestFile; |
| 2168 | } else { |
| 2169 | ICompilationUnit unit = type.getCompilationUnit(); |
| 2170 | if (unit != null) { |
| 2171 | resource = unit.getCorrespondingResource(); |
| 2172 | if (resource == null) { |
| 2173 | return null; |
| 2174 | } |
| 2175 | if (project.findMember(resource.getProjectRelativePath()) == null) { |
| 2176 | resource = null; |
| 2177 | IResource manifestFile = Util.getManifestFile(project); |
| 2178 | if (manifestFile == null) { |
| 2179 | // Cannot retrieve the manifest.mf file |
| 2180 | return null; |
| 2181 | } |
| 2182 | resource = manifestFile; |
| 2183 | } |
| 2184 | } else { |
| 2185 | IResource manifestFile = Util.getManifestFile(project); |
| 2186 | if (manifestFile == null) { |
| 2187 | // Cannot retrieve the manifest.mf file |
| 2188 | return null; |
| 2189 | } |
| 2190 | resource = manifestFile; |
| 2191 | } |
| 2192 | } |
| 2193 | } catch (JavaModelException e) { |
| 2194 | ApiPlugin.log(e); |
| 2195 | } |
| 2196 | return resource; |
| 2197 | } |
| 2198 | |
| 2199 | /** |
| 2200 | * Default comparator that orders {@link IApiComponent} by their ID |
| 2201 | */ |
| 2202 | public static final Comparator componentsorter = new Comparator(){ |
| 2203 | public int compare(Object o1, Object o2) { |
| 2204 | if(o1 instanceof IApiComponent && o2 instanceof IApiComponent) { |
| 2205 | return ((IApiComponent)o1).getId().compareTo(((IApiComponent)o2).getId()); |
| 2206 | } |
| 2207 | if(o1 instanceof SkippedComponent && o2 instanceof SkippedComponent) { |
| 2208 | return ((SkippedComponent)o1).getComponentId().compareTo(((SkippedComponent)o2).getComponentId()); |
| 2209 | } |
| 2210 | if(o1 instanceof String && o2 instanceof String) { |
| 2211 | return ((String)o1).compareTo((String)o2); |
| 2212 | } |
| 2213 | return -1; |
| 2214 | } |
| 2215 | }; |
| 2216 | |
| 2217 | /** |
| 2218 | * Initializes the exclude set with regex support. The API baseline is used to determine which |
| 2219 | * bundles should be added to the list when processing regex expressions. |
| 2220 | * |
| 2221 | * @param location |
| 2222 | * @param baseline |
| 2223 | * @return the list of bundles to be excluded |
| 2224 | */ |
| 2225 | public static Set initializeRegexExcludeList(String location, IApiBaseline baseline) { |
| 2226 | HashSet list = new HashSet(); |
| 2227 | if (location != null) { |
| 2228 | File file = new File(location); |
| 2229 | if (file.exists()) { |
| 2230 | InputStream stream = null; |
| 2231 | char[] contents = null; |
| 2232 | try { |
| 2233 | stream = new BufferedInputStream(new FileInputStream(file)); |
| 2234 | contents = getInputStreamAsCharArray(stream, -1, ISO_8859_1); |
| 2235 | } |
| 2236 | catch (FileNotFoundException e) {} |
| 2237 | catch (IOException e) {} |
| 2238 | finally { |
| 2239 | if (stream != null) { |
| 2240 | try { |
| 2241 | stream.close(); |
| 2242 | } catch (IOException e) {} |
| 2243 | } |
| 2244 | } |
| 2245 | if (contents != null) { |
| 2246 | LineNumberReader reader = new LineNumberReader(new StringReader(new String(contents))); |
| 2247 | String line = null; |
| 2248 | try { |
| 2249 | while ((line = reader.readLine()) != null) { |
| 2250 | if (line.startsWith("#") || line.length() == 0) { //$NON-NLS-1$ |
| 2251 | continue; |
| 2252 | } |
| 2253 | if(line.startsWith(REGULAR_EXPRESSION_START)) { |
| 2254 | if(baseline != null) { |
| 2255 | Util.collectRegexIds(line, list, baseline.getApiComponents()); |
| 2256 | } |
| 2257 | } |
| 2258 | else { |
| 2259 | list.add(line); |
| 2260 | } |
| 2261 | } |
| 2262 | } |
| 2263 | catch (IOException e) {} |
| 2264 | catch (Exception e) {} |
| 2265 | finally { |
| 2266 | try { |
| 2267 | reader.close(); |
| 2268 | } catch (IOException e) {} |
| 2269 | } |
| 2270 | } |
| 2271 | } |
| 2272 | } |
| 2273 | return list; |
| 2274 | } |
| 2275 | |
| 2276 | /** |
| 2277 | * Collects the set of component ids that match a given regex in the exclude file |
| 2278 | * @param line |
| 2279 | * @param list |
| 2280 | * @param components |
| 2281 | */ |
| 2282 | public static void collectRegexIds(String line, Set list, IApiComponent[] components) throws Exception { |
| 2283 | if (line.startsWith(REGULAR_EXPRESSION_START)) { |
| 2284 | String componentname = line; |
| 2285 | // regular expression |
| 2286 | componentname = componentname.substring(2); |
| 2287 | Pattern pattern = null; |
| 2288 | try { |
| 2289 | pattern = Pattern.compile(componentname); |
| 2290 | String componentid = null; |
| 2291 | for (int j = 0, max2 = components.length; j < max2; j++) { |
| 2292 | componentid = components[j].getId(); |
| 2293 | if (pattern.matcher(componentid).matches()) { |
| 2294 | list.add(componentid); |
| 2295 | } |
| 2296 | } |
| 2297 | } catch (PatternSyntaxException e) { |
| 2298 | throw new Exception(NLS.bind( |
| 2299 | UtilMessages.comparison_invalidRegularExpression, |
| 2300 | componentname)); |
| 2301 | } |
| 2302 | } |
| 2303 | } |
| 2304 | |
| 2305 | /** |
| 2306 | * Default comparator that orders {@link File}s by their name |
| 2307 | */ |
| 2308 | public static final Comparator filesorter = new Comparator(){ |
| 2309 | public int compare(Object o1, Object o2) { |
| 2310 | if(o1 instanceof File && o2 instanceof File) { |
| 2311 | return ((File)o1).getName().compareTo(((File)o2).getName()); |
| 2312 | } |
| 2313 | return 0; |
| 2314 | } |
| 2315 | }; |
| 2316 | |
| 2317 | /** |
| 2318 | * Returns true if the given {@link IApiType} is API or not, where API is defined |
| 2319 | * as having API visibility in an API description and having either the public of protected |
| 2320 | * Java flag set |
| 2321 | * |
| 2322 | * @param visibility |
| 2323 | * @param typeDescriptor |
| 2324 | * @return true if the given type is API, false otherwise |
| 2325 | */ |
| 2326 | public static boolean isAPI(int visibility, IApiType typeDescriptor) { |
| 2327 | int access = typeDescriptor.getModifiers(); |
| 2328 | return VisibilityModifiers.isAPI(visibility) && (Flags.isPublic(access) || Flags.isProtected(access)); |
| 2329 | } |
| 2330 | } |