1 package org.codehaus.plexus;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.Comparator;
6 import java.util.IdentityHashMap;
7 import java.util.Iterator;
8 import java.util.LinkedHashMap;
9 import java.util.List;
10 import java.util.Map;
11 import java.util.Map.Entry;
12 import java.util.Set;
13 import java.util.TreeMap;
14
15 import org.codehaus.plexus.classworlds.realm.ClassRealm;
16 import org.codehaus.plexus.component.composition.CycleDetectedInComponentGraphException;
17 import org.codehaus.plexus.component.factory.ComponentInstantiationException;
18 import org.codehaus.plexus.component.manager.ComponentManager;
19 import org.codehaus.plexus.component.manager.ComponentManagerFactory;
20 import org.codehaus.plexus.component.repository.ComponentDescriptor;
21 import org.codehaus.plexus.component.repository.ComponentRepository;
22 import org.codehaus.plexus.component.repository.exception.ComponentLifecycleException;
23 import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
24 import org.codehaus.plexus.lifecycle.LifecycleHandler;
25 import org.codehaus.plexus.lifecycle.LifecycleHandlerManager;
26 import org.codehaus.plexus.lifecycle.UndefinedLifecycleHandlerException;
27 import org.codehaus.plexus.logging.Logger;
28 import org.codehaus.plexus.util.StringUtils;
29
30 import static org.codehaus.plexus.component.CastUtils.isAssignableFrom;
31
32 public class DefaultComponentRegistry implements ComponentRegistry {
33 private static final String DEFAULT_INSTANTIATION_STRATEGY = "singleton";
34
35 private final MutablePlexusContainer container;
36 private final ComponentRepository repository;
37 private final LifecycleHandlerManager lifecycleHandlerManager;
38 private final Logger logger;
39
40 private boolean disposingComponents;
41
42 private final Map<String, ComponentManagerFactory> componentManagerFactories =
43 Collections.synchronizedMap(new TreeMap<String, ComponentManagerFactory>());
44
45 private final Map<Key, ComponentManager<?>> componentManagers = new TreeMap<Key, ComponentManager<?>>();
46 private final Map<Object, ComponentManager<?>> componentManagersByComponent =
47 new IdentityHashMap<Object, ComponentManager<?>>();
48
49 private final Map<Key, Object> unmanagedComponents = new TreeMap<Key, Object>();
50
51 public DefaultComponentRegistry(
52 MutablePlexusContainer container,
53 ComponentRepository repository,
54 LifecycleHandlerManager lifecycleHandlerManager) {
55 this.container = container;
56 this.repository = repository;
57 this.lifecycleHandlerManager = lifecycleHandlerManager;
58 logger = container.getLogger();
59 }
60
61 public void dispose() {
62 List<ComponentManager<?>> managers;
63 synchronized (this) {
64 managers = new ArrayList<ComponentManager<?>>(componentManagers.values());
65 componentManagers.clear();
66 componentManagersByComponent.clear();
67 unmanagedComponents.clear();
68
69 disposingComponents = true;
70 }
71
72
73 Collections.sort(managers, new Comparator<ComponentManager<?>>() {
74 public int compare(ComponentManager<?> left, ComponentManager<?> right) {
75 if (left.getStartId() < right.getStartId()) {
76 return 1;
77 } else if (left.getStartId() == right.getStartId()) {
78 return 0;
79 } else {
80 return -1;
81 }
82 }
83 });
84
85
86 try {
87 for (ComponentManager<?> componentManager : managers) {
88 try {
89 componentManager.dispose();
90 } catch (Exception e) {
91
92 logger.error("Error while disposing component manager. Continuing with the rest", e);
93 }
94 }
95 } finally {
96 synchronized (this) {
97 disposingComponents = false;
98 }
99 }
100 }
101
102 public void registerComponentManagerFactory(ComponentManagerFactory componentManagerFactory) {
103 componentManagerFactories.put(componentManagerFactory.getId(), componentManagerFactory);
104 }
105
106 public void addComponentDescriptor(ComponentDescriptor<?> componentDescriptor)
107 throws CycleDetectedInComponentGraphException {
108 repository.addComponentDescriptor(componentDescriptor);
109 }
110
111 @SuppressWarnings("unchecked")
112 public synchronized <T> void addComponent(T component, String role, String roleHint) {
113 ComponentDescriptor descriptor = new ComponentDescriptor(component.getClass(), null);
114 descriptor.setRole(role);
115 descriptor.setRoleHint(roleHint);
116
117 Key key = new Key(descriptor.getRealm(), role, roleHint);
118
119 unmanagedComponents.put(key, component);
120 }
121
122 public <T> ComponentDescriptor<T> getComponentDescriptor(Class<T> type, String role, String roleHint) {
123 return repository.getComponentDescriptor(type, role, roleHint);
124 }
125
126 @Deprecated
127 public ComponentDescriptor<?> getComponentDescriptor(String role, String roleHint, ClassRealm realm) {
128 return repository.getComponentDescriptor(role, roleHint, realm);
129 }
130
131 public <T> Map<String, ComponentDescriptor<T>> getComponentDescriptorMap(Class<T> type, String role) {
132 return repository.getComponentDescriptorMap(type, role);
133 }
134
135 public <T> List<ComponentDescriptor<T>> getComponentDescriptorList(Class<T> type, String role) {
136 return repository.getComponentDescriptorList(type, role);
137 }
138
139 public <T> T lookup(Class<T> type, String role, String roleHint) throws ComponentLookupException {
140
141 if (type == null) {
142 throw new NullPointerException("type is null");
143 }
144 if (role == null) {
145 throw new NullPointerException("role is null");
146 }
147 if (roleHint == null) {
148 roleHint = "";
149 }
150
151 return getComponent(type, role, roleHint, null);
152 }
153
154 public <T> T lookup(ComponentDescriptor<T> componentDescriptor) throws ComponentLookupException {
155 return getComponent(
156 componentDescriptor.getRoleClass(),
157 componentDescriptor.getRole(),
158 componentDescriptor.getRoleHint(),
159 componentDescriptor);
160 }
161
162 public <T> Map<String, T> lookupMap(Class<T> type, String role, List<String> roleHints)
163 throws ComponentLookupException {
164
165 if (type == null) {
166 throw new NullPointerException("type is null");
167 }
168 if (role == null) {
169 throw new NullPointerException("role is null");
170 }
171
172
173 Map<String, T> components = new LinkedHashMap<String, T>();
174 if (roleHints == null) {
175 Map<String, ComponentDescriptor<T>> componentDescriptors = getComponentDescriptorMap(type, role);
176 for (Entry<String, ComponentDescriptor<T>> entry : componentDescriptors.entrySet()) {
177 String roleHint = entry.getKey();
178 ComponentDescriptor<T> componentDescriptor = entry.getValue();
179
180
181 T component = getComponent(type, role, roleHint, componentDescriptor);
182 components.put(roleHint, component);
183 }
184 } else {
185 for (String roleHint : roleHints) {
186
187
188 T component = getComponent(type, role, roleHint, null);
189 components.put(roleHint, component);
190 }
191 }
192
193 return components;
194 }
195
196 public <T> List<T> lookupList(Class<T> type, String role, List<String> roleHints) throws ComponentLookupException {
197
198 if (type == null) {
199 throw new NullPointerException("type is null");
200 }
201 if (role == null) {
202 throw new NullPointerException("role is null");
203 }
204
205
206 List<T> components = new ArrayList<T>();
207 if (roleHints == null) {
208 List<ComponentDescriptor<T>> componentDescriptors = getComponentDescriptorList(type, role);
209 for (ComponentDescriptor<T> componentDescriptor : componentDescriptors) {
210
211
212 T component = getComponent(type, role, componentDescriptor.getRoleHint(), componentDescriptor);
213 components.add(component);
214 }
215 } else {
216 for (String roleHint : roleHints) {
217
218
219 T component = getComponent(type, role, roleHint, null);
220 components.add(component);
221 }
222 }
223
224 return components;
225 }
226
227 public void release(Object component) throws ComponentLifecycleException {
228 if (component == null) {
229 return;
230 }
231
232
233 ComponentManager<?> componentManager;
234 synchronized (this) {
235 componentManager = componentManagersByComponent.get(component);
236 if (componentManager == null) {
237
238
239
240
241 return;
242 }
243 }
244
245
246 componentManager.release(component);
247
248
249
250 if (componentManager.getConnections() <= 0) {
251 synchronized (this) {
252 componentManagersByComponent.remove(component);
253 }
254 }
255 }
256
257 public void removeComponentRealm(ClassRealm classRealm) throws PlexusContainerException {
258 repository.removeComponentRealm(classRealm);
259
260 List<ComponentManager<?>> dispose = new ArrayList<ComponentManager<?>>();
261 try {
262 synchronized (this) {
263 for (Iterator<Entry<Key, ComponentManager<?>>> it =
264 componentManagers.entrySet().iterator();
265 it.hasNext(); ) {
266 Entry<Key, ComponentManager<?>> entry = it.next();
267 Key key = entry.getKey();
268
269 ComponentManager<?> componentManager = entry.getValue();
270
271 if (key.realm.equals(classRealm)) {
272 dispose.add(componentManager);
273 it.remove();
274 } else {
275 componentManager.dissociateComponentRealm(classRealm);
276 }
277 }
278 }
279
280
281 for (ComponentManager<?> componentManager : dispose) {
282 componentManager.dispose();
283 }
284 } catch (ComponentLifecycleException e) {
285 throw new PlexusContainerException("Failed to dissociate component realm: " + classRealm.getId(), e);
286 }
287 }
288
289 private <T> T getComponent(Class<T> type, String role, String roleHint, ComponentDescriptor<T> descriptor)
290 throws ComponentLookupException {
291
292
293 T component = this.<T>getUnmanagedComponent(
294 role, roleHint);
295
296 if (component != null) {
297 return component;
298 }
299
300 ComponentManager<T> componentManager = getComponentManager(type, role, roleHint, descriptor);
301
302
303 try {
304 component = componentManager.getComponent();
305 synchronized (this) {
306 componentManagersByComponent.put(component, componentManager);
307 }
308 return component;
309 } catch (ComponentInstantiationException e) {
310 throw new ComponentLookupException(
311 "Unable to lookup component '" + componentManager.getRole() + "', it could not be created.",
312 componentManager.getRole(),
313 componentManager.getRoleHint(),
314 componentManager.getRealm(),
315 e);
316 } catch (ComponentLifecycleException e) {
317 throw new ComponentLookupException(
318 "Unable to lookup component '" + componentManager.getRole() + "', it could not be started.",
319 componentManager.getRole(),
320 componentManager.getRoleHint(),
321 componentManager.getRealm(),
322 e);
323 }
324 }
325
326 @SuppressWarnings("unchecked")
327 private synchronized <T> T getUnmanagedComponent(String role, String roleHint) {
328 Set<ClassRealm> realms = getSearchRealms(true);
329
330 if (realms != null) {
331
332
333 return null;
334 } else {
335 if (StringUtils.isEmpty(roleHint)) {
336 roleHint = PlexusConstants.PLEXUS_DEFAULT_HINT;
337 }
338
339 return (T) unmanagedComponents.get(new Key(null, role, roleHint));
340 }
341 }
342
343 private synchronized <T> ComponentManager<T> getComponentManager(
344 Class<T> type, String role, String roleHint, ComponentDescriptor<T> descriptor)
345 throws ComponentLookupException {
346 if (disposingComponents) {
347 throw new ComponentLookupException("ComponentRegistry is not active", role, roleHint);
348 }
349
350 if (descriptor == null) {
351 descriptor = getComponentDescriptor(type, role, roleHint);
352 }
353
354 ComponentManager<T> componentManager = null;
355
356 if (descriptor != null) {
357 componentManager = getComponentManager(type, role, descriptor.getRoleHint(), descriptor.getRealm());
358 } else {
359 componentManager = getComponentManager(type, role, roleHint);
360 }
361
362 if (componentManager == null) {
363
364 if (descriptor == null) {
365 descriptor = getComponentDescriptor(type, role, roleHint);
366 if (descriptor == null) {
367 throw new ComponentLookupException(
368 "Component descriptor cannot be found in the component repository", role, roleHint);
369 }
370
371 componentManager = getComponentManager(type, role, descriptor.getRoleHint(), descriptor.getRealm());
372 }
373
374 if (componentManager == null) {
375 componentManager = createComponentManager(descriptor, role, descriptor.getRoleHint());
376 }
377 }
378
379 return componentManager;
380 }
381
382 @SuppressWarnings("unchecked")
383 private <T> ComponentManager<T> getComponentManager(Class<T> type, String role, String roleHint) {
384 Set<ClassRealm> realms = getSearchRealms(false);
385
386
387 for (ClassRealm realm : realms) {
388 ComponentManager<?> manager = componentManagers.get(new Key(realm, role, roleHint));
389 if (manager != null && isAssignableFrom(type, manager.getType())) {
390 return (ComponentManager<T>) manager;
391 }
392 }
393 return null;
394 }
395
396 @SuppressWarnings("unchecked")
397 private <T> ComponentManager<T> getComponentManager(Class<T> type, String role, String roleHint, ClassRealm realm) {
398 ComponentManager<?> manager = componentManagers.get(new Key(realm, role, roleHint));
399 if (manager != null && isAssignableFrom(type, manager.getType())) {
400 return (ComponentManager<T>) manager;
401 }
402 return null;
403 }
404
405 @SuppressWarnings("unchecked")
406 private Set<ClassRealm> getSearchRealms(boolean specifiedOnly) {
407
408 Set<ClassRealm> realms = ClassRealmUtil.getContextRealms(container.getClassWorld());
409
410 if (realms.isEmpty()) {
411 if (specifiedOnly) {
412 return null;
413 }
414
415 realms.addAll(container.getClassWorld().getRealms());
416 }
417
418 return realms;
419 }
420
421 private <T> ComponentManager<T> createComponentManager(
422 ComponentDescriptor<T> descriptor, String role, String roleHint) throws ComponentLookupException {
423
424 String instantiationStrategy = descriptor.getInstantiationStrategy();
425 if (instantiationStrategy == null) {
426 instantiationStrategy = DEFAULT_INSTANTIATION_STRATEGY;
427 }
428 ComponentManagerFactory componentManagerFactory = componentManagerFactories.get(instantiationStrategy);
429 if (componentManagerFactory == null) {
430 throw new ComponentLookupException(
431 "Unsupported instantiation strategy: " + instantiationStrategy,
432 role,
433 roleHint,
434 descriptor.getRealm());
435 }
436
437
438 LifecycleHandler lifecycleHandler;
439 try {
440 lifecycleHandler = lifecycleHandlerManager.getLifecycleHandler(descriptor.getLifecycleHandler());
441 } catch (UndefinedLifecycleHandlerException e) {
442 throw new ComponentLookupException(
443 "Undefined lifecycle handler: " + descriptor.getLifecycleHandler(),
444 role,
445 roleHint,
446 descriptor.getRealm());
447 }
448
449
450 ComponentManager<T> componentManager =
451 componentManagerFactory.createComponentManager(container, lifecycleHandler, descriptor, role, roleHint);
452
453
454 Key key = new Key(descriptor.getRealm(), role, roleHint);
455 componentManagers.put(key, componentManager);
456
457 return componentManager;
458 }
459
460 private static class Key implements Comparable<Key> {
461 private final ClassRealm realm;
462 private final String role;
463 private final String roleHint;
464 private final int hashCode;
465
466 private Key(ClassRealm realm, String role, String roleHint) {
467 this.realm = realm;
468
469 if (role == null) {
470 role = "null";
471 }
472 this.role = role;
473
474 if (roleHint == null) {
475 roleHint = "null";
476 }
477 this.roleHint = roleHint;
478
479 int hashCode;
480 hashCode = (realm != null ? realm.hashCode() : 0);
481 hashCode = 31 * hashCode + role.hashCode();
482 hashCode = 31 * hashCode + roleHint.hashCode();
483 this.hashCode = hashCode;
484 }
485
486 public boolean equals(Object o) {
487 if (this == o) {
488 return true;
489 }
490 if (o == null || getClass() != o.getClass()) {
491 return false;
492 }
493
494 Key key = (Key) o;
495
496 return !(realm != null ? !realm.equals(key.realm) : key.realm != null)
497 && role.equals(key.role)
498 && roleHint.equals(key.roleHint);
499 }
500
501 public int hashCode() {
502 return hashCode;
503 }
504
505 public String toString() {
506 return realm + "/" + role + "/" + roleHint;
507 }
508
509 public int compareTo(Key o) {
510 int value;
511 if (realm != null) {
512 value = o.realm == null ? -1 : realm.getId().compareTo(o.realm.getId());
513 } else {
514 value = o.realm == null ? 0 : 1;
515 }
516
517 if (value == 0) {
518 value = role.compareTo(o.role);
519 if (value == 0) {
520 value = roleHint.compareTo(o.roleHint);
521 }
522 }
523 return value;
524 }
525 }
526 }