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 | } |