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 }