source: other-projects/trunk/gs3-release-maker/apache-ant-1.6.5/src/main/org/apache/tools/ant/taskdefs/optional/extension/Extension.java@ 14627

Last change on this file since 14627 was 14627, checked in by oranfry, 17 years ago

initial import of the gs3-release-maker

File size: 25.3 KB
Line 
1/*
2 * Copyright 2002-2005 The Apache Software Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 *
16 */
17package org.apache.tools.ant.taskdefs.optional.extension;
18
19import java.util.ArrayList;
20import java.util.Iterator;
21import java.util.Map;
22import java.util.StringTokenizer;
23import java.util.jar.Attributes;
24import java.util.jar.Manifest;
25
26/**
27 * <p>Utility class that represents either an available "Optional Package"
28 * (formerly known as "Standard Extension") as described in the manifest
29 * of a JAR file, or the requirement for such an optional package.</p>
30 *
31 * <p>For more information about optional packages, see the document
32 * <em>Optional Package Versioning</em> in the documentation bundle for your
33 * Java2 Standard Edition package, in file
34 * <code>guide/extensions/versioning.html</code>.</p>
35 *
36 */
37public final class Extension {
38 /**
39 * Manifest Attribute Name object for EXTENSION_LIST.
40 */
41 public static final Attributes.Name EXTENSION_LIST
42 = new Attributes.Name("Extension-List");
43
44 /**
45 * <code>Name</code> object for <code>Optional-Extension-List</code>
46 * manifest attribute used for declaring optional dependencies on
47 * installed extensions. Note that the dependencies declared by this method
48 * are not required for the library to operate but if present will be used.
49 * It is NOT part of the official "Optional Package" specification.
50 *
51 * @see <a href="http://java.sun.com/j2se/1.3/docs/guide/extensions/spec.html#dependnecy">
52 * Installed extension dependency</a>
53 */
54 public static final Attributes.Name OPTIONAL_EXTENSION_LIST
55 = new Attributes.Name("Optional-Extension-List");
56
57 /**
58 * Manifest Attribute Name object for EXTENSION_NAME.
59 */
60 public static final Attributes.Name EXTENSION_NAME =
61 new Attributes.Name("Extension-Name");
62 /**
63 * Manifest Attribute Name object for SPECIFICATION_VERSION.
64 */
65 public static final Attributes.Name SPECIFICATION_VERSION
66 = Attributes.Name.SPECIFICATION_VERSION;
67
68 /**
69 * Manifest Attribute Name object for SPECIFICATION_VENDOR.
70 */
71 public static final Attributes.Name SPECIFICATION_VENDOR
72 = Attributes.Name.SPECIFICATION_VENDOR;
73
74 /**
75 * Manifest Attribute Name object for IMPLEMENTATION_VERSION.
76 */
77 public static final Attributes.Name IMPLEMENTATION_VERSION
78 = Attributes.Name.IMPLEMENTATION_VERSION;
79
80 /**
81 * Manifest Attribute Name object for IMPLEMENTATION_VENDOR.
82 */
83 public static final Attributes.Name IMPLEMENTATION_VENDOR
84 = Attributes.Name.IMPLEMENTATION_VENDOR;
85
86 /**
87 * Manifest Attribute Name object for IMPLEMENTATION_URL.
88 */
89 public static final Attributes.Name IMPLEMENTATION_URL
90 = new Attributes.Name("Implementation-URL");
91
92 /**
93 * Manifest Attribute Name object for IMPLEMENTATION_VENDOR_ID.
94 */
95 public static final Attributes.Name IMPLEMENTATION_VENDOR_ID
96 = new Attributes.Name("Implementation-Vendor-Id");
97
98 /**
99 * Enum indicating that extension is compatible with other extension.
100 */
101 public static final Compatibility COMPATIBLE
102 = new Compatibility("COMPATIBLE");
103
104 /**
105 * Enum indicating that extension requires an upgrade
106 * of specification to be compatible with other extension.
107 */
108 public static final Compatibility REQUIRE_SPECIFICATION_UPGRADE
109 = new Compatibility("REQUIRE_SPECIFICATION_UPGRADE");
110
111 /**
112 * Enum indicating that extension requires a vendor
113 * switch to be compatible with other extension.
114 */
115 public static final Compatibility REQUIRE_VENDOR_SWITCH
116 = new Compatibility("REQUIRE_VENDOR_SWITCH");
117
118 /**
119 * Enum indicating that extension requires an upgrade
120 * of implementation to be compatible with other extension.
121 */
122 public static final Compatibility REQUIRE_IMPLEMENTATION_UPGRADE
123 = new Compatibility("REQUIRE_IMPLEMENTATION_UPGRADE");
124
125 /**
126 * Enum indicating that extension is incompatible with
127 * other extension in ways other than other enums
128 * indicate). For example the other extension may have
129 * a different ID.
130 */
131 public static final Compatibility INCOMPATIBLE
132 = new Compatibility("INCOMPATIBLE");
133
134 /**
135 * The name of the optional package being made available, or required.
136 */
137 private String extensionName;
138
139 /**
140 * The version number (dotted decimal notation) of the specification
141 * to which this optional package conforms.
142 */
143 private DeweyDecimal specificationVersion;
144
145 /**
146 * The name of the company or organization that originated the
147 * specification to which this optional package conforms.
148 */
149 private String specificationVendor;
150
151 /**
152 * The unique identifier of the company that produced the optional
153 * package contained in this JAR file.
154 */
155 private String implementationVendorID;
156
157 /**
158 * The name of the company or organization that produced this
159 * implementation of this optional package.
160 */
161 private String implementationVendor;
162
163 /**
164 * The version number (dotted decimal notation) for this implementation
165 * of the optional package.
166 */
167 private DeweyDecimal implementationVersion;
168
169 /**
170 * The URL from which the most recent version of this optional package
171 * can be obtained if it is not already installed.
172 */
173 private String implementationURL;
174
175 /**
176 * Return an array of <code>Extension</code> objects representing optional
177 * packages that are available in the JAR file associated with the
178 * specified <code>Manifest</code>. If there are no such optional
179 * packages, a zero-length array is returned.
180 *
181 * @param manifest Manifest to be parsed
182 * @return the "available" extensions in specified manifest
183 */
184 public static Extension[] getAvailable(final Manifest manifest) {
185 if (null == manifest) {
186 return new Extension[ 0 ];
187 }
188
189 final ArrayList results = new ArrayList();
190
191 final Attributes mainAttributes = manifest.getMainAttributes();
192 if (null != mainAttributes) {
193 final Extension extension = getExtension("", mainAttributes);
194 if (null != extension) {
195 results.add(extension);
196 }
197 }
198
199 final Map entries = manifest.getEntries();
200 final Iterator keys = entries.keySet().iterator();
201 while (keys.hasNext()) {
202 final String key = (String) keys.next();
203 final Attributes attributes = (Attributes) entries.get(key);
204 final Extension extension = getExtension("", attributes);
205 if (null != extension) {
206 results.add(extension);
207 }
208 }
209
210 return (Extension[]) results.toArray(new Extension[0]);
211 }
212
213 /**
214 * Return the set of <code>Extension</code> objects representing optional
215 * packages that are required by the application contained in the JAR
216 * file associated with the specified <code>Manifest</code>. If there
217 * are no such optional packages, a zero-length list is returned.
218 *
219 * @param manifest Manifest to be parsed
220 * @return the dependencies that are specified in manifes
221 */
222 public static Extension[] getRequired(final Manifest manifest) {
223 return getListed(manifest, Attributes.Name.EXTENSION_LIST);
224 }
225
226 /**
227 * Return the set of <code>Extension</code> objects representing "Optional
228 * Packages" that the application declares they will use if present. If
229 * there are no such optional packages, a zero-length list is returned.
230 *
231 * @param manifest Manifest to be parsed
232 * @return the optional dependencies that are specified in manifest
233 */
234 public static Extension[] getOptions(final Manifest manifest) {
235 return getListed(manifest, OPTIONAL_EXTENSION_LIST);
236 }
237
238 /**
239 * Add Extension to the specified manifest Attributes.
240 *
241 * @param attributes the attributes of manifest to add to
242 * @param extension the extension
243 */
244 public static void addExtension(final Extension extension,
245 final Attributes attributes) {
246 addExtension(extension, "", attributes);
247 }
248
249 /**
250 * Add Extension to the specified manifest Attributes.
251 * Use the specified prefix so that dependencies can added
252 * with a prefix such as "java3d-" etc.
253 *
254 * @param attributes the attributes of manifest to add to
255 * @param extension the extension
256 * @param prefix the name to prefix to extension
257 */
258 public static void addExtension(final Extension extension,
259 final String prefix,
260 final Attributes attributes) {
261 attributes.putValue(prefix + EXTENSION_NAME,
262 extension.getExtensionName());
263
264 final String specificationVendor = extension.getSpecificationVendor();
265 if (null != specificationVendor) {
266 attributes.putValue(prefix + SPECIFICATION_VENDOR,
267 specificationVendor);
268 }
269
270 final DeweyDecimal specificationVersion
271 = extension.getSpecificationVersion();
272 if (null != specificationVersion) {
273 attributes.putValue(prefix + SPECIFICATION_VERSION,
274 specificationVersion.toString());
275 }
276
277 final String implementationVendorID
278 = extension.getImplementationVendorID();
279 if (null != implementationVendorID) {
280 attributes.putValue(prefix + IMPLEMENTATION_VENDOR_ID,
281 implementationVendorID);
282 }
283
284 final String implementationVendor = extension.getImplementationVendor();
285 if (null != implementationVendor) {
286 attributes.putValue(prefix + IMPLEMENTATION_VENDOR,
287 implementationVendor);
288 }
289
290 final DeweyDecimal implementationVersion
291 = extension.getImplementationVersion();
292 if (null != implementationVersion) {
293 attributes.putValue(prefix + IMPLEMENTATION_VERSION,
294 implementationVersion.toString());
295 }
296
297 final String implementationURL = extension.getImplementationURL();
298 if (null != implementationURL) {
299 attributes.putValue(prefix + IMPLEMENTATION_URL,
300 implementationURL);
301 }
302 }
303
304 /**
305 * The constructor to create Extension object.
306 * Note that every component is allowed to be specified
307 * but only the extensionName is mandatory.
308 *
309 * @param extensionName the name of extension.
310 * @param specificationVersion the specification Version of extension.
311 * @param specificationVendor the specification Vendor of extension.
312 * @param implementationVersion the implementation Version of extension.
313 * @param implementationVendor the implementation Vendor of extension.
314 * @param implementationVendorId the implementation VendorId of extension.
315 * @param implementationURL the implementation URL of extension.
316 */
317 public Extension(final String extensionName,
318 final String specificationVersion,
319 final String specificationVendor,
320 final String implementationVersion,
321 final String implementationVendor,
322 final String implementationVendorId,
323 final String implementationURL) {
324 this.extensionName = extensionName;
325 this.specificationVendor = specificationVendor;
326
327 if (null != specificationVersion) {
328 try {
329 this.specificationVersion
330 = new DeweyDecimal(specificationVersion);
331 } catch (final NumberFormatException nfe) {
332 final String error = "Bad specification version format '"
333 + specificationVersion + "' in '" + extensionName
334 + "'. (Reason: " + nfe + ")";
335 throw new IllegalArgumentException(error);
336 }
337 }
338
339 this.implementationURL = implementationURL;
340 this.implementationVendor = implementationVendor;
341 this.implementationVendorID = implementationVendorId;
342
343 if (null != implementationVersion) {
344 try {
345 this.implementationVersion
346 = new DeweyDecimal(implementationVersion);
347 } catch (final NumberFormatException nfe) {
348 final String error = "Bad implementation version format '"
349 + implementationVersion + "' in '" + extensionName
350 + "'. (Reason: " + nfe + ")";
351 throw new IllegalArgumentException(error);
352 }
353 }
354
355 if (null == this.extensionName) {
356 throw new NullPointerException("extensionName property is null");
357 }
358 }
359
360 /**
361 * Get the name of the extension.
362 *
363 * @return the name of the extension
364 */
365 public String getExtensionName() {
366 return extensionName;
367 }
368
369 /**
370 * Get the vendor of the extensions specification.
371 *
372 * @return the vendor of the extensions specification.
373 */
374 public String getSpecificationVendor() {
375 return specificationVendor;
376 }
377
378 /**
379 * Get the version of the extensions specification.
380 *
381 * @return the version of the extensions specification.
382 */
383 public DeweyDecimal getSpecificationVersion() {
384 return specificationVersion;
385 }
386
387 /**
388 * Get the url of the extensions implementation.
389 *
390 * @return the url of the extensions implementation.
391 */
392 public String getImplementationURL() {
393 return implementationURL;
394 }
395
396 /**
397 * Get the vendor of the extensions implementation.
398 *
399 * @return the vendor of the extensions implementation.
400 */
401 public String getImplementationVendor() {
402 return implementationVendor;
403 }
404
405 /**
406 * Get the vendorID of the extensions implementation.
407 *
408 * @return the vendorID of the extensions implementation.
409 */
410 public String getImplementationVendorID() {
411 return implementationVendorID;
412 }
413
414 /**
415 * Get the version of the extensions implementation.
416 *
417 * @return the version of the extensions implementation.
418 */
419 public DeweyDecimal getImplementationVersion() {
420 return implementationVersion;
421 }
422
423 /**
424 * Return a Compatibility enum indicating the relationship of this
425 * <code>Extension</code> with the specified <code>Extension</code>.
426 *
427 * @param required Description of the required optional package
428 * @return the enum indicating the compatibility (or lack thereof)
429 * of specifed extension
430 */
431 public Compatibility getCompatibilityWith(final Extension required) {
432 // Extension Name must match
433 if (!extensionName.equals(required.getExtensionName())) {
434 return INCOMPATIBLE;
435 }
436
437 // Available specification version must be >= required
438 final DeweyDecimal requiredSpecificationVersion
439 = required.getSpecificationVersion();
440 if (null != requiredSpecificationVersion) {
441 if (null == specificationVersion
442 || !isCompatible(specificationVersion, requiredSpecificationVersion)) {
443 return REQUIRE_SPECIFICATION_UPGRADE;
444 }
445 }
446
447 // Implementation Vendor ID must match
448 final String requiredImplementationVendorID
449 = required.getImplementationVendorID();
450 if (null != requiredImplementationVendorID) {
451 if (null == implementationVendorID
452 || !implementationVendorID.equals(requiredImplementationVendorID)) {
453 return REQUIRE_VENDOR_SWITCH;
454 }
455 }
456
457 // Implementation version must be >= required
458 final DeweyDecimal requiredImplementationVersion
459 = required.getImplementationVersion();
460 if (null != requiredImplementationVersion) {
461 if (null == implementationVersion
462 || !isCompatible(implementationVersion, requiredImplementationVersion)) {
463 return REQUIRE_IMPLEMENTATION_UPGRADE;
464 }
465 }
466
467 // This available optional package satisfies the requirements
468 return COMPATIBLE;
469 }
470
471 /**
472 * Return <code>true</code> if the specified <code>Extension</code>
473 * (which represents an optional package required by an application)
474 * is satisfied by this <code>Extension</code> (which represents an
475 * optional package that is already installed. Otherwise, return
476 * <code>false</code>.
477 *
478 * @param required Description of the required optional package
479 * @return true if the specified extension is compatible with this extension
480 */
481 public boolean isCompatibleWith(final Extension required) {
482 return (COMPATIBLE == getCompatibilityWith(required));
483 }
484
485 /**
486 * Return a String representation of this object.
487 *
488 * @return string representation of object.
489 */
490 public String toString() {
491 final String lineSeparator = System.getProperty("line.separator");
492 final String brace = ": ";
493
494 final StringBuffer sb = new StringBuffer(EXTENSION_NAME.toString());
495 sb.append(brace);
496 sb.append(extensionName);
497 sb.append(lineSeparator);
498
499 if (null != specificationVersion) {
500 sb.append(SPECIFICATION_VERSION);
501 sb.append(brace);
502 sb.append(specificationVersion);
503 sb.append(lineSeparator);
504 }
505
506 if (null != specificationVendor) {
507 sb.append(SPECIFICATION_VENDOR);
508 sb.append(brace);
509 sb.append(specificationVendor);
510 sb.append(lineSeparator);
511 }
512
513 if (null != implementationVersion) {
514 sb.append(IMPLEMENTATION_VERSION);
515 sb.append(brace);
516 sb.append(implementationVersion);
517 sb.append(lineSeparator);
518 }
519
520 if (null != implementationVendorID) {
521 sb.append(IMPLEMENTATION_VENDOR_ID);
522 sb.append(brace);
523 sb.append(implementationVendorID);
524 sb.append(lineSeparator);
525 }
526
527 if (null != implementationVendor) {
528 sb.append(IMPLEMENTATION_VENDOR);
529 sb.append(brace);
530 sb.append(implementationVendor);
531 sb.append(lineSeparator);
532 }
533
534 if (null != implementationURL) {
535 sb.append(IMPLEMENTATION_URL);
536 sb.append(brace);
537 sb.append(implementationURL);
538 sb.append(lineSeparator);
539 }
540
541 return sb.toString();
542 }
543
544 /**
545 * Return <code>true</code> if the first version number is greater than
546 * or equal to the second; otherwise return <code>false</code>.
547 *
548 * @param first First version number (dotted decimal)
549 * @param second Second version number (dotted decimal)
550 */
551 private boolean isCompatible(final DeweyDecimal first,
552 final DeweyDecimal second) {
553 return first.isGreaterThanOrEqual(second);
554 }
555
556 /**
557 * Retrieve all the extensions listed under a particular key
558 * (Usually EXTENSION_LIST or OPTIONAL_EXTENSION_LIST).
559 *
560 * @param manifest the manifest to extract extensions from
561 * @param listKey the key used to get list (Usually
562 * EXTENSION_LIST or OPTIONAL_EXTENSION_LIST)
563 * @return the list of listed extensions
564 */
565 private static Extension[] getListed(final Manifest manifest,
566 final Attributes.Name listKey) {
567 final ArrayList results = new ArrayList();
568 final Attributes mainAttributes = manifest.getMainAttributes();
569
570 if (null != mainAttributes) {
571 getExtension(mainAttributes, results, listKey);
572 }
573
574 final Map entries = manifest.getEntries();
575 final Iterator keys = entries.keySet().iterator();
576 while (keys.hasNext()) {
577 final String key = (String) keys.next();
578 final Attributes attributes = (Attributes) entries.get(key);
579 getExtension(attributes, results, listKey);
580 }
581
582 return (Extension[]) results.toArray(new Extension[ 0 ]);
583 }
584
585 /**
586 * Add required optional packages defined in the specified
587 * attributes entry, if any.
588 *
589 * @param attributes Attributes to be parsed
590 * @param required list to add required optional packages to
591 * @param listKey the key to use to lookup list, usually EXTENSION_LIST
592 * or OPTIONAL_EXTENSION_LIST
593 */
594 private static void getExtension(final Attributes attributes,
595 final ArrayList required,
596 final Attributes.Name listKey) {
597 final String names = attributes.getValue(listKey);
598 if (null == names) {
599 return;
600 }
601
602 final String[] extentions = split(names, " ");
603 for (int i = 0; i < extentions.length; i++) {
604 final String prefix = extentions[ i ] + "-";
605 final Extension extension = getExtension(prefix, attributes);
606
607 if (null != extension) {
608 required.add(extension);
609 }
610 }
611 }
612
613 /**
614 * Splits the string on every token into an array of strings.
615 *
616 * @param string the string
617 * @param onToken the token
618 * @return the resultant array
619 */
620 private static final String[] split(final String string,
621 final String onToken) {
622 final StringTokenizer tokenizer = new StringTokenizer(string, onToken);
623 final String[] result = new String[ tokenizer.countTokens() ];
624
625 for (int i = 0; i < result.length; i++) {
626 result[ i ] = tokenizer.nextToken();
627 }
628
629 return result;
630 }
631
632 /**
633 * Extract an Extension from Attributes.
634 * Prefix indicates the prefix checked for each string.
635 * Usually the prefix is <em>"&lt;extension&gt;-"</em> if looking for a
636 * <b>Required</b> extension. If you are looking for an
637 * <b>Available</b> extension
638 * then the prefix is <em>""</em>.
639 *
640 * @param prefix the prefix for each attribute name
641 * @param attributes Attributes to searched
642 * @return the new Extension object, or null
643 */
644 private static Extension getExtension(final String prefix,
645 final Attributes attributes) {
646 //WARNING: We trim the values of all the attributes because
647 //Some extension declarations are badly defined (ie have spaces
648 //after version or vendorID)
649 final String nameKey = prefix + EXTENSION_NAME;
650 final String name = getTrimmedString(attributes.getValue(nameKey));
651 if (null == name) {
652 return null;
653 }
654
655 final String specVendorKey = prefix + SPECIFICATION_VENDOR;
656 final String specVendor
657 = getTrimmedString(attributes.getValue(specVendorKey));
658 final String specVersionKey = prefix + SPECIFICATION_VERSION;
659 final String specVersion
660 = getTrimmedString(attributes.getValue(specVersionKey));
661
662 final String impVersionKey = prefix + IMPLEMENTATION_VERSION;
663 final String impVersion
664 = getTrimmedString(attributes.getValue(impVersionKey));
665 final String impVendorKey = prefix + IMPLEMENTATION_VENDOR;
666 final String impVendor
667 = getTrimmedString(attributes.getValue(impVendorKey));
668 final String impVendorIDKey = prefix + IMPLEMENTATION_VENDOR_ID;
669 final String impVendorId
670 = getTrimmedString(attributes.getValue(impVendorIDKey));
671 final String impURLKey = prefix + IMPLEMENTATION_URL;
672 final String impURL = getTrimmedString(attributes.getValue(impURLKey));
673
674 return new Extension(name, specVersion, specVendor, impVersion,
675 impVendor, impVendorId, impURL);
676 }
677
678 /**
679 * Trim the supplied string if the string is non-null
680 *
681 * @param value the string to trim or null
682 * @return the trimmed string or null
683 */
684 private static String getTrimmedString(final String value) {
685 if (null == value) {
686 return null;
687 } else {
688 return value.trim();
689 }
690 }
691}
Note: See TracBrowser for help on using the repository browser.