KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > avalon > extension > Specification


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

17
18 package org.apache.avalon.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 /**
29  * <p>Utility class that represents either an available "Optional Package"
30  * (formerly known as "Standard Extension") as described in the manifest
31  * of a JAR file, or the requirement for such an optional package.</p>
32  *
33  * <p>For more information about optional packages, see the document
34  * <em>Optional Package Versioning</em> in the documentation bundle for your
35  * Java2 Standard Edition package, in file
36  * <code>guide/extensions/versioning.html</code>.</p>
37  *
38  * @author <a HREF="mailto:dev@avalon.apache.org">Avalon Development Team</a>
39  * @version $Revision: 1.3 $ $Date: 2004/04/06 07:42:48 $
40  */

41 public final class Specification
42 {
43     /**
44      * Manifest Attribute Name object for SPECIFICATION_TITLE.
45      * @see java.util.jar.Attributes.Name#SPECIFICATION_TITLE
46      */

47     public static final Attributes.Name JavaDoc SPECIFICATION_TITLE = Attributes.Name.SPECIFICATION_TITLE;
48
49     /**
50      * Manifest Attribute Name object for SPECIFICATION_VERSION.
51      * @see java.util.jar.Attributes.Name#SPECIFICATION_VERSION
52      */

53     public static final Attributes.Name JavaDoc SPECIFICATION_VERSION = Attributes.Name.SPECIFICATION_VERSION;
54
55     /**
56      * Manifest Attribute Name object for SPECIFICATION_VENDOR.
57      * @see java.util.jar.Attributes.Name#SPECIFICATION_VENDOR
58      */

59     public static final Attributes.Name JavaDoc SPECIFICATION_VENDOR = Attributes.Name.SPECIFICATION_VENDOR;
60
61     /**
62      * Manifest Attribute Name object for IMPLEMENTATION_TITLE.
63      * @see java.util.jar.Attributes.Name#IMPLEMENTATION_TITLE
64      */

65     public static final Attributes.Name JavaDoc IMPLEMENTATION_TITLE = Attributes.Name.IMPLEMENTATION_TITLE;
66
67     /**
68      * Manifest Attribute Name object for IMPLEMENTATION_VERSION.
69      * @see java.util.jar.Attributes.Name#IMPLEMENTATION_VERSION
70      */

71     public static final Attributes.Name JavaDoc IMPLEMENTATION_VERSION = Attributes.Name.IMPLEMENTATION_VERSION;
72
73     /**
74      * Manifest Attribute Name object for IMPLEMENTATION_VENDOR.
75      * @see java.util.jar.Attributes.Name#IMPLEMENTATION_VENDOR
76      */

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

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

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

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

104     public static final Compatability REQUIRE_IMPLEMENTATION_CHANGE =
105         new Compatability( "REQUIRE_IMPLEMENTATION_CHANGE" );
106
107     /**
108      * Enum indicating that extension is incompatible with
109      * other Package Specification in ways other than other enums
110      * indicate). ie For example the other Package Specification
111      * may have a different ID.
112      */

113     public static final Compatability INCOMPATIBLE =
114         new Compatability( "INCOMPATIBLE" );
115
116     /**
117      * The name of the Package Specification.
118      */

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

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

131     private String JavaDoc m_specificationVendor;
132
133     /**
134      * The title of implementation.
135      */

136     private String JavaDoc m_implementationTitle;
137
138     /**
139      * The name of the company or organization that produced this
140      * implementation of this specification.
141      */

142     private String JavaDoc m_implementationVendor;
143
144     /**
145      * The version string for implementation. The version string is
146      * opaque.
147      */

148     private String JavaDoc m_implementationVersion;
149
150     /**
151      * The sections of jar that the specification applies to.
152      */

153     private String JavaDoc[] m_sections;
154
155     /**
156      * Return an array of <code>Package Specification</code> objects.
157      * If there are no such optional packages, a zero-length array is returned.
158      *
159      * @param manifest Manifest to be parsed
160      * @return the Package Specifications extensions in specified manifest
161      */

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

201     public Specification( final String JavaDoc specificationTitle,
202                           final String JavaDoc specificationVersion,
203                           final String JavaDoc specificationVendor,
204                           final String JavaDoc implementationTitle,
205                           final String JavaDoc implementationVersion,
206                           final String JavaDoc implementationVendor )
207     {
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     {
234         m_specificationTitle = specificationTitle;
235         m_specificationVendor = specificationVendor;
236
237         if( null != specificationVersion )
238         {
239             try
240             {
241                 m_specificationVersion = new DeweyDecimal( specificationVersion );
242             }
243             catch( final NumberFormatException JavaDoc nfe )
244             {
245                 //
246
// don't complain because maven is generating illegal
247
// spec values by default - instead we leave it as null
248
//
249

250                 //
251
//final String error =
252
// "Bad specification version format '" + specificationVersion +
253
// "' in '" + specificationTitle + "'. (Reason: " + nfe + ")";
254
//throw new IllegalArgumentException( error );
255
}
256         }
257
258         m_implementationTitle = implementationTitle;
259         m_implementationVendor = implementationVendor;
260         m_implementationVersion = implementationVersion;
261
262         if( null == m_specificationTitle )
263         {
264             throw new NullPointerException JavaDoc( "specificationTitle" );
265         }
266
267         String JavaDoc[] copy = null;
268         if( null != sections )
269         {
270             copy = new String JavaDoc[ sections.length ];
271             System.arraycopy( sections, 0, copy, 0, sections.length );
272         }
273         m_sections = copy;
274     }
275
276     /**
277      * Get the title of the specification.
278      *
279      * @return the title of speciication
280      */

281     public String JavaDoc getSpecificationTitle()
282     {
283         return m_specificationTitle;
284     }
285
286     /**
287      * Get the vendor of the specification.
288      *
289      * @return the vendor of the specification.
290      */

291     public String JavaDoc getSpecificationVendor()
292     {
293         return m_specificationVendor;
294     }
295
296     /**
297      * Get the title of the specification.
298      *
299      * @return the title of the specification.
300      */

301     public String JavaDoc getImplementationTitle()
302     {
303         return m_implementationTitle;
304     }
305
306     /**
307      * Get the version of the specification.
308      *
309      * @return the version of the specification.
310      */

311     public DeweyDecimal getSpecificationVersion()
312     {
313         return m_specificationVersion;
314     }
315
316     /**
317      * Get the vendor of the extensions implementation.
318      *
319      * @return the vendor of the extensions implementation.
320      */

321     public String JavaDoc getImplementationVendor()
322     {
323         return m_implementationVendor;
324     }
325
326     /**
327      * Get the version of the implementation.
328      *
329      * @return the version of the implementation.
330      */

331     public String JavaDoc getImplementationVersion()
332     {
333         return m_implementationVersion;
334     }
335
336     /**
337      * Return an array containing sections to which specification applies
338      * or null if relevant to no sections.
339      *
340      * @return an array containing sections to which specification applies
341      * or null if relevant to no sections.
342      */

343     public String JavaDoc[] getSections()
344     {
345         if( null == m_sections )
346         {
347             return null;
348         }
349         else
350         {
351             final String JavaDoc[] sections = new String JavaDoc[ m_sections.length ];
352             System.arraycopy( m_sections, 0, sections, 0, m_sections.length );
353             return sections;
354         }
355     }
356
357     /**
358      * Return a Compatibility enum indicating the relationship of this
359      * <code>Package Specification</code> with the specified <code>Extension</code>.
360      *
361      * @param other the other specification
362      * @return the enum indicating the compatability (or lack thereof)
363      * of specifed Package Specification
364      */

365     public Compatability getCompatibilityWith( final Specification other )
366     {
367         // Specification Name must match
368
if( !m_specificationTitle.equals( other.getSpecificationTitle() ) )
369         {
370             return INCOMPATIBLE;
371         }
372
373         // Available specification version must be >= required
374
final DeweyDecimal specificationVersion = other.getSpecificationVersion();
375         if( null != specificationVersion )
376         {
377             if( null == m_specificationVersion ||
378                 !isCompatible( m_specificationVersion, specificationVersion ) )
379             {
380                 return REQUIRE_SPECIFICATION_UPGRADE;
381             }
382         }
383
384         // Implementation Vendor ID must match
385
final String JavaDoc implementationVendor = other.getImplementationVendor();
386         if( null != implementationVendor )
387         {
388             if( null == m_implementationVendor ||
389                 !m_implementationVendor.equals( implementationVendor ) )
390             {
391                 return REQUIRE_VENDOR_SWITCH;
392             }
393         }
394
395         // Implementation version must be >= required
396
final String JavaDoc implementationVersion = other.getImplementationVersion();
397         if( null != implementationVersion )
398         {
399             if( null == m_implementationVersion ||
400                 !m_implementationVersion.equals( implementationVersion ) )
401             {
402                 return REQUIRE_IMPLEMENTATION_CHANGE;
403             }
404         }
405
406         // This available optional package satisfies the requirements
407
return COMPATIBLE;
408     }
409
410     /**
411      * Return <code>true</code> if the specified <code>package</code>
412      * is satisfied by this <code>Specification</code>. Otherwise, return
413      * <code>false</code>.
414      *
415      * @param other the specification
416      * @return true if the specification is compatible with this specification
417      */

418     public boolean isCompatibleWith( final Specification other )
419     {
420         return ( COMPATIBLE == getCompatibilityWith( other ) );
421     }
422
423     /**
424      * Return a String representation of this object.
425      *
426      * @return string representation of object.
427      */

428     public String JavaDoc toString()
429     {
430         final String JavaDoc lineSeparator = System.getProperty( "line.separator" );
431         final String JavaDoc brace = ": ";
432
433         final StringBuffer JavaDoc sb = new StringBuffer JavaDoc( SPECIFICATION_TITLE.toString() );
434         sb.append( brace );
435         sb.append( m_specificationTitle );
436         sb.append( lineSeparator );
437
438         if( null != m_specificationVersion )
439         {
440             sb.append( SPECIFICATION_VERSION );
441             sb.append( brace );
442             sb.append( m_specificationVersion );
443             sb.append( lineSeparator );
444         }
445
446         if( null != m_specificationVendor )
447         {
448             sb.append( SPECIFICATION_VENDOR );
449             sb.append( brace );
450             sb.append( m_specificationVendor );
451             sb.append( lineSeparator );
452         }
453
454         if( null != m_implementationTitle )
455         {
456             sb.append( IMPLEMENTATION_TITLE );
457             sb.append( brace );
458             sb.append( m_implementationTitle );
459             sb.append( lineSeparator );
460         }
461
462         if( null != m_implementationVersion )
463         {
464             sb.append( IMPLEMENTATION_VERSION );
465             sb.append( brace );
466             sb.append( m_implementationVersion );
467             sb.append( lineSeparator );
468         }
469
470         if( null != m_implementationVendor )
471         {
472             sb.append( IMPLEMENTATION_VENDOR );
473             sb.append( brace );
474             sb.append( m_implementationVendor );
475             sb.append( lineSeparator );
476         }
477
478         return sb.toString();
479     }
480
481     /**
482      * Return <code>true</code> if the first version number is greater than
483      * or equal to the second; otherwise return <code>false</code>.
484      *
485      * @param first First version number (dotted decimal)
486      * @param second Second version number (dotted decimal)
487      */

488     private boolean isCompatible( final DeweyDecimal first, final DeweyDecimal second )
489     {
490         return first.isGreaterThanOrEqual( second );
491     }
492
493     /**
494      * Combine all specifications objects that are identical except
495      * for the sections.
496      *
497      * <p>Note this is very inefficent and should probably be fixed
498      * in the future.</p>
499      *
500      * @param list the array of results to trim
501      * @return an array list with all duplicates removed
502      */

503     private static ArrayList JavaDoc removeDuplicates( final ArrayList JavaDoc list )
504     {
505         final ArrayList JavaDoc results = new ArrayList JavaDoc();
506         final ArrayList JavaDoc sections = new ArrayList JavaDoc();
507         while( list.size() > 0 )
508         {
509             final Specification specification = (Specification)list.remove( 0 );
510             final Iterator JavaDoc iterator = list.iterator();
511             while( iterator.hasNext() )
512             {
513                 final Specification other = (Specification)iterator.next();
514                 if( isEqual( specification, other ) )
515                 {
516                     final String JavaDoc[] otherSections = other.getSections();
517                     if( null != sections )
518                     {
519                         sections.addAll( Arrays.asList( otherSections ) );
520                     }
521                     iterator.remove();
522                 }
523             }
524
525             final Specification merged =
526                 mergeInSections( specification, sections );
527             results.add( merged );
528             //Reset list of sections
529
sections.clear();
530         }
531
532         return results;
533     }
534
535     /**
536      * Test if two specifications are equal except for their sections.
537      *
538      * @param specification one specificaiton
539      * @param other the ohter specification
540      * @return true if two specifications are equal except for their
541      * sections, else false
542      */

543     private static boolean isEqual( final Specification specification,
544                                     final Specification other )
545     {
546         return
547             specification.getSpecificationTitle().equals( other.getSpecificationTitle() ) &&
548             specification.getSpecificationVersion().isEqual( other.getSpecificationVersion() ) &&
549             specification.getSpecificationVendor().equals( other.getSpecificationVendor() ) &&
550             specification.getImplementationTitle().equals( other.getImplementationTitle() ) &&
551             specification.getImplementationVersion().equals( other.getImplementationVersion() ) &&
552             specification.getImplementationVendor().equals( other.getImplementationVendor() );
553     }
554
555     /**
556      * Merge the specified sections into specified section and return result.
557      * If no sections to be added then just return original specification.
558      *
559      * @param specification the specification
560      * @param sectionsToAdd the list of sections to merge
561      * @return the merged specification
562      */

563     private static Specification mergeInSections( final Specification specification,
564                                                   final ArrayList JavaDoc sectionsToAdd )
565     {
566         if( 0 == sectionsToAdd.size() )
567         {
568             return specification;
569         }
570         else
571         {
572             sectionsToAdd.addAll( Arrays.asList( specification.getSections() ) );
573
574             final String JavaDoc[] sections =
575                 (String JavaDoc[])sectionsToAdd.toArray( new String JavaDoc[ sectionsToAdd.size() ] );
576
577             return new Specification( specification.getSpecificationTitle(),
578                                       specification.getSpecificationVersion().toString(),
579                                       specification.getSpecificationVendor(),
580                                       specification.getImplementationTitle(),
581                                       specification.getImplementationVersion(),
582                                       specification.getImplementationVendor(),
583                                       sections );
584         }
585     }
586
587     /**
588      * Trim the supplied string if the string is non-null
589      *
590      * @param value the string to trim or null
591      * @return the trimmed string or null
592      */

593     private static String JavaDoc getTrimmedString( final String JavaDoc value )
594     {
595         if( null == value )
596         {
597             return null;
598         }
599         else
600         {
601             return value.trim();
602         }
603     }
604
605     /**
606      * Extract an Package Specification from Attributes.
607      *
608      * @param attributes Attributes to searched
609      * @return the new Specification object, or null
610      */

611     private static Specification getSpecification( final String JavaDoc section,
612                                                    final Attributes JavaDoc attributes )
613         throws ParseException JavaDoc
614     {
615         //WARNING: We trim the values of all the attributes because
616
//Some extension declarations are badly defined (ie have spaces
617
//after version or vendor)
618
final String JavaDoc name = getTrimmedString( attributes.getValue( SPECIFICATION_TITLE ) );
619         if( null == name )
620         {
621             return null;
622         }
623
624         final String JavaDoc specVendor = getTrimmedString( attributes.getValue( SPECIFICATION_VENDOR ) );
625         if( null == specVendor )
626         {
627             throw new ParseException JavaDoc( "Missing " + SPECIFICATION_VENDOR, 0 );
628         }
629
630         final String JavaDoc specVersion = getTrimmedString( attributes.getValue( SPECIFICATION_VERSION ) );
631         if( null == specVersion )
632         {
633             throw new ParseException JavaDoc( "Missing " + SPECIFICATION_VERSION, 0 );
634         }
635
636         final String JavaDoc impTitle = getTrimmedString( attributes.getValue( IMPLEMENTATION_TITLE ) );
637         if( null == impTitle )
638         {
639             throw new ParseException JavaDoc( "Missing " + IMPLEMENTATION_TITLE, 0 );
640         }
641
642         final String JavaDoc impVersion = getTrimmedString( attributes.getValue( IMPLEMENTATION_VERSION ) );
643         if( null == impVersion )
644         {
645             throw new ParseException JavaDoc( "Missing " + IMPLEMENTATION_VERSION, 0 );
646         }
647
648         final String JavaDoc impVendor = getTrimmedString( attributes.getValue( IMPLEMENTATION_VENDOR ) );
649         if( null == impVendor )
650         {
651             throw new ParseException JavaDoc( "Missing " + IMPLEMENTATION_VENDOR, 0 );
652         }
653
654         return new Specification( name, specVersion, specVendor,
655                                   impTitle, impVersion, impVendor,
656                                   new String JavaDoc[]{section} );
657     }
658 }
659
Popular Tags