KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > tools > ant > taskdefs > optional > extension > Specification


1 /*
2  * Licensed to the Apache Software Foundation (ASF) under one or more
3  * contributor license agreements. See the NOTICE file distributed with
4  * this work for additional information regarding copyright ownership.
5  * The ASF licenses this file to You under the Apache License, Version 2.0
6  * (the "License"); you may not use this file except in compliance with
7  * the License. You may obtain a copy of the License at
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  *
17  */

18 package org.apache.tools.ant.taskdefs.optional.extension;
19
20 import java.text.ParseException JavaDoc;
21 import java.util.ArrayList JavaDoc;
22 import java.util.Arrays JavaDoc;
23 import java.util.Iterator JavaDoc;
24 import java.util.Map JavaDoc;
25 import java.util.jar.Attributes JavaDoc;
26 import java.util.jar.Manifest JavaDoc;
27
28 import org.apache.tools.ant.util.StringUtils;
29
30 /**
31  * <p>Utility class that represents either an available "Optional Package"
32  * (formerly known as "Standard Extension") as described in the manifest
33  * of a JAR file, or the requirement for such an optional package.</p>
34  *
35  * <p>For more information about optional packages, see the document
36  * <em>Optional Package Versioning</em> in the documentation bundle for your
37  * Java2 Standard Edition package, in file
38  * <code>guide/extensions/versioning.html</code>.</p>
39  *
40  */

41 public final class Specification {
42
43     private static final String JavaDoc MISSING = "Missing ";
44
45     /**
46      * Manifest Attribute Name object for SPECIFICATION_TITLE.
47      */

48     public static final Attributes.Name JavaDoc SPECIFICATION_TITLE
49         = Attributes.Name.SPECIFICATION_TITLE;
50
51     /**
52      * Manifest Attribute Name object for SPECIFICATION_VERSION.
53      */

54     public static final Attributes.Name JavaDoc SPECIFICATION_VERSION
55         = Attributes.Name.SPECIFICATION_VERSION;
56
57     /**
58      * Manifest Attribute Name object for SPECIFICATION_VENDOR.
59      */

60     public static final Attributes.Name JavaDoc SPECIFICATION_VENDOR
61         = Attributes.Name.SPECIFICATION_VENDOR;
62
63     /**
64      * Manifest Attribute Name object for IMPLEMENTATION_TITLE.
65      */

66     public static final Attributes.Name JavaDoc IMPLEMENTATION_TITLE
67         = Attributes.Name.IMPLEMENTATION_TITLE;
68
69     /**
70      * Manifest Attribute Name object for IMPLEMENTATION_VERSION.
71      */

72     public static final Attributes.Name JavaDoc IMPLEMENTATION_VERSION
73         = Attributes.Name.IMPLEMENTATION_VERSION;
74
75     /**
76      * Manifest Attribute Name object for IMPLEMENTATION_VENDOR.
77      */

78     public static final Attributes.Name JavaDoc IMPLEMENTATION_VENDOR
79         = Attributes.Name.IMPLEMENTATION_VENDOR;
80
81     /**
82      * Enum indicating that extension is compatible with other Package
83      * Specification.
84      */

85     public static final Compatibility COMPATIBLE =
86         new Compatibility("COMPATIBLE");
87
88     /**
89      * Enum indicating that extension requires an upgrade
90      * of specification to be compatible with other Package Specification.
91      */

92     public static final Compatibility REQUIRE_SPECIFICATION_UPGRADE =
93         new Compatibility("REQUIRE_SPECIFICATION_UPGRADE");
94
95     /**
96      * Enum indicating that extension requires a vendor
97      * switch to be compatible with other Package Specification.
98      */

99     public static final Compatibility REQUIRE_VENDOR_SWITCH =
100         new Compatibility("REQUIRE_VENDOR_SWITCH");
101
102     /**
103      * Enum indicating that extension requires an upgrade
104      * of implementation to be compatible with other Package Specification.
105      */

106     public static final Compatibility REQUIRE_IMPLEMENTATION_CHANGE =
107         new Compatibility("REQUIRE_IMPLEMENTATION_CHANGE");
108
109     /**
110      * This enum indicates that an extension is incompatible with
111      * other Package Specification in ways other than other enums
112      * indicate. For example, the other Package Specification
113      * may have a different ID.
114      */

115     public static final Compatibility INCOMPATIBLE =
116         new Compatibility("INCOMPATIBLE");
117
118     /**
119      * The name of the Package Specification.
120      */

121     private String JavaDoc specificationTitle;
122
123     /**
124      * The version number (dotted decimal notation) of the specification
125      * to which this optional package conforms.
126      */

127     private DeweyDecimal specificationVersion;
128
129     /**
130      * The name of the company or organization that originated the
131      * specification to which this specification conforms.
132      */

133     private String JavaDoc specificationVendor;
134
135     /**
136      * The title of implementation.
137      */

138     private String JavaDoc implementationTitle;
139
140     /**
141      * The name of the company or organization that produced this
142      * implementation of this specification.
143      */

144     private String JavaDoc implementationVendor;
145
146     /**
147      * The version string for implementation. The version string is
148      * opaque.
149      */

150     private String JavaDoc implementationVersion;
151
152     /**
153      * The sections of jar that the specification applies to.
154      */

155     private String JavaDoc[] sections;
156
157     /**
158      * Return an array of <code>Package Specification</code> objects.
159      * If there are no such optional packages, a zero-length array is returned.
160      *
161      * @param manifest Manifest to be parsed
162      * @return the Package Specifications extensions in specified manifest
163      * @throws ParseException if the attributes of the specifications cannot
164      * be parsed according to their expected formats.
165      */

166     public static Specification[] getSpecifications(final Manifest JavaDoc manifest)
167         throws ParseException JavaDoc {
168         if (null == manifest) {
169             return new Specification[ 0 ];
170         }
171
172         final ArrayList JavaDoc results = new ArrayList JavaDoc();
173
174         final Map JavaDoc entries = manifest.getEntries();
175         final Iterator JavaDoc keys = entries.keySet().iterator();
176         while (keys.hasNext()) {
177             final String JavaDoc key = (String JavaDoc) keys.next();
178             final Attributes JavaDoc attributes = (Attributes JavaDoc) entries.get(key);
179             final Specification specification
180                 = getSpecification(key, attributes);
181             if (null != specification) {
182                 results.add(specification);
183             }
184         }
185
186         final ArrayList JavaDoc trimmedResults = removeDuplicates(results);
187         return (Specification[]) trimmedResults.toArray(new Specification[trimmedResults.size()]);
188     }
189
190     /**
191      * The constructor to create Package Specification object.
192      * Note that every component is allowed to be specified
193      * but only the specificationTitle is mandatory.
194      *
195      * @param specificationTitle the name of specification.
196      * @param specificationVersion the specification Version.
197      * @param specificationVendor the specification Vendor.
198      * @param implementationTitle the title of implementation.
199      * @param implementationVersion the implementation Version.
200      * @param implementationVendor the implementation Vendor.
201      */

202     public Specification(final String JavaDoc specificationTitle,
203                           final String JavaDoc specificationVersion,
204                           final String JavaDoc specificationVendor,
205                           final String JavaDoc implementationTitle,
206                           final String JavaDoc implementationVersion,
207                           final String JavaDoc implementationVendor) {
208         this(specificationTitle, specificationVersion, specificationVendor,
209               implementationTitle, implementationVersion, implementationVendor,
210               null);
211     }
212
213     /**
214      * The constructor to create Package Specification object.
215      * Note that every component is allowed to be specified
216      * but only the specificationTitle is mandatory.
217      *
218      * @param specificationTitle the name of specification.
219      * @param specificationVersion the specification Version.
220      * @param specificationVendor the specification Vendor.
221      * @param implementationTitle the title of implementation.
222      * @param implementationVersion the implementation Version.
223      * @param implementationVendor the implementation Vendor.
224      * @param sections the sections/packages that Specification applies to.
225      */

226     public Specification(final String JavaDoc specificationTitle,
227                           final String JavaDoc specificationVersion,
228                           final String JavaDoc specificationVendor,
229                           final String JavaDoc implementationTitle,
230                           final String JavaDoc implementationVersion,
231                           final String JavaDoc implementationVendor,
232                           final String JavaDoc[] sections) {
233         this.specificationTitle = specificationTitle;
234         this.specificationVendor = specificationVendor;
235
236         if (null != specificationVersion) {
237             try {
238                 this.specificationVersion
239                     = new DeweyDecimal(specificationVersion);
240             } catch (final NumberFormatException JavaDoc nfe) {
241                 final String JavaDoc error = "Bad specification version format '"
242                     + specificationVersion + "' in '" + specificationTitle
243                     + "'. (Reason: " + nfe + ")";
244                 throw new IllegalArgumentException JavaDoc(error);
245             }
246         }
247
248         this.implementationTitle = implementationTitle;
249         this.implementationVendor = implementationVendor;
250         this.implementationVersion = implementationVersion;
251
252         if (null == this.specificationTitle) {
253             throw new NullPointerException JavaDoc("specificationTitle");
254         }
255
256         String JavaDoc[] copy = null;
257         if (null != sections) {
258             copy = new String JavaDoc[ sections.length ];
259             System.arraycopy(sections, 0, copy, 0, sections.length);
260         }
261         this.sections = copy;
262     }
263
264     /**
265      * Get the title of the specification.
266      *
267      * @return the title of speciication
268      */

269     public String JavaDoc getSpecificationTitle() {
270         return specificationTitle;
271     }
272
273     /**
274      * Get the vendor of the specification.
275      *
276      * @return the vendor of the specification.
277      */

278     public String JavaDoc getSpecificationVendor() {
279         return specificationVendor;
280     }
281
282     /**
283      * Get the title of the specification.
284      *
285      * @return the title of the specification.
286      */

287     public String JavaDoc getImplementationTitle() {
288         return implementationTitle;
289     }
290
291     /**
292      * Get the version of the specification.
293      *
294      * @return the version of the specification.
295      */

296     public DeweyDecimal getSpecificationVersion() {
297         return specificationVersion;
298     }
299
300     /**
301      * Get the vendor of the extensions implementation.
302      *
303      * @return the vendor of the extensions implementation.
304      */

305     public String JavaDoc getImplementationVendor() {
306         return implementationVendor;
307     }
308
309     /**
310      * Get the version of the implementation.
311      *
312      * @return the version of the implementation.
313      */

314     public String JavaDoc getImplementationVersion() {
315         return implementationVersion;
316     }
317
318     /**
319      * Return an array containing sections to which specification applies
320      * or null if relevent to no sections.
321      *
322      * @return an array containing sections to which specification applies
323      * or null if relevent to no sections.
324      */

325     public String JavaDoc[] getSections() {
326         if (null == sections) {
327             return null;
328         }
329         final String JavaDoc[] newSections = new String JavaDoc[ sections.length ];
330         System.arraycopy(sections, 0, newSections, 0, sections.length);
331         return newSections;
332     }
333
334     /**
335      * Return a Compatibility enum indicating the relationship of this
336      * <code>Package Specification</code> with the specified
337      * <code>Extension</code>.
338      *
339      * @param other the other specification
340      * @return the enum indicating the compatibility (or lack thereof)
341      * of specifed Package Specification
342      */

343     public Compatibility getCompatibilityWith(final Specification other) {
344         // Specification Name must match
345
if (!specificationTitle.equals(other.getSpecificationTitle())) {
346             return INCOMPATIBLE;
347         }
348
349         // Available specification version must be >= required
350
final DeweyDecimal otherSpecificationVersion
351             = other.getSpecificationVersion();
352         if (null != specificationVersion) {
353             if (null == otherSpecificationVersion
354                 || !isCompatible(specificationVersion, otherSpecificationVersion)) {
355                 return REQUIRE_SPECIFICATION_UPGRADE;
356             }
357         }
358
359         // Implementation Vendor ID must match
360
final String JavaDoc otherImplementationVendor
361             = other.getImplementationVendor();
362         if (null != implementationVendor) {
363             if (null == otherImplementationVendor
364                 || !implementationVendor.equals(otherImplementationVendor)) {
365                 return REQUIRE_VENDOR_SWITCH;
366             }
367         }
368
369         // Implementation version must be >= required
370
final String JavaDoc otherImplementationVersion
371             = other.getImplementationVersion();
372         if (null != implementationVersion) {
373             if (null == otherImplementationVersion
374                 || !implementationVersion.equals(otherImplementationVersion)) {
375                 return REQUIRE_IMPLEMENTATION_CHANGE;
376             }
377         }
378
379         // This available optional package satisfies the requirements
380
return COMPATIBLE;
381     }
382
383     /**
384      * Return <code>true</code> if the specified <code>package</code>
385      * is satisfied by this <code>Specification</code>. Otherwise, return
386      * <code>false</code>.
387      *
388      * @param other the specification
389      * @return true if the specification is compatible with this specification
390      */

391     public boolean isCompatibleWith(final Specification other) {
392         return (COMPATIBLE == getCompatibilityWith(other));
393     }
394
395     /**
396      * Return a String representation of this object.
397      *
398      * @return string representation of object.
399      */

400     public String JavaDoc toString() {
401         final String JavaDoc brace = ": ";
402
403         final StringBuffer JavaDoc sb
404             = new StringBuffer JavaDoc(SPECIFICATION_TITLE.toString());
405         sb.append(brace);
406         sb.append(specificationTitle);
407         sb.append(StringUtils.LINE_SEP);
408
409         if (null != specificationVersion) {
410             sb.append(SPECIFICATION_VERSION);
411             sb.append(brace);
412             sb.append(specificationVersion);
413             sb.append(StringUtils.LINE_SEP);
414         }
415
416         if (null != specificationVendor) {
417             sb.append(SPECIFICATION_VENDOR);
418             sb.append(brace);
419             sb.append(specificationVendor);
420             sb.append(StringUtils.LINE_SEP);
421         }
422
423         if (null != implementationTitle) {
424             sb.append(IMPLEMENTATION_TITLE);
425             sb.append(brace);
426             sb.append(implementationTitle);
427             sb.append(StringUtils.LINE_SEP);
428         }
429
430         if (null != implementationVersion) {
431             sb.append(IMPLEMENTATION_VERSION);
432             sb.append(brace);
433             sb.append(implementationVersion);
434             sb.append(StringUtils.LINE_SEP);
435         }
436
437         if (null != implementationVendor) {
438             sb.append(IMPLEMENTATION_VENDOR);
439             sb.append(brace);
440             sb.append(implementationVendor);
441             sb.append(StringUtils.LINE_SEP);
442         }
443
444         return sb.toString();
445     }
446
447     /**
448      * Return <code>true</code> if the first version number is greater than
449      * or equal to the second; otherwise return <code>false</code>.
450      *
451      * @param first First version number (dotted decimal)
452      * @param second Second version number (dotted decimal)
453      */

454     private boolean isCompatible(final DeweyDecimal first,
455                                  final DeweyDecimal second) {
456         return first.isGreaterThanOrEqual(second);
457     }
458
459     /**
460      * Combine all specifications objects that are identical except
461      * for the sections.
462      *
463      * <p>Note this is very inefficent and should probably be fixed
464      * in the future.</p>
465      *
466      * @param list the array of results to trim
467      * @return an array list with all duplicates removed
468      */

469     private static ArrayList JavaDoc removeDuplicates(final ArrayList JavaDoc list) {
470         final ArrayList JavaDoc results = new ArrayList JavaDoc();
471         final ArrayList JavaDoc sections = new ArrayList JavaDoc();
472         while (list.size() > 0) {
473             final Specification specification = (Specification) list.remove(0);
474             final Iterator JavaDoc iterator = list.iterator();
475             while (iterator.hasNext()) {
476                 final Specification other = (Specification) iterator.next();
477                 if (isEqual(specification, other)) {
478                     final String JavaDoc[] otherSections = other.getSections();
479                     if (null != sections) {
480                         sections.addAll(Arrays.asList(otherSections));
481                     }
482                     iterator.remove();
483                 }
484             }
485
486             final Specification merged =
487                 mergeInSections(specification, sections);
488             results.add(merged);
489             //Reset list of sections
490
sections.clear();
491         }
492
493         return results;
494     }
495
496     /**
497      * Test if two specifications are equal except for their sections.
498      *
499      * @param specification one specificaiton
500      * @param other the ohter specification
501      * @return true if two specifications are equal except for their
502      * sections, else false
503      */

504     private static boolean isEqual(final Specification specification,
505                                     final Specification other) {
506         return
507             specification.getSpecificationTitle().equals(other.getSpecificationTitle())
508             && specification.getSpecificationVersion().isEqual(other.getSpecificationVersion())
509             && specification.getSpecificationVendor().equals(other.getSpecificationVendor())
510             && specification.getImplementationTitle().equals(other.getImplementationTitle())
511             && specification.getImplementationVersion().equals(other.getImplementationVersion())
512             && specification.getImplementationVendor().equals(other.getImplementationVendor());
513     }
514
515     /**
516      * Merge the specified sections into specified section and return result.
517      * If no sections to be added then just return original specification.
518      *
519      * @param specification the specification
520      * @param sectionsToAdd the list of sections to merge
521      * @return the merged specification
522      */

523     private static Specification mergeInSections(final Specification specification,
524                                               final ArrayList JavaDoc sectionsToAdd) {
525         if (0 == sectionsToAdd.size()) {
526             return specification;
527         }
528         sectionsToAdd.addAll(Arrays.asList(specification.getSections()));
529
530         final String JavaDoc[] sections =
531             (String JavaDoc[]) sectionsToAdd.toArray(new String JavaDoc[sectionsToAdd.size()]);
532
533         return new Specification(specification.getSpecificationTitle(),
534                 specification.getSpecificationVersion().toString(),
535                 specification.getSpecificationVendor(),
536                 specification.getImplementationTitle(),
537                 specification.getImplementationVersion(),
538                 specification.getImplementationVendor(),
539                 sections);
540     }
541
542     /**
543      * Trim the supplied string if the string is non-null
544      *
545      * @param value the string to trim or null
546      * @return the trimmed string or null
547      */

548     private static String JavaDoc getTrimmedString(final String JavaDoc value) {
549         return value == null ? null : value.trim();
550     }
551
552     /**
553      * Extract an Package Specification from Attributes.
554      *
555      * @param attributes Attributes to searched
556      * @return the new Specification object, or null
557      */

558     private static Specification getSpecification(final String JavaDoc section,
559                                                    final Attributes JavaDoc attributes)
560         throws ParseException JavaDoc {
561         //WARNING: We trim the values of all the attributes because
562
//Some extension declarations are badly defined (ie have spaces
563
//after version or vendor)
564
final String JavaDoc name
565             = getTrimmedString(attributes.getValue(SPECIFICATION_TITLE));
566         if (null == name) {
567             return null;
568         }
569
570         final String JavaDoc specVendor
571             = getTrimmedString(attributes.getValue(SPECIFICATION_VENDOR));
572         if (null == specVendor) {
573             throw new ParseException JavaDoc(MISSING + SPECIFICATION_VENDOR, 0);
574         }
575
576         final String JavaDoc specVersion
577             = getTrimmedString(attributes.getValue(SPECIFICATION_VERSION));
578         if (null == specVersion) {
579             throw new ParseException JavaDoc(MISSING + SPECIFICATION_VERSION, 0);
580         }
581
582         final String JavaDoc impTitle
583             = getTrimmedString(attributes.getValue(IMPLEMENTATION_TITLE));
584         if (null == impTitle) {
585             throw new ParseException JavaDoc(MISSING + IMPLEMENTATION_TITLE, 0);
586         }
587
588         final String JavaDoc impVersion
589             = getTrimmedString(attributes.getValue(IMPLEMENTATION_VERSION));
590         if (null == impVersion) {
591             throw new ParseException JavaDoc(MISSING + IMPLEMENTATION_VERSION, 0);
592         }
593
594         final String JavaDoc impVendor
595             = getTrimmedString(attributes.getValue(IMPLEMENTATION_VENDOR));
596         if (null == impVendor) {
597             throw new ParseException JavaDoc(MISSING + IMPLEMENTATION_VENDOR, 0);
598         }
599
600         return new Specification(name, specVersion, specVendor,
601                                   impTitle, impVersion, impVendor,
602                                   new String JavaDoc[]{section});
603     }
604 }
605
Popular Tags