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.provisional.comparator; |
12 | |
13 | import java.util.HashSet; |
14 | import java.util.Iterator; |
15 | import java.util.Set; |
16 | |
17 | import org.eclipse.core.runtime.CoreException; |
18 | import org.eclipse.core.runtime.IProgressMonitor; |
19 | import org.eclipse.core.runtime.IStatus; |
20 | import org.eclipse.core.runtime.SubMonitor; |
21 | import org.eclipse.jdt.core.Flags; |
22 | import org.eclipse.pde.api.tools.internal.comparator.ClassFileComparator; |
23 | import org.eclipse.pde.api.tools.internal.comparator.Delta; |
24 | import org.eclipse.pde.api.tools.internal.provisional.ApiPlugin; |
25 | import org.eclipse.pde.api.tools.internal.provisional.IApiAnnotations; |
26 | import org.eclipse.pde.api.tools.internal.provisional.IApiDescription; |
27 | import org.eclipse.pde.api.tools.internal.provisional.IRequiredComponentDescription; |
28 | import org.eclipse.pde.api.tools.internal.provisional.RestrictionModifiers; |
29 | import org.eclipse.pde.api.tools.internal.provisional.VisibilityModifiers; |
30 | import org.eclipse.pde.api.tools.internal.provisional.model.ApiTypeContainerVisitor; |
31 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiBaseline; |
32 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiComponent; |
33 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiScope; |
34 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiType; |
35 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiTypeContainer; |
36 | import org.eclipse.pde.api.tools.internal.provisional.model.IApiTypeRoot; |
37 | import org.eclipse.pde.api.tools.internal.util.Util; |
38 | import org.osgi.framework.Version; |
39 | |
40 | /** |
41 | * This class defines a comparator to get a IDelta out of the comparison of two elements. |
42 | * |
43 | * @since 1.0 |
44 | */ |
45 | public class ApiComparator { |
46 | /** |
47 | * Constant used for controlling tracing in the API comparator |
48 | */ |
49 | static boolean DEBUG = Util.DEBUG; |
50 | |
51 | /** |
52 | * Default empty delta |
53 | */ |
54 | public static final IDelta NO_DELTA = new Delta(); |
55 | |
56 | /** |
57 | * Reports a delta for a API component version change |
58 | * @param apiComponent2 |
59 | * @param id |
60 | * @param apiComponentVersion |
61 | * @param apiComponentVersion2 |
62 | * @param globalDelta |
63 | */ |
64 | private static void checkBundleVersionChanges(IApiComponent apiComponent2, String id, String apiComponentVersion, String apiComponentVersion2, Delta globalDelta) { |
65 | Version version = null; |
66 | try { |
67 | version = new Version(apiComponentVersion); |
68 | } catch (IllegalArgumentException e) { |
69 | // ignore |
70 | } |
71 | Version version2 = null; |
72 | try { |
73 | version2 = new Version(apiComponentVersion2); |
74 | } catch (IllegalArgumentException e) { |
75 | // ignore |
76 | } |
77 | if (version != null && version2 != null) { |
78 | // add check for bundle versions |
79 | if (version.getMajor() != version2.getMajor()) { |
80 | globalDelta.add( |
81 | new Delta( |
82 | Util.getDeltaComponentVersionsId(apiComponent2), |
83 | IDelta.API_COMPONENT_ELEMENT_TYPE, |
84 | IDelta.CHANGED, |
85 | IDelta.MAJOR_VERSION, |
86 | RestrictionModifiers.NO_RESTRICTIONS, |
87 | 0, |
88 | 0, |
89 | null, |
90 | id, |
91 | new String[] { |
92 | id, |
93 | apiComponentVersion, |
94 | apiComponentVersion2 |
95 | })); |
96 | } else if (version.getMinor() != version2.getMinor()) { |
97 | globalDelta.add( |
98 | new Delta( |
99 | Util.getDeltaComponentVersionsId(apiComponent2), |
100 | IDelta.API_COMPONENT_ELEMENT_TYPE, |
101 | IDelta.CHANGED, |
102 | IDelta.MINOR_VERSION, |
103 | RestrictionModifiers.NO_RESTRICTIONS, |
104 | 0, |
105 | 0, |
106 | null, |
107 | id, |
108 | new String[] { |
109 | id, |
110 | apiComponentVersion, |
111 | apiComponentVersion2 |
112 | })); |
113 | } |
114 | } |
115 | } |
116 | |
117 | /** |
118 | * Returns a delta that corresponds to the difference between the given baseline and the reference. |
119 | * |
120 | * @param referenceBaseline the given API baseline which is used as the reference |
121 | * @param baseline the given API baseline to compare with |
122 | * @param visibilityModifiers the given visibility that triggers what visibility should be used for the comparison |
123 | * @param force a flag to force the comparison of nested API components with the same versions |
124 | * @param monitor |
125 | * |
126 | * @return a delta, an empty delta if no difference is found or null if the delta detection failed |
127 | * @throws IllegalArgumentException if one of the two baselines is null |
128 | */ |
129 | public static IDelta compare( |
130 | final IApiBaseline referenceBaseline, |
131 | final IApiBaseline baseline, |
132 | final int visibilityModifiers, |
133 | final boolean force, |
134 | final IProgressMonitor monitor) { |
135 | SubMonitor localmonitor = SubMonitor.convert(monitor, 2); |
136 | try { |
137 | if (referenceBaseline == null || baseline == null) { |
138 | throw new IllegalArgumentException("None of the baselines must be null"); //$NON-NLS-1$ |
139 | } |
140 | IApiComponent[] apiComponents = referenceBaseline.getApiComponents(); |
141 | IApiComponent[] apiComponents2 = baseline.getApiComponents(); |
142 | Set apiComponentsIds = new HashSet(); |
143 | final Delta globalDelta = new Delta(); |
144 | for (int i = 0, max = apiComponents.length; i < max; i++) { |
145 | Util.updateMonitor(localmonitor); |
146 | IApiComponent apiComponent = apiComponents[i]; |
147 | if (!apiComponent.isSystemComponent()) { |
148 | String id = apiComponent.getId(); |
149 | IApiComponent apiComponent2 = baseline.getApiComponent(id); |
150 | IDelta delta = null; |
151 | if (apiComponent2 == null) { |
152 | // report removal of an API component |
153 | delta = |
154 | new Delta( |
155 | null, |
156 | IDelta.API_PROFILE_ELEMENT_TYPE, |
157 | IDelta.REMOVED, |
158 | IDelta.API_COMPONENT, |
159 | null, |
160 | id, |
161 | id); |
162 | } else { |
163 | apiComponentsIds.add(id); |
164 | String versionString = apiComponent.getVersion(); |
165 | String versionString2 = apiComponent2.getVersion(); |
166 | checkBundleVersionChanges(apiComponent2, id, versionString, versionString2, globalDelta); |
167 | if (!versionString.equals(versionString2) |
168 | || force) { |
169 | long time = System.currentTimeMillis(); |
170 | try { |
171 | delta = compare(apiComponent, apiComponent2, referenceBaseline, baseline, visibilityModifiers, localmonitor.newChild(1)); |
172 | } finally { |
173 | if (DEBUG) { |
174 | System.out.println("Time spent for " + id+ " " + versionString + " : " + (System.currentTimeMillis() - time) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
175 | } |
176 | } |
177 | } |
178 | } |
179 | if (delta != null && delta != NO_DELTA) { |
180 | globalDelta.add(delta); |
181 | } |
182 | } |
183 | } |
184 | Util.updateMonitor(localmonitor, 1); |
185 | for (int i = 0, max = apiComponents2.length; i < max; i++) { |
186 | Util.updateMonitor(localmonitor); |
187 | IApiComponent apiComponent = apiComponents2[i]; |
188 | if (!apiComponent.isSystemComponent()) { |
189 | String id = apiComponent.getId(); |
190 | if (!apiComponentsIds.contains(id)) { |
191 | // addition of an API component |
192 | globalDelta.add( |
193 | new Delta( |
194 | null, |
195 | IDelta.API_PROFILE_ELEMENT_TYPE, |
196 | IDelta.ADDED, |
197 | IDelta.API_COMPONENT, |
198 | null, |
199 | id, |
200 | id)); |
201 | } |
202 | } |
203 | } |
204 | return globalDelta.isEmpty() ? NO_DELTA : globalDelta; |
205 | } |
206 | finally { |
207 | localmonitor.done(); |
208 | } |
209 | } |
210 | |
211 | /** |
212 | * Returns a delta that corresponds to the difference between the given component and the reference baseline. |
213 | * |
214 | * @param component the given component to compare with the given reference baseline |
215 | * @param referenceBaseline the given API baseline which is used as the reference |
216 | * @param visibilityModifiers the given visibility that triggers what visibility should be used for the comparison |
217 | * @param force a flag to force the comparison of nested API components with the same versions |
218 | * @param monitor |
219 | * |
220 | * @return a delta, an empty delta if no difference is found or null if the delta detection failed |
221 | * @exception IllegalArgumentException if:<ul> |
222 | * <li>the given component is null</li> |
223 | * <li>the reference baseline is null</li> |
224 | * </ul> |
225 | */ |
226 | public static IDelta compare( |
227 | final IApiComponent component, |
228 | final IApiBaseline referenceBaseline, |
229 | final int visibilityModifiers, |
230 | final boolean force, |
231 | final IProgressMonitor monitor) { |
232 | SubMonitor localmonitor = SubMonitor.convert(monitor, 2); |
233 | try { |
234 | if (component == null) { |
235 | throw new IllegalArgumentException("The composent cannot be null"); //$NON-NLS-1$ |
236 | } |
237 | if (referenceBaseline == null) { |
238 | throw new IllegalArgumentException("The reference baseline cannot be null"); //$NON-NLS-1$ |
239 | } |
240 | Util.updateMonitor(localmonitor, 1); |
241 | IDelta delta = null; |
242 | if (!component.isSystemComponent()) { |
243 | String id = component.getId(); |
244 | IApiComponent apiComponent2 = referenceBaseline.getApiComponent(id); |
245 | if (apiComponent2 == null) { |
246 | // report addition of an API component |
247 | delta = |
248 | new Delta( |
249 | null, |
250 | IDelta.API_PROFILE_ELEMENT_TYPE, |
251 | IDelta.ADDED, |
252 | IDelta.API_COMPONENT, |
253 | null, |
254 | id, |
255 | id); |
256 | } else { |
257 | if (!component.getVersion().equals(apiComponent2.getVersion()) |
258 | || force) { |
259 | long time = System.currentTimeMillis(); |
260 | try { |
261 | delta = compare(apiComponent2, component, visibilityModifiers, localmonitor.newChild(1)); |
262 | } finally { |
263 | if (DEBUG) { |
264 | System.out.println("Time spent for " + id+ " " + component.getVersion() + " : " + (System.currentTimeMillis() - time) + "ms"); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ |
265 | } |
266 | } |
267 | } |
268 | } |
269 | if (delta != null && delta != NO_DELTA) { |
270 | return delta; |
271 | } |
272 | } |
273 | return NO_DELTA; |
274 | } |
275 | finally { |
276 | localmonitor.done(); |
277 | } |
278 | } |
279 | |
280 | /** |
281 | * Returns a delta that corresponds to the comparison of the two given API components. |
282 | * The two components are compared even if their versions are identical. |
283 | * |
284 | * @param referenceComponent the given API component |
285 | * @param component2 the given API component to compare with |
286 | * @param referenceBaseline the given API baseline from which the given component <code>component</code> is coming from |
287 | * @param baseline the given API baseline from which the given component <code>component2</code> is coming from |
288 | * @param visibilityModifiers the given visibility that triggers what visibility should be used for the comparison |
289 | * @param monitor |
290 | * |
291 | * @return a delta, an empty delta if no difference is found or null if the delta detection failed |
292 | * @exception IllegalArgumentException if:<ul> |
293 | * <li>both given components are null</li> |
294 | * <li>one of the baselines is null</li> |
295 | * </ul> |
296 | */ |
297 | public static IDelta compare( |
298 | final IApiComponent referenceComponent, |
299 | final IApiComponent component2, |
300 | final IApiBaseline referenceBaseline, |
301 | final IApiBaseline baseline, |
302 | final int visibilityModifiers, |
303 | final IProgressMonitor monitor) { |
304 | SubMonitor localmonitor = SubMonitor.convert(monitor, 3); |
305 | try { |
306 | if (referenceComponent == null) { |
307 | if (component2 == null) { |
308 | throw new IllegalArgumentException("Both components cannot be null"); //$NON-NLS-1$ |
309 | } |
310 | return new Delta( |
311 | null, |
312 | IDelta.API_PROFILE_ELEMENT_TYPE, |
313 | IDelta.ADDED, |
314 | IDelta.API_COMPONENT, |
315 | null, |
316 | component2.getId(), |
317 | Util.getComponentVersionsId(component2)); |
318 | } else if (component2 == null) { |
319 | String referenceComponentId = referenceComponent.getId(); |
320 | return new Delta( |
321 | null, |
322 | IDelta.API_PROFILE_ELEMENT_TYPE, |
323 | IDelta.REMOVED, |
324 | IDelta.API_COMPONENT, |
325 | null, |
326 | referenceComponentId, |
327 | Util.getComponentVersionsId(referenceComponent)); |
328 | } |
329 | Util.updateMonitor(localmonitor, 1); |
330 | if (referenceBaseline == null || baseline == null) { |
331 | throw new IllegalArgumentException("The baselines cannot be null"); //$NON-NLS-1$ |
332 | } |
333 | String referenceComponentId = referenceComponent.getId(); |
334 | final Delta globalDelta = new Delta(); |
335 | |
336 | // check the EE first |
337 | Set referenceEEs = Util.convertAsSet(referenceComponent.getExecutionEnvironments()); |
338 | Set componentsEEs = Util.convertAsSet(component2.getExecutionEnvironments()); |
339 | Util.updateMonitor(localmonitor, 1); |
340 | for (Iterator iterator = referenceEEs.iterator(); iterator.hasNext(); ) { |
341 | Util.updateMonitor(localmonitor); |
342 | String currentEE = (String) iterator.next(); |
343 | if (!componentsEEs.remove(currentEE)) { |
344 | globalDelta.add( |
345 | new Delta( |
346 | Util.getDeltaComponentVersionsId(referenceComponent), |
347 | IDelta.API_COMPONENT_ELEMENT_TYPE, |
348 | IDelta.REMOVED, |
349 | IDelta.EXECUTION_ENVIRONMENT, |
350 | RestrictionModifiers.NO_RESTRICTIONS, |
351 | 0, |
352 | 0, |
353 | null, |
354 | referenceComponentId, |
355 | new String[] { currentEE, Util.getComponentVersionsId(referenceComponent)})); |
356 | } |
357 | } |
358 | for (Iterator iterator = componentsEEs.iterator(); iterator.hasNext(); ) { |
359 | Util.updateMonitor(localmonitor); |
360 | String currentEE = (String) iterator.next(); |
361 | globalDelta.add( |
362 | new Delta( |
363 | Util.getDeltaComponentVersionsId(referenceComponent), |
364 | IDelta.API_COMPONENT_ELEMENT_TYPE, |
365 | IDelta.ADDED, |
366 | IDelta.EXECUTION_ENVIRONMENT, |
367 | RestrictionModifiers.NO_RESTRICTIONS, |
368 | 0, |
369 | 0, |
370 | null, |
371 | referenceComponentId, |
372 | new String[] { currentEE, Util.getComponentVersionsId(referenceComponent)})); |
373 | } |
374 | return internalCompare(referenceComponent, component2, referenceBaseline, baseline, visibilityModifiers, globalDelta, localmonitor.newChild(1)); |
375 | } catch(CoreException e) { |
376 | // null means an error case |
377 | return null; |
378 | } |
379 | finally { |
380 | localmonitor.done(); |
381 | } |
382 | } |
383 | |
384 | /** |
385 | * Returns a delta that corresponds to the difference between the given component and the given reference component. |
386 | * The given component cannot be null. |
387 | * |
388 | * @param referenceComponent the given API component that is used as the reference |
389 | * @param component the given component to compare with |
390 | * @param visibilityModifiers the given visibility that triggers what visibility should be used for the comparison |
391 | * @param force a flag to force the comparison of nested API components with the same versions |
392 | * @param monitor |
393 | * |
394 | * @return a delta, an empty delta if no difference is found or null if the delta detection failed |
395 | */ |
396 | public static IDelta compare( |
397 | final IApiComponent referenceComponent, |
398 | final IApiComponent component, |
399 | final int visibilityModifiers, |
400 | final IProgressMonitor monitor) { |
401 | try { |
402 | return compare(referenceComponent, component, referenceComponent == null ? null : referenceComponent.getBaseline(), component.getBaseline(), visibilityModifiers, monitor); |
403 | } catch (CoreException e) { |
404 | ApiPlugin.log(e); |
405 | } |
406 | return null; |
407 | } |
408 | |
409 | /** |
410 | * Returns a delta that corresponds to the comparison of the given class file with the reference. |
411 | * |
412 | * @param typeRoot2 the given class file that comes from the <code>component2</code> |
413 | * @param component the given API component from the reference |
414 | * @param component2 the given API component to compare with |
415 | * @param referenceBaseline the given API baseline from which the given component <code>component</code> is coming from |
416 | * @param baseline the given API baseline from which the given component <code>component2</code> is coming from |
417 | * @param visibilityModifiers the given visibility that triggers what visibility should be used for the comparison |
418 | * @param monitor |
419 | * |
420 | * @return a delta, an empty delta if no difference is found or null if the delta detection failed |
421 | * @exception IllegalArgumentException if:<ul> |
422 | * <li>the given class file is null</li> |
423 | * <li>one of the given components is null</li> |
424 | * <li>one of the given baselines is null</li> |
425 | * </ul> |
426 | */ |
427 | public static IDelta compare( |
428 | final IApiTypeRoot typeRoot2, |
429 | final IApiComponent component, |
430 | final IApiComponent component2, |
431 | final IApiBaseline referenceBaseline, |
432 | final IApiBaseline baseline, |
433 | final int visibilityModifiers, |
434 | final IProgressMonitor monitor) { |
435 | |
436 | if (typeRoot2 == null) { |
437 | throw new IllegalArgumentException("The given class file is null"); //$NON-NLS-1$ |
438 | } |
439 | if (component == null || component2 == null) { |
440 | throw new IllegalArgumentException("One of the given components is null"); //$NON-NLS-1$ |
441 | } |
442 | if (referenceBaseline == null || baseline == null) { |
443 | throw new IllegalArgumentException("One of the given baselines is null"); //$NON-NLS-1$ |
444 | } |
445 | SubMonitor localmonitor = SubMonitor.convert(monitor, 6); |
446 | try { |
447 | IApiType typeDescriptor2 = typeRoot2.getStructure(); |
448 | if (typeDescriptor2.isMemberType() || typeDescriptor2.isAnonymous() || typeDescriptor2.isLocal()) { |
449 | // we skip nested types (member, local and anonymous) |
450 | return NO_DELTA; |
451 | } |
452 | String typeName = typeRoot2.getTypeName(); |
453 | IApiTypeRoot typeRoot = null; |
454 | String id = component.getId(); |
455 | if (Util.ORG_ECLIPSE_SWT.equals(id)) { |
456 | typeRoot = component.findTypeRoot(typeName); |
457 | } else { |
458 | typeRoot = component.findTypeRoot(typeName, id); |
459 | } |
460 | final IApiDescription apiDescription2 = component2.getApiDescription(); |
461 | IApiAnnotations elementDescription2 = apiDescription2.resolveAnnotations(typeDescriptor2.getHandle()); |
462 | int visibility = 0; |
463 | if (elementDescription2 != null) { |
464 | visibility = elementDescription2.getVisibility(); |
465 | } |
466 | Util.updateMonitor(localmonitor, 1); |
467 | final IApiDescription referenceApiDescription = component.getApiDescription(); |
468 | IApiAnnotations refElementDescription = referenceApiDescription.resolveAnnotations(typeDescriptor2.getHandle()); |
469 | int refVisibility = 0; |
470 | if (refElementDescription != null) { |
471 | refVisibility = refElementDescription.getVisibility(); |
472 | } |
473 | Util.updateMonitor(localmonitor, 1); |
474 | String deltaComponentID = Util.getDeltaComponentVersionsId(component2); |
475 | if (typeRoot == null) { |
476 | if (Util.isAPI(visibility, typeDescriptor2)) { |
477 | return new Delta( |
478 | deltaComponentID, |
479 | IDelta.API_COMPONENT_ELEMENT_TYPE, |
480 | IDelta.ADDED, |
481 | IDelta.TYPE, |
482 | elementDescription2 != null ? elementDescription2.getRestrictions() : RestrictionModifiers.NO_RESTRICTIONS, |
483 | 0, |
484 | typeDescriptor2.getModifiers(), |
485 | typeName, |
486 | typeName, |
487 | new String[] { typeName, Util.getComponentVersionsId(component2)}); |
488 | } |
489 | return NO_DELTA; |
490 | } |
491 | Util.updateMonitor(localmonitor, 1); |
492 | IApiType typeDescriptor = typeRoot.getStructure(); |
493 | if ((visibility & visibilityModifiers) == 0) { |
494 | if ((refVisibility & visibilityModifiers) == 0) { |
495 | // no delta |
496 | return NO_DELTA; |
497 | } |
498 | if (Util.isAPI(refVisibility, typeDescriptor)) { |
499 | return new Delta( |
500 | deltaComponentID, |
501 | IDelta.API_COMPONENT_ELEMENT_TYPE, |
502 | IDelta.REMOVED, |
503 | IDelta.API_TYPE, |
504 | elementDescription2 != null ? elementDescription2.getRestrictions() : RestrictionModifiers.NO_RESTRICTIONS, |
505 | typeDescriptor.getModifiers(), |
506 | typeDescriptor2.getModifiers(), |
507 | typeName, |
508 | typeName, |
509 | new String[] { typeName, Util.getComponentVersionsId(component2)}); |
510 | } |
511 | } else if (!Util.isAPI(refVisibility, typeDescriptor) |
512 | && Util.isAPI(visibility, typeDescriptor2)) { |
513 | return new Delta( |
514 | deltaComponentID, |
515 | IDelta.API_COMPONENT_ELEMENT_TYPE, |
516 | IDelta.ADDED, |
517 | IDelta.TYPE, |
518 | elementDescription2 != null ? elementDescription2.getRestrictions() : RestrictionModifiers.NO_RESTRICTIONS, |
519 | typeDescriptor.getModifiers(), |
520 | typeDescriptor2.getModifiers(), |
521 | typeName, |
522 | typeName, |
523 | new String[] { typeName, Util.getComponentVersionsId(component2)}); |
524 | } |
525 | Util.updateMonitor(localmonitor, 1); |
526 | if (visibilityModifiers == VisibilityModifiers.API) { |
527 | // if the visibility is API, we only consider public and protected types |
528 | if (Util.isDefault(typeDescriptor2.getModifiers()) |
529 | || Flags.isPrivate(typeDescriptor2.getModifiers())) { |
530 | // we need to check if the reference contains the type to report a reduced visibility |
531 | if (Flags.isPublic(typeDescriptor.getModifiers()) |
532 | || Flags.isProtected(typeDescriptor.getModifiers())) { |
533 | return new Delta( |
534 | deltaComponentID, |
535 | IDelta.API_COMPONENT_ELEMENT_TYPE, |
536 | IDelta.REMOVED, |
537 | IDelta.API_TYPE, |
538 | elementDescription2 != null ? elementDescription2.getRestrictions() : RestrictionModifiers.NO_RESTRICTIONS, |
539 | typeDescriptor.getModifiers(), |
540 | typeDescriptor2.getModifiers(), |
541 | typeName, |
542 | typeName, |
543 | new String[] { typeName, Util.getComponentVersionsId(component2)}); |
544 | } else { |
545 | return NO_DELTA; |
546 | } |
547 | } |
548 | } |
549 | Util.updateMonitor(localmonitor, 1); |
550 | ClassFileComparator comparator = new ClassFileComparator(typeDescriptor, typeRoot2, component, component2, referenceBaseline, baseline, visibilityModifiers); |
551 | IDelta delta = comparator.getDelta(localmonitor.newChild(1)); |
552 | if (DEBUG) { |
553 | IStatus status = comparator.getStatus(); |
554 | if(status != null) { |
555 | ApiPlugin.log(status); |
556 | } |
557 | } |
558 | return delta; |
559 | } catch (CoreException e) { |
560 | return null; |
561 | } |
562 | finally { |
563 | localmonitor.done(); |
564 | } |
565 | } |
566 | |
567 | /** |
568 | * Returns a delta that corresponds to the comparison of the given class file. |
569 | * |
570 | * @param typeRoot the given class file |
571 | * @param typeRoot2 the given class file to compare with |
572 | * @param component the given API component from which the given class file is coming from |
573 | * @param component2 the given API component to compare with |
574 | * @param referenceBaseline the given API baseline from which the given component <code>component</code> is coming from |
575 | * @param baseline the given API baseline from which the given component <code>component2</code> is coming from |
576 | * @param visibilityModifiers the given visibility that triggers what visibility should be used for the comparison |
577 | * @param monitor |
578 | * |
579 | * @return a delta, an empty delta if no difference is found or <code>null</code> if the delta detection failed |
580 | * @exception IllegalArgumentException if:<ul> |
581 | * <li>one of the given components is null</li> |
582 | * <li>one of the given baselines is null</li> |
583 | * </ul> |
584 | */ |
585 | public static IDelta compare( |
586 | final IApiTypeRoot typeRoot, |
587 | final IApiTypeRoot typeRoot2, |
588 | final IApiComponent component, |
589 | final IApiComponent component2, |
590 | final IApiBaseline referenceBaseline, |
591 | final IApiBaseline baseline, |
592 | final int visibilityModifiers, |
593 | final IProgressMonitor monitor) { |
594 | if (typeRoot == null || typeRoot2 == null) { |
595 | throw new IllegalArgumentException("One of the given class files is null"); //$NON-NLS-1$ |
596 | } |
597 | if (component == null || component2 == null) { |
598 | throw new IllegalArgumentException("One of the given components is null"); //$NON-NLS-1$ |
599 | } |
600 | if (referenceBaseline == null || baseline == null) { |
601 | throw new IllegalArgumentException("One of the given baselines is null"); //$NON-NLS-1$ |
602 | } |
603 | IDelta delta = null; |
604 | try { |
605 | ClassFileComparator comparator = |
606 | new ClassFileComparator( |
607 | typeRoot, |
608 | typeRoot2, |
609 | component, |
610 | component2, |
611 | referenceBaseline, |
612 | baseline, |
613 | visibilityModifiers); |
614 | delta = comparator.getDelta(SubMonitor.convert(monitor)); |
615 | if (DEBUG) { |
616 | IStatus status = comparator.getStatus(); |
617 | if(status != null) { |
618 | ApiPlugin.log(status); |
619 | } |
620 | } |
621 | } |
622 | catch(CoreException e) { |
623 | ApiPlugin.log(e); |
624 | } |
625 | return delta; |
626 | } |
627 | |
628 | /** |
629 | * Returns a delta that corresponds to the comparison of the two given API baselines. |
630 | * Nested API components with the same versions are not compared. |
631 | * <p>Equivalent to: compare(baseline, baseline2, visibilityModifiers, false);</p> |
632 | * |
633 | * @param scope the given scope for the comparison |
634 | * @param baseline the given API baseline to compare with |
635 | * @param visibilityModifiers the given visibility that triggers what visibility should be used for the comparison |
636 | * @param force a flag to force the comparison of nested API components with the same versions |
637 | * @param monitor the given progress monitor to report progress |
638 | * |
639 | * @return a delta, an empty delta if no difference is found or null if the delta detection failed |
640 | * @throws IllegalArgumentException if one of the two baselines is null |
641 | * CoreException if one of the element in the scope cannot be visited |
642 | */ |
643 | public static IDelta compare( |
644 | final IApiScope scope, |
645 | final IApiBaseline baseline, |
646 | final int visibilityModifiers, |
647 | final boolean force, |
648 | final IProgressMonitor monitor) throws CoreException { |
649 | if (scope == null || baseline == null) { |
650 | throw new IllegalArgumentException("None of the scope or the baseline must be null"); //$NON-NLS-1$ |
651 | } |
652 | SubMonitor localmonitor = SubMonitor.convert(monitor, 2); |
653 | try { |
654 | final Set deltas = new HashSet(); |
655 | final CompareApiScopeVisitor visitor = new CompareApiScopeVisitor(deltas, baseline, force, visibilityModifiers, localmonitor.newChild(1)); |
656 | scope.accept(visitor); |
657 | if (visitor.containsError()) { |
658 | return null; |
659 | } |
660 | if (deltas.isEmpty()) { |
661 | return NO_DELTA; |
662 | } |
663 | final Delta globalDelta = new Delta(); |
664 | for (Iterator iterator = deltas.iterator(); iterator.hasNext(); ) { |
665 | IDelta delta = (IDelta) iterator.next(); |
666 | delta.accept(new DeltaVisitor() { |
667 | public void endVisit(IDelta localDelta) { |
668 | if (localDelta.getChildren().length == 0) { |
669 | switch(localDelta.getElementType()) { |
670 | case IDelta.ANNOTATION_ELEMENT_TYPE : |
671 | case IDelta.ENUM_ELEMENT_TYPE : |
672 | case IDelta.CONSTRUCTOR_ELEMENT_TYPE : |
673 | case IDelta.METHOD_ELEMENT_TYPE : |
674 | case IDelta.INTERFACE_ELEMENT_TYPE : |
675 | case IDelta.CLASS_ELEMENT_TYPE : |
676 | case IDelta.FIELD_ELEMENT_TYPE : |
677 | case IDelta.API_COMPONENT_ELEMENT_TYPE : |
678 | case IDelta.API_PROFILE_ELEMENT_TYPE : |
679 | globalDelta.add(localDelta); |
680 | } |
681 | } |
682 | } |
683 | }); |
684 | } |
685 | Util.updateMonitor(localmonitor, 1); |
686 | return globalDelta.isEmpty() ? NO_DELTA : globalDelta; |
687 | } |
688 | finally { |
689 | localmonitor.done(); |
690 | } |
691 | } |
692 | |
693 | /** |
694 | * Returns true, if the given type descriptor should be skipped, false otherwise. |
695 | * @param visibilityModifiers |
696 | * @param elementDescription |
697 | * @param typeDescriptor |
698 | * @return |
699 | */ |
700 | static boolean filterType(final int visibilityModifiers, |
701 | IApiAnnotations elementDescription, |
702 | IApiType typeDescriptor) { |
703 | if (elementDescription != null && (elementDescription.getVisibility() & visibilityModifiers) == 0) { |
704 | // we skip the class file according to their visibility |
705 | return true; |
706 | } |
707 | if (visibilityModifiers == VisibilityModifiers.API) { |
708 | // if the visibility is API, we only consider public and protected types or types |
709 | // without element description |
710 | if (elementDescription == null |
711 | || Util.isDefault(typeDescriptor.getModifiers()) |
712 | || Flags.isPrivate(typeDescriptor.getModifiers())) { |
713 | return true; |
714 | } |
715 | } |
716 | return false; |
717 | } |
718 | |
719 | /** |
720 | * Performs the internal compare of the given {@link IApiComponent}s using their type containers |
721 | * @param component |
722 | * @param component2 |
723 | * @param referenceBaseline |
724 | * @param baseline |
725 | * @param visibilityModifiers |
726 | * @param globalDelta |
727 | * @param monitor |
728 | * |
729 | * @return a delta of changed API elements |
730 | * @throws CoreException |
731 | */ |
732 | private static IDelta internalCompare(final IApiComponent component, |
733 | final IApiComponent component2, |
734 | final IApiBaseline referenceBaseline, |
735 | final IApiBaseline baseline, |
736 | final int visibilityModifiers, |
737 | final Delta globalDelta, |
738 | final IProgressMonitor monitor) throws CoreException { |
739 | final Set typeRootBaseLineNames = new HashSet(); |
740 | final String id = component.getId(); |
741 | IApiTypeContainer[] typeRootContainers = null; |
742 | IApiTypeContainer[] typeRootContainers2 = null; |
743 | final SubMonitor localmonitor = SubMonitor.convert(monitor, 4); |
744 | final boolean isSWT = Util.ORG_ECLIPSE_SWT.equals(id); |
745 | if (isSWT) { |
746 | typeRootContainers = component.getApiTypeContainers(); |
747 | typeRootContainers2 = component2.getApiTypeContainers(); |
748 | } else { |
749 | typeRootContainers = component.getApiTypeContainers(id); |
750 | typeRootContainers2 = component2.getApiTypeContainers(id); |
751 | } |
752 | final IApiDescription apiDescription = component.getApiDescription(); |
753 | final IApiDescription apiDescription2 = component2.getApiDescription(); |
754 | Util.updateMonitor(localmonitor, 1); |
755 | if (typeRootContainers != null) { |
756 | for (int i = 0, max = typeRootContainers.length; i < max; i++) { |
757 | Util.updateMonitor(localmonitor); |
758 | IApiTypeContainer container = typeRootContainers[i]; |
759 | try { |
760 | container.accept(new ApiTypeContainerVisitor() { |
761 | public void visit(String packageName, IApiTypeRoot typeRoot) { |
762 | Util.updateMonitor(localmonitor); |
763 | String typeName = typeRoot.getTypeName(); |
764 | try { |
765 | IApiType typeDescriptor = typeRoot.getStructure(); |
766 | IApiAnnotations elementDescription = apiDescription.resolveAnnotations(typeDescriptor.getHandle()); |
767 | if (typeDescriptor.isMemberType() || typeDescriptor.isAnonymous() || typeDescriptor.isLocal()) { |
768 | // we skip nested types (member, local and anonymous) |
769 | return; |
770 | } |
771 | int visibility = 0; |
772 | if (elementDescription != null) { |
773 | visibility = elementDescription.getVisibility(); |
774 | } |
775 | IApiTypeRoot typeRoot2 = null; |
776 | if (isSWT) { |
777 | typeRoot2 = component2.findTypeRoot(typeName); |
778 | } else{ |
779 | typeRoot2 = component2.findTypeRoot(typeName, id); |
780 | } |
781 | String deltaComponentID = null; |
782 | IApiComponent provider = null; |
783 | IApiDescription providerApiDesc = null; |
784 | boolean reexported = false; |
785 | if (typeRoot2 == null) { |
786 | // check if the type is provided by a required component (it could have been moved/re-exported) |
787 | IApiComponent[] providers = component2.getBaseline().resolvePackage(component2, packageName); |
788 | int index = 0; |
789 | while (typeRoot2 == null && index < providers.length) { |
790 | Util.updateMonitor(localmonitor); |
791 | IApiComponent p = providers[index]; |
792 | if (!p.equals(component2)) { |
793 | String id2 = p.getId(); |
794 | if (Util.ORG_ECLIPSE_SWT.equals(id2)) { |
795 | typeRoot2 = p.findTypeRoot(typeName); |
796 | } else { |
797 | typeRoot2 = p.findTypeRoot(typeName, id2); |
798 | } |
799 | if (typeRoot2 != null) { |
800 | provider = p; |
801 | providerApiDesc = p.getApiDescription(); |
802 | IRequiredComponentDescription[] required = component2.getRequiredComponents(); |
803 | for (int k = 0; k < required.length; k++) { |
804 | IRequiredComponentDescription description = required[k]; |
805 | if (description.getId().equals(id2)) { |
806 | reexported = description.isExported(); |
807 | break; |
808 | } |
809 | } |
810 | } |
811 | } |
812 | index++; |
813 | } |
814 | } else { |
815 | provider = component2; |
816 | providerApiDesc = apiDescription2; |
817 | } |
818 | Util.updateMonitor(localmonitor); |
819 | deltaComponentID = Util.getDeltaComponentVersionsId(component2); |
820 | if(typeRoot2 == null) { |
821 | if ((visibility & visibilityModifiers) == 0) { |
822 | // we skip the class file according to their visibility |
823 | return; |
824 | } |
825 | if (visibilityModifiers == VisibilityModifiers.API) { |
826 | // if the visibility is API, we only consider public and protected types |
827 | if (Util.isDefault(typeDescriptor.getModifiers()) |
828 | || Flags.isPrivate(typeDescriptor.getModifiers())) { |
829 | return; |
830 | } |
831 | } |
832 | globalDelta.add( |
833 | new Delta( |
834 | deltaComponentID, |
835 | IDelta.API_COMPONENT_ELEMENT_TYPE, |
836 | IDelta.REMOVED, |
837 | IDelta.TYPE, |
838 | RestrictionModifiers.NO_RESTRICTIONS, |
839 | typeDescriptor.getModifiers(), |
840 | 0, |
841 | typeName, |
842 | typeName, |
843 | new String[] { typeName, Util.getComponentVersionsId(component2) })); |
844 | } else { |
845 | if ((visibility & visibilityModifiers) == 0) { |
846 | // we skip the class file according to their visibility |
847 | return; |
848 | } |
849 | IApiType typeDescriptor2 = typeRoot2.getStructure(); |
850 | IApiAnnotations elementDescription2 = providerApiDesc.resolveAnnotations(typeDescriptor2.getHandle()); |
851 | int visibility2 = 0; |
852 | if (elementDescription2 != null) { |
853 | visibility2 = elementDescription2.getVisibility(); |
854 | } |
855 | if (visibilityModifiers == VisibilityModifiers.API) { |
856 | // if the visibility is API, we only consider public and protected types |
857 | if (Util.isDefault(typeDescriptor.getModifiers()) |
858 | || Flags.isPrivate(typeDescriptor.getModifiers())) { |
859 | return; |
860 | } |
861 | } |
862 | if (Util.isAPI(visibility, typeDescriptor)) { |
863 | if (!Util.isAPI(visibility2, typeDescriptor2)) { |
864 | globalDelta.add( |
865 | new Delta( |
866 | deltaComponentID, |
867 | IDelta.API_COMPONENT_ELEMENT_TYPE, |
868 | IDelta.REMOVED, |
869 | reexported ? IDelta.REEXPORTED_API_TYPE : IDelta.API_TYPE, |
870 | elementDescription2 != null ? elementDescription2.getRestrictions() : RestrictionModifiers.NO_RESTRICTIONS, |
871 | typeDescriptor.getModifiers(), |
872 | typeDescriptor2.getModifiers(), |
873 | typeName, |
874 | typeName, |
875 | new String[] { typeName, Util.getComponentVersionsId(component2) })); |
876 | return; |
877 | } |
878 | } |
879 | if ((visibility2 & visibilityModifiers) == 0) { |
880 | // we simply report a changed visibility |
881 | globalDelta.add( |
882 | new Delta( |
883 | deltaComponentID, |
884 | IDelta.API_COMPONENT_ELEMENT_TYPE, |
885 | IDelta.CHANGED, |
886 | IDelta.TYPE_VISIBILITY, |
887 | elementDescription2 != null ? elementDescription2.getRestrictions() : RestrictionModifiers.NO_RESTRICTIONS, |
888 | typeDescriptor.getModifiers(), |
889 | typeDescriptor2.getModifiers(), |
890 | typeName, |
891 | typeName, |
892 | new String[] { typeName, Util.getComponentVersionsId(component2)})); |
893 | } |
894 | typeRootBaseLineNames.add(typeName); |
895 | ClassFileComparator comparator = new ClassFileComparator(typeDescriptor, typeRoot2, component, provider, referenceBaseline, baseline, visibilityModifiers); |
896 | IDelta delta = comparator.getDelta(localmonitor.newChild(1)); |
897 | if (DEBUG) { |
898 | IStatus status = comparator.getStatus(); |
899 | if(status != null) { |
900 | ApiPlugin.log(status); |
901 | } |
902 | } |
903 | if (delta != null && delta != NO_DELTA) { |
904 | globalDelta.add(delta); |
905 | } |
906 | } |
907 | Util.updateMonitor(localmonitor); |
908 | } catch (CoreException e) { |
909 | ApiPlugin.log(e); |
910 | } |
911 | } |
912 | }); |
913 | } catch (CoreException e) { |
914 | ApiPlugin.log(e); |
915 | } |
916 | } |
917 | } |
918 | Util.updateMonitor(localmonitor, 1); |
919 | IRequiredComponentDescription[] requiredComponents = component.getRequiredComponents(); |
920 | int length = requiredComponents.length; |
921 | if (length != 0) { |
922 | for (int j = 0; j < length; j++) { |
923 | Util.updateMonitor(localmonitor); |
924 | IRequiredComponentDescription description = requiredComponents[j]; |
925 | if (description.isExported()) { |
926 | final String currentComponentID = Util.getDeltaComponentVersionsId(component); |
927 | String descriptionID = description.getId(); |
928 | IApiComponent currentRequiredApiComponent = referenceBaseline.getApiComponent(descriptionID); |
929 | if (currentRequiredApiComponent == null) { |
930 | continue; |
931 | } |
932 | final IApiDescription reexportedApiDescription = currentRequiredApiComponent.getApiDescription(); |
933 | IApiTypeContainer[] apiTypeContainers = currentRequiredApiComponent.getApiTypeContainers(); |
934 | if (apiTypeContainers != null) { |
935 | for (int i = 0, max = apiTypeContainers.length; i < max; i++) { |
936 | Util.updateMonitor(localmonitor); |
937 | IApiTypeContainer container = apiTypeContainers[i]; |
938 | try { |
939 | container.accept(new ApiTypeContainerVisitor() { |
940 | public void visit(String packageName, IApiTypeRoot typeRoot) { |
941 | Util.updateMonitor(localmonitor); |
942 | String typeName = typeRoot.getTypeName(); |
943 | try { |
944 | IApiType typeDescriptor = typeRoot.getStructure(); |
945 | IApiAnnotations elementDescription = reexportedApiDescription.resolveAnnotations(typeDescriptor.getHandle()); |
946 | if (typeDescriptor.isMemberType() || typeDescriptor.isAnonymous() || typeDescriptor.isLocal()) { |
947 | // we skip nested types (member, local and anonymous) |
948 | return; |
949 | } |
950 | int visibility = 0; |
951 | if (elementDescription != null) { |
952 | visibility = elementDescription.getVisibility(); |
953 | } |
954 | IApiTypeRoot typeRoot2 = null; |
955 | if (isSWT) { |
956 | typeRoot2 = component2.findTypeRoot(typeName); |
957 | } else{ |
958 | typeRoot2 = component2.findTypeRoot(typeName, id); |
959 | } |
960 | IApiDescription providerApiDesc = null; |
961 | if (typeRoot2 == null) { |
962 | // check if the type is provided by a required component (it could have been moved/re-exported) |
963 | IApiComponent[] providers = component2.getBaseline().resolvePackage(component2, packageName); |
964 | int index = 0; |
965 | while (typeRoot2 == null && index < providers.length) { |
966 | IApiComponent p = providers[index]; |
967 | if (!p.equals(component2)) { |
968 | String id2 = p.getId(); |
969 | if (Util.ORG_ECLIPSE_SWT.equals(id2)) { |
970 | typeRoot2 = p.findTypeRoot(typeName); |
971 | } else { |
972 | typeRoot2 = p.findTypeRoot(typeName, id2); |
973 | } |
974 | if (typeRoot2 != null) { |
975 | providerApiDesc = p.getApiDescription(); |
976 | } |
977 | } |
978 | index++; |
979 | } |
980 | } else { |
981 | providerApiDesc = apiDescription2; |
982 | } |
983 | if(typeRoot2 == null) { |
984 | if ((visibility & visibilityModifiers) == 0) { |
985 | // we skip the class file according to their visibility |
986 | return; |
987 | } |
988 | if (visibilityModifiers == VisibilityModifiers.API) { |
989 | // if the visibility is API, we only consider public and protected types |
990 | if (Util.isDefault(typeDescriptor.getModifiers()) |
991 | || Flags.isPrivate(typeDescriptor.getModifiers())) { |
992 | return; |
993 | } |
994 | } |
995 | globalDelta.add( |
996 | new Delta( |
997 | currentComponentID, |
998 | IDelta.API_COMPONENT_ELEMENT_TYPE, |
999 | IDelta.REMOVED, |
1000 | IDelta.REEXPORTED_TYPE, |
1001 | RestrictionModifiers.NO_RESTRICTIONS, |
1002 | typeDescriptor.getModifiers(), |
1003 | 0, |
1004 | typeName, |
1005 | typeName, |
1006 | new String[] { typeName, Util.getComponentVersionsId(component) })); |
1007 | } else { |
1008 | typeRootBaseLineNames.add(typeName); |
1009 | IApiType typeDescriptor2 = typeRoot2.getStructure(); |
1010 | IApiAnnotations elementDescription2 = providerApiDesc.resolveAnnotations(typeDescriptor2.getHandle()); |
1011 | int visibility2 = 0; |
1012 | if (elementDescription2 != null) { |
1013 | visibility2 = elementDescription2.getVisibility(); |
1014 | } |
1015 | // if the visibility is API, we only consider public and protected types |
1016 | if (Util.isDefault(typeDescriptor.getModifiers()) |
1017 | || Flags.isPrivate(typeDescriptor.getModifiers())) { |
1018 | return; |
1019 | } |
1020 | if (Util.isAPI(visibility, typeDescriptor)) { |
1021 | if (!Util.isAPI(visibility2, typeDescriptor2)) { |
1022 | globalDelta.add( |
1023 | new Delta( |
1024 | currentComponentID, |
1025 | IDelta.API_COMPONENT_ELEMENT_TYPE, |
1026 | IDelta.REMOVED, |
1027 | IDelta.REEXPORTED_API_TYPE, |
1028 | elementDescription2 != null ? elementDescription2.getRestrictions() : RestrictionModifiers.NO_RESTRICTIONS, |
1029 | typeDescriptor.getModifiers(), |
1030 | typeDescriptor2.getModifiers(), |
1031 | typeName, |
1032 | typeName, |
1033 | new String[] { typeName, Util.getComponentVersionsId(component) })); |
1034 | return; |
1035 | } |
1036 | } |
1037 | } |
1038 | } catch (CoreException e) { |
1039 | ApiPlugin.log(e); |
1040 | } |
1041 | } |
1042 | }); |
1043 | } catch (CoreException e) { |
1044 | ApiPlugin.log(e); |
1045 | } |
1046 | } |
1047 | } |
1048 | } |
1049 | } |
1050 | } |
1051 | Util.updateMonitor(localmonitor, 1); |
1052 | if (typeRootContainers2 != null) { |
1053 | for (int i = 0, max = typeRootContainers2.length; i < max; i++) { |
1054 | Util.updateMonitor(localmonitor); |
1055 | IApiTypeContainer container = typeRootContainers2[i]; |
1056 | try { |
1057 | container.accept(new ApiTypeContainerVisitor() { |
1058 | public void visit(String packageName, IApiTypeRoot typeRoot) { |
1059 | Util.updateMonitor(localmonitor); |
1060 | String typeName = typeRoot.getTypeName(); |
1061 | try { |
1062 | IApiType type = typeRoot.getStructure(); |
1063 | IApiAnnotations elementDescription = apiDescription2.resolveAnnotations(type.getHandle()); |
1064 | if (type.isMemberType() || type.isLocal() || type.isAnonymous()) { |
1065 | // we skip nested types (member, local and anonymous) |
1066 | return; |
1067 | } |
1068 | if (filterType(visibilityModifiers, elementDescription, type)) { |
1069 | return; |
1070 | } |
1071 | if (typeRootBaseLineNames.contains(typeName)) { |
1072 | // already processed |
1073 | return; |
1074 | } |
1075 | typeRootBaseLineNames.add(typeName); |
1076 | String deltaComponentID = Util.getDeltaComponentVersionsId(component2); |
1077 | globalDelta.add( |
1078 | new Delta( |
1079 | deltaComponentID, |
1080 | IDelta.API_COMPONENT_ELEMENT_TYPE, |
1081 | IDelta.ADDED, |
1082 | IDelta.TYPE, |
1083 | elementDescription != null ? elementDescription.getRestrictions() : RestrictionModifiers.NO_RESTRICTIONS, |
1084 | 0, |
1085 | type.getModifiers(), |
1086 | typeName, |
1087 | typeName, |
1088 | new String[] { typeName, Util.getComponentVersionsId(component2) })); |
1089 | } catch (CoreException e) { |
1090 | ApiPlugin.log(e); |
1091 | } |
1092 | } |
1093 | }); |
1094 | } catch (CoreException e) { |
1095 | ApiPlugin.log(e); |
1096 | } |
1097 | } |
1098 | } |
1099 | Util.updateMonitor(localmonitor, 1); |
1100 | requiredComponents = component2.getRequiredComponents(); |
1101 | length = requiredComponents.length; |
1102 | if (length != 0) { |
1103 | for (int j = 0; j < length; j++) { |
1104 | Util.updateMonitor(localmonitor); |
1105 | IRequiredComponentDescription description = requiredComponents[j]; |
1106 | if (description.isExported()) { |
1107 | final String currentComponentID = Util.getDeltaComponentVersionsId(component); |
1108 | String descriptionID = description.getId(); |
1109 | IApiComponent currentRequiredApiComponent = baseline.getApiComponent(descriptionID); |
1110 | if (currentRequiredApiComponent == null) { |
1111 | continue; |
1112 | } |
1113 | IApiTypeContainer[] apiTypeContainers = currentRequiredApiComponent.getApiTypeContainers(); |
1114 | final IApiDescription reexportedApiDescription = currentRequiredApiComponent.getApiDescription(); |
1115 | if (apiTypeContainers != null) { |
1116 | for (int i = 0, max = apiTypeContainers.length; i < max; i++) { |
1117 | Util.updateMonitor(localmonitor); |
1118 | IApiTypeContainer container = apiTypeContainers[i]; |
1119 | try { |
1120 | container.accept(new ApiTypeContainerVisitor() { |
1121 | public void visit(String packageName, IApiTypeRoot typeRoot) { |
1122 | Util.updateMonitor(localmonitor); |
1123 | String typeName = typeRoot.getTypeName(); |
1124 | try { |
1125 | IApiType typeDescriptor = typeRoot.getStructure(); |
1126 | IApiAnnotations elementDescription = reexportedApiDescription.resolveAnnotations(typeDescriptor.getHandle()); |
1127 | if (typeDescriptor.isMemberType() || typeDescriptor.isAnonymous() || typeDescriptor.isLocal()) { |
1128 | // we skip nested types (member, local and anonymous) |
1129 | return; |
1130 | } |
1131 | if (filterType(visibilityModifiers, elementDescription, typeDescriptor)) { |
1132 | return; |
1133 | } |
1134 | if (typeRootBaseLineNames.contains(typeName)) { |
1135 | // already processed |
1136 | return; |
1137 | } |
1138 | typeRootBaseLineNames.add(typeName); |
1139 | globalDelta.add( |
1140 | new Delta( |
1141 | currentComponentID, |
1142 | IDelta.API_COMPONENT_ELEMENT_TYPE, |
1143 | IDelta.ADDED, |
1144 | IDelta.REEXPORTED_TYPE, |
1145 | elementDescription != null ? elementDescription.getRestrictions() : RestrictionModifiers.NO_RESTRICTIONS, |
1146 | 0, |
1147 | typeDescriptor.getModifiers(), |
1148 | typeName, |
1149 | typeName, |
1150 | new String[] { typeName, Util.getComponentVersionsId(component) })); |
1151 | } catch (CoreException e) { |
1152 | ApiPlugin.log(e); |
1153 | } |
1154 | } |
1155 | }); |
1156 | } catch (CoreException e) { |
1157 | ApiPlugin.log(e); |
1158 | } |
1159 | } |
1160 | } |
1161 | } |
1162 | } |
1163 | } |
1164 | return globalDelta.isEmpty() ? NO_DELTA : globalDelta; |
1165 | } |
1166 | |
1167 | /** |
1168 | * Method used for initializing tracing in the API comparator |
1169 | */ |
1170 | public static void setDebug(boolean debugValue) { |
1171 | DEBUG = debugValue || Util.DEBUG; |
1172 | } |
1173 | } |