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