View Javadoc
1   package org.codehaus.plexus.component.repository;
2   
3   /*
4    * Copyright 2001-2006 Codehaus Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * You may obtain a copy of the License at
9    *
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   *
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  
19  import org.codehaus.plexus.PlexusConstants;
20  import org.codehaus.plexus.classworlds.realm.ClassRealm;
21  import org.codehaus.plexus.configuration.PlexusConfiguration;
22  
23  import java.util.ArrayList;
24  import java.util.List;
25  import java.util.Arrays;
26  import java.util.Collections;
27  
28  /**
29   * Component instantiation description.
30   *
31   * @author Jason van Zyl
32   * @author <a href="mailto:bob@eng.werken.com">bob mcwhirter</a>
33   * @author <a href="mailto:mmaczka@interia.pl">Michal Maczka</a>
34   */
35  public class ComponentDescriptor<T>
36  {
37      private String alias = null;
38  
39      private String role = null;
40  
41      private Class<T> roleClass;
42  
43      private String roleHint = PlexusConstants.PLEXUS_DEFAULT_HINT;
44  
45      private String implementation;
46  
47      private Class<? extends T> implementationClass;
48  
49      private String version;
50  
51      private String componentType;
52  
53      private PlexusConfiguration configuration;
54  
55      private String instantiationStrategy;
56  
57      private String lifecycleHandler;
58  
59      private String componentProfile;
60  
61      private final List<ComponentRequirement> requirements = new ArrayList<ComponentRequirement>();
62  
63      private String componentFactory;
64  
65      private String componentComposer;
66  
67      private String componentConfigurator;
68  
69      private String description;
70  
71      private ClassRealm realm;
72  
73      // ----------------------------------------------------------------------
74      // These two fields allow for the specification of an isolated class realm
75      // and dependencies that might be specified in a component configuration
76      // setup by a user i.e. this is here to allow isolation for components
77      // that are not picked up by the discovery mechanism.
78      // ----------------------------------------------------------------------
79  
80      private boolean isolatedRealm;
81  
82      // ----------------------------------------------------------------------
83  
84      private ComponentSetDescriptor componentSetDescriptor;
85  
86      private String source;
87  
88      // ----------------------------------------------------------------------
89      // Instance methods
90      // ----------------------------------------------------------------------
91  
92      public ComponentDescriptor()
93      {
94      }
95  
96      public ComponentDescriptor( Class<T> implementationClass, ClassRealm realm )
97      {
98          this.implementationClass = implementationClass;
99          this.implementation = implementationClass.getName();
100         this.realm = realm;
101     }
102 
103     /**
104      * The location this information came from (descriptor file URI).
105      * @param source The source of the descriptor.
106      */
107     public void setSource( String source )
108     {
109         this.source = source;
110     }
111 
112     /**
113      * The location this information came from (descriptor file URI).
114      * @return The source.
115      */
116     public String getSource()
117     {
118         return source;
119     }
120 
121     /**
122      * Returns a human-friendly key, suitable for display.
123      *
124      * @return a human-friendly key
125      */
126     public String getHumanReadableKey()
127     {
128         StringBuilder key = new StringBuilder();
129 
130         key.append( "role: '" ).append( getRole() ).append( "'" );
131 
132         key.append( ", implementation: '" ).append( getImplementation() ).append( "'" );
133 
134         if ( roleHint != null )
135         {
136             key.append( ", role hint: '" ).append( getRoleHint() ).append( "'" );
137         }
138 
139         if ( alias != null )
140         {
141             key.append( ", alias: '" ).append( getAlias() ).append( "'" );
142         }
143 
144         return key.toString();
145     }
146 
147     /**
148      * Returns an alias for this component. An alias as an alternate name other than the normal key.
149      *
150      * @return an alias for this component
151      */
152     public String getAlias()
153     {
154         return alias;
155     }
156 
157     /**
158      * Sets the alias for this component.
159      *
160      * @param alias alternate name to set
161      */
162     public void setAlias( String alias )
163     {
164         this.alias = alias;
165     }
166 
167     /**
168      * Returns the role of this component.
169      *
170      * @return the role of this component
171      */
172     public String getRole()
173     {
174         return role;
175     }
176 
177     public Class<T> getRoleClass()
178     {
179         attemptRoleLoad();
180 
181         if (roleClass == null) {
182             return (Class<T>) Object.class;
183         }
184         return (Class<T>) roleClass;
185     }
186 
187     private void attemptRoleLoad()
188     {
189         if ( roleClass == null && getRole() != null && getRealm() != null )
190         {
191             try
192             {
193                 roleClass = (Class<T>) getRealm().loadClass( getRole() );
194                 Thread.currentThread();
195             }
196             catch ( Throwable ignored )
197             {
198                 Thread.currentThread();
199             }
200         }
201     }
202 
203 
204     /**
205      * Sets the role of this component.
206      *
207      * @param role this component's role
208      */
209     public void setRole( String role )
210     {
211         this.role = role;
212 
213         // reload role class
214         roleClass = null;
215         attemptRoleLoad();
216     }
217 
218     public void setRoleClass( Class<T> roleClass )
219     {
220         this.roleClass = roleClass;
221 
222         if (roleClass == null) {
223             role = null;
224         } else {
225             role = roleClass.getName();
226         }
227     }
228 
229     /**
230      * Returns the role-hint of this component.
231      *
232      * @return the role-hint of this component
233      */
234     public String getRoleHint()
235     {
236         return roleHint;
237     }
238 
239     /**
240      * Sets the role-hint of this component. Pasing null will set the hint to the default value.
241      *
242      * @param roleHint this component's role-hint
243      */
244     public void setRoleHint( String roleHint )
245     {
246         if ( ( roleHint == null ) || roleHint.trim().equals( "" ) )
247         {
248             this.roleHint = PlexusConstants.PLEXUS_DEFAULT_HINT;
249         }
250         else
251         {
252             this.roleHint = roleHint;
253         }
254     }
255 
256     /**
257      * Returns the implementation of this componet. Implementation is a string denoting a FQCN in normal Java
258      * components, or some other name or file for other component factory implementations.
259      *
260      * @return the implementation of this componet's role.
261      */
262     public String getImplementation()
263     {
264         return implementation;
265     }
266 
267     /**
268      * Sets the implementation of this componet.
269      *
270      * @param implementation string denoting a FQCN in normal Java components, or some other name or file for other
271      *        component factory implementations
272      */
273     public void setImplementation( String implementation )
274     {
275         this.implementation = implementation;
276 
277         // reload implementation class
278         implementationClass = null;
279         attemptImplementationLoad();
280     }
281 
282     /**
283      * Returns the implementation class of this componet, or null if the implementation class can not be loaded.
284      *
285      * @return the implementation of this componet's role.
286      */
287     public Class<? extends T> getImplementationClass()
288     {
289         attemptImplementationLoad();
290 
291         if (implementationClass == null) {
292             return (Class<T>) Object.class;
293         }
294         return (Class<T>)implementationClass;
295     }
296 
297     private void attemptImplementationLoad()
298     {
299         if ( implementationClass == null && getImplementation() != null && getRealm() != null )
300         {
301             try
302             {
303                 implementationClass = (Class<? extends T>) getRealm().loadClass( getImplementation() );
304                 Thread.currentThread();
305             }
306             catch ( Throwable ignored )
307             {
308                 Thread.currentThread();
309             }
310         }
311     }
312 
313     public void setImplementationClass( Class<? extends T> implementationClass )
314     {
315         this.implementationClass = implementationClass;
316         if (implementationClass == null) {
317             implementation = null;
318         } else {
319             implementation = implementationClass.getName();
320         }
321     }
322 
323     /**
324      * Returns a specific point in a components's project timeline. i.e. version 1, or 2.1.4
325      *
326      * @return a specific point in a components's project timeline
327      */
328     public String getVersion()
329     {
330         return version;
331     }
332 
333     /**
334      * Sets the point in a components's project development timeline
335      *
336      * @param version the components's version
337      */
338     public void setVersion( String version )
339     {
340         this.version = version;
341     }
342 
343     /**
344      * Returns the type of this component.
345      *
346      * @return the type of this component
347      */
348     public String getComponentType()
349     {
350         return componentType;
351     }
352 
353     /**
354      * Sets this component's type.
355      *
356      * @param componentType the type to set
357      */
358     public void setComponentType( String componentType )
359     {
360         this.componentType = componentType;
361     }
362 
363     /**
364      * Returns the type of instantiation strategy for this component.
365      *
366      * @return the type of instantiation strategy for this component
367      */
368     public String getInstantiationStrategy()
369     {
370         return instantiationStrategy;
371     }
372 
373     /**
374      * Returns configuration values defined for this component.
375      *
376      * @return configuration values defined for this component
377      */
378     public PlexusConfiguration getConfiguration()
379     {
380         return configuration;
381     }
382 
383     /**
384      * Sets the configuration hierarchy for this component.
385      *
386      * @param configuration the configuration hierarchy to set
387      */
388     public void setConfiguration( PlexusConfiguration configuration )
389     {
390          this.configuration = configuration;
391     }
392 
393     /**
394      * Returns true if this component has a configuration.
395      *
396      * @return true if this component has a configuration
397      */
398     public boolean hasConfiguration()
399     {
400         return configuration != null;
401     }
402 
403     /**
404      * Returns the lifecycle-handler for this component.
405      *
406      * @return the lifecycle-handler for this component
407      */
408     public String getLifecycleHandler()
409     {
410         return lifecycleHandler;
411     }
412 
413     /**
414      * Sets the lifecycle-handler for this component. For example, "basic", "passive", "bootstrap".
415      *
416      * @param lifecycleHandler the lifecycle handler string to set
417      */
418     public void setLifecycleHandler( String lifecycleHandler )
419     {
420         this.lifecycleHandler = lifecycleHandler;
421     }
422 
423     public String getComponentProfile()
424     {
425         return componentProfile;
426     }
427 
428     public void setComponentProfile( String componentProfile )
429     {
430         this.componentProfile = componentProfile;
431     }
432 
433     /**
434      * Add a project requirement to this component.
435      *
436      * @param requirement the requirement to add
437      */
438     public void addRequirement( ComponentRequirement requirement )
439     {
440         this.requirements.add( requirement );
441     }
442 
443     /**
444      * Add a project requirement to this component.
445      *
446      * @param requirement the requirement to add
447      */
448     public void addRequirement( ComponentRequirement... requirement )
449     {
450         this.requirements.addAll( Arrays.asList( requirement ));
451     }
452 
453     /**
454      * Adds a list of requirements to this component.
455      *
456      * @param requirements the requirements to add
457      */
458     public void addRequirements( List<ComponentRequirement> requirements )
459     {
460         this.requirements.addAll( requirements );
461     }
462 
463     /**
464      * Remove a project requirement from this component.
465      *
466      * @param requirement the requirement to remove
467      */
468     public void removeRequirement( ComponentRequirement... requirement )
469     {
470         this.requirements.removeAll( Arrays.asList( requirement ));
471     }
472 
473     /**
474      * Removes a list of requirements from this component.
475      *
476      * @param requirements the requirements to remove
477      */
478     public void removeRequirements( List<ComponentRequirement> requirements )
479     {
480         this.requirements.removeAll( requirements );
481     }
482 
483     /**
484      * Returns all project requirements of this component.
485      *
486      * @return all project requirements of this component
487      */
488     public List<ComponentRequirement> getRequirements()
489     {
490         return Collections.unmodifiableList( requirements );
491     }
492 
493     /**
494      * Returns an id of the factory used to create this component.
495      *
496      * @return an id of the factory used to create this component
497      */
498     public String getComponentFactory()
499     {
500         return componentFactory;
501     }
502 
503     /**
504      * Sets the id of the factory to use to create this component. For example, "jruby" will use a JRuby factory.
505      *
506      * @param componentFactory The componentFactor.
507      */
508     public void setComponentFactory( String componentFactory )
509     {
510         this.componentFactory = componentFactory;
511     }
512 
513     /**
514      * Returns the ID of the type of composer this component will use. For example, "setter" or "field" for the
515      * different types of dependency injection.
516      *
517      * @return the ID of the type of composer this component will use
518      */
519     public String getComponentComposer()
520     {
521         return componentComposer;
522     }
523 
524     /**
525      * Sets a representation of the composer this component uses.
526      *
527      * @param componentComposer string representation of the composer to use
528      */
529     public void setComponentComposer( String componentComposer )
530     {
531         this.componentComposer = componentComposer;
532     }
533 
534     /**
535      * Return a human-readable description of this component.
536      *
537      * @return a human-readable description of this component
538      */
539     public String getDescription()
540     {
541         return description;
542     }
543 
544     /**
545      * Sets a description of this component for users to read.
546      *
547      * @param description a human-readable description of this component
548      */
549     public void setDescription( String description )
550     {
551         this.description = description;
552     }
553 
554     /**
555      * Sets the instantiation-strategy for this component. For example, "container".
556      *
557      * @param instantiationStrategy The strategy.
558      */
559     public void setInstantiationStrategy( String instantiationStrategy )
560     {
561         this.instantiationStrategy = instantiationStrategy;
562     }
563 
564     // ----------------------------------------------------------------------
565     //
566     // ----------------------------------------------------------------------
567 
568     /**
569      * Returns true if this may be in an isolated classrealm.
570      *
571      * @return true if this may be in an isolated classrealm
572      */
573     public boolean isIsolatedRealm()
574     {
575         return isolatedRealm;
576     }
577 
578     /**
579      * Sets the component set descriptor of components and dependencies for this component.
580      *
581      * @param componentSetDescriptor the component set descriptor of components and dependencies
582      */
583     public void setComponentSetDescriptor( ComponentSetDescriptor componentSetDescriptor )
584     {
585         this.componentSetDescriptor = componentSetDescriptor;
586     }
587 
588     /**
589      * Returns the component set descriptor.
590      *
591      * @return the component set descriptor
592      */
593     public ComponentSetDescriptor getComponentSetDescriptor()
594     {
595         return componentSetDescriptor;
596     }
597 
598     /**
599      * Sets that this component may be in an isolated classrealm.
600      *
601      * @param isolatedRealm true if this component may be in an isolated classrealm
602      */
603     public void setIsolatedRealm( boolean isolatedRealm )
604     {
605         this.isolatedRealm = isolatedRealm;
606     }
607 
608     /**
609      * Returns the type of component configurator for this project. For example "basic" for normal, or "map-oriented"
610      * for map oriented components.
611      *
612      * @return the type of component configurator for this project
613      */
614     public String getComponentConfigurator()
615     {
616         return componentConfigurator;
617     }
618 
619     /**
620      * Sets the type of component configurator for this project.
621      *
622      * @param componentConfigurator The component configurator.
623      */
624     public void setComponentConfigurator( String componentConfigurator )
625     {
626         this.componentConfigurator = componentConfigurator;
627     }
628 
629     /**
630      * The ClassRealm that this component lives under.
631      *
632      * @return ClassRealm that this component lives under
633      */
634     public ClassRealm getRealm()
635     {
636         return realm;
637     }
638 
639     /**
640      * Set the ClassRealm that this component lives under.
641      *
642      * @param realm the ClassRealm that this component lives under
643      */
644     public void setRealm( ClassRealm realm )
645     {
646         this.realm = realm;
647 
648         // reload implementation class
649         implementationClass = null;
650         attemptImplementationLoad();
651 
652         // reload role class
653         roleClass = null;
654         attemptRoleLoad();
655     }
656 
657     public String toString()
658     {
659         return getClass().getName() + " [role: '" + getRole() + "', hint: '" + getRoleHint() + "', realm: "
660             + ( realm == null ? "NULL" : "'" + realm + "'" ) + "]";
661     }
662 
663     // Component identity established here!
664     public boolean equals( Object other )
665     {
666         if ( this == other )
667         {
668             return true;
669         }
670 
671         if ( !( other instanceof ComponentDescriptor ) )
672         {
673             return false;
674         }
675 
676         ComponentDescriptor<?> that = (ComponentDescriptor<?>) other;
677 
678         return eq( getRole(), that.getRole() ) && eq( getRoleHint(), that.getRoleHint() )
679             && eq( getRealm(), that.getRealm() );
680     }
681 
682     private static <T> boolean eq( T o1, T o2 )
683     {
684         return ( o1 != null ) ? o1.equals( o2 ) : o2 == null;
685     }
686 
687     public int hashCode()
688     {
689         int hash = 17;
690 
691         hash = hash * 31 + hash( getRole() );
692         hash = hash * 31 + hash( getRoleHint() );
693         hash = hash * 31 + hash( getRealm() );
694 
695         return hash;
696     }
697 
698     private static int hash( Object obj )
699     {
700         return ( obj != null ) ? obj.hashCode() : 0;
701     }
702 
703 }