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