1. Project Clover database Tue Dec 20 2016 21:24:09 CET
  2. Package org.xwiki.component.embed

File EmbeddableComponentManager.java

 
testDisplayMacroWhenSectionSpecified: Failed to lookup default document displayer.
testIncludeMacroWhenSectionSpecified: Failed to lookup default document displayer.
verifySubHeadingVelocityVariableCorrectlyEvaluatedWhenUsedInSection: Failed to lookup default document displayer.
webRssFiltersHiddenDocuments: Failed to lookup default document displayer.
testDisplayMacroShowsVelocityMacrosAreIsolated: Failed to lookup component [org.xwiki.test.rendering.velo...
executeWithIdGeneratedByVelocityMacro: Failed to lookup component [org.xwiki.test.rendering.velo...
testIncludeMacroWhenIncludingDocumentWithRelativeReferences: Failed to lookup default document displayer.
testIncludeMacroWithCurrentContextShowsVelocityMacrosAreShared: Failed to lookup component [org.xwiki.test.rendering.velo...
testIncludeMacroWithNewContextShowsVelocityMacrosAreIsolated: Failed to lookup component [org.xwiki.test.rendering.velo...
webRssDisplay: Failed to lookup default document displayer.
executeWhenNoIdAndSameContent: Failed to lookup component [org.xwiki.test.rendering.velo...
executeWhenNoIdAndDifferentContent: Failed to lookup component [org.xwiki.test.rendering.velo...
testIncludeMacroWithNewContextShowsPassingOnRestrictedFlag: Failed to lookup default document displayer.
testDisplayMacroWhenDisplayingDocumentWithRelativeReferences: Failed to lookup default document displayer.
testMissingParserException: Failed to find a parser for syntax [XWiki 2.1]
executeWhenSameIdAndDifferentContent: Failed to lookup component [org.xwiki.test.rendering.velo...
 

Coverage histogram

../../../../img/srcFileCovDistChart10.png
0% of files have more coverage

Code metrics

78
188
40
2
694
455
88
0.47
4.7
20
2.2

Classes

Class Line # Actions
EmbeddableComponentManager 60 186 0% 87 6
0.98019898%
EmbeddableComponentManager.ComponentEntry 79 2 0% 1 0
1.0100%
 

Contributing tests

This file is covered by 3656 tests. .

Source view

1    /*
2    * See the NOTICE file distributed with this work for additional
3    * information regarding copyright ownership.
4    *
5    * This is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU Lesser General Public License as
7    * published by the Free Software Foundation; either version 2.1 of
8    * the License, or (at your option) any later version.
9    *
10    * This software is distributed in the hope that it will be useful,
11    * but WITHOUT ANY WARRANTY; without even the implied warranty of
12    * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13    * Lesser General Public License for more details.
14    *
15    * You should have received a copy of the GNU Lesser General Public
16    * License along with this software; if not, write to the Free
17    * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
18    * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
19    */
20    package org.xwiki.component.embed;
21   
22    import java.lang.reflect.Type;
23    import java.util.ArrayList;
24    import java.util.Collections;
25    import java.util.Comparator;
26    import java.util.HashMap;
27    import java.util.List;
28    import java.util.Map;
29    import java.util.Objects;
30    import java.util.ServiceLoader;
31    import java.util.concurrent.ConcurrentHashMap;
32   
33    import javax.inject.Provider;
34   
35    import org.slf4j.Logger;
36    import org.slf4j.LoggerFactory;
37    import org.xwiki.component.annotation.ComponentAnnotationLoader;
38    import org.xwiki.component.annotation.DisposePriority;
39    import org.xwiki.component.descriptor.ComponentDependency;
40    import org.xwiki.component.descriptor.ComponentDescriptor;
41    import org.xwiki.component.descriptor.ComponentInstantiationStrategy;
42    import org.xwiki.component.descriptor.DefaultComponentDescriptor;
43    import org.xwiki.component.internal.RoleHint;
44    import org.xwiki.component.manager.ComponentEventManager;
45    import org.xwiki.component.manager.ComponentLifecycleException;
46    import org.xwiki.component.manager.ComponentLookupException;
47    import org.xwiki.component.manager.ComponentManager;
48    import org.xwiki.component.manager.ComponentManagerInitializer;
49    import org.xwiki.component.manager.ComponentRepositoryException;
50    import org.xwiki.component.manager.NamespacedComponentManager;
51    import org.xwiki.component.phase.Disposable;
52    import org.xwiki.component.util.ReflectionUtils;
53   
54    /**
55    * Simple implementation of {@link ComponentManager} to be used when using some XWiki modules standalone.
56    *
57    * @version $Id: c7c602e532e87889958cf967ec6b6b3ff1ef29c7 $
58    * @since 2.0M1
59    */
 
60    public class EmbeddableComponentManager implements NamespacedComponentManager, Disposable
61    {
62    /**
63    * Logger to use to log shutdown information (opposite of initialization).
64    */
65    private static final Logger SHUTDOWN_LOGGER = LoggerFactory.getLogger("org.xwiki.shutdown");
66   
67    /**
68    * @see #getNamespace()
69    */
70    private String namespace;
71   
72    private ComponentEventManager eventManager;
73   
74    /**
75    * Used as fallback for lookup methods.
76    */
77    private ComponentManager parent;
78   
 
79    private static class ComponentEntry<R>
80    {
81    /**
82    * Descriptor of the component.
83    */
84    public final ComponentDescriptor<R> descriptor;
85   
86    /**
87    * Cached instance of the component. Lazily initialized when needed.
88    * <p>
89    * This variable can be accesses and modified by many different threads at the same time so we make it volatile
90    * to ensure it's really shared and sync between all of them and not in each thread memory.
91    */
92    public volatile R instance;
93   
 
94  769939 toggle public ComponentEntry(ComponentDescriptor<R> descriptor, R instance)
95    {
96  769939 this.descriptor = descriptor;
97  769939 this.instance = instance;
98    }
99    }
100   
101    private Map<RoleHint<?>, ComponentEntry<?>> componentEntries = new ConcurrentHashMap<>();
102   
103    private Logger logger = LoggerFactory.getLogger(EmbeddableComponentManager.class);
104   
105    /**
106    * Finds all lifecycle handlers to use when instantiating a Component.
107    */
108    private ServiceLoader<LifecycleHandler> lifecycleHandlers = ServiceLoader.load(LifecycleHandler.class);
109   
 
110  5009 toggle public EmbeddableComponentManager()
111    {
112  5009 registerThis();
113    }
114   
115    /**
116    * @param namespace the namespace associated with this component manager
117    * @since 6.4M2
118    */
 
119  102 toggle public EmbeddableComponentManager(String namespace)
120    {
121  102 registerThis();
122   
123  102 this.namespace = namespace;
124    }
125   
 
126  4 toggle @Override
127    public String getNamespace()
128    {
129  4 return this.namespace;
130    }
131   
132    /**
133    * Allow to lookup the this as default {@link ComponentManager} implementation.
134    */
 
135  5111 toggle private void registerThis()
136    {
137  5111 DefaultComponentDescriptor<ComponentManager> cd = new DefaultComponentDescriptor<>();
138  5111 cd.setRoleType(ComponentManager.class);
139   
140  5111 registerComponent(cd, this);
141    }
142   
143    /**
144    * Load all component annotations and register them as components.
145    *
146    * @param classLoader the class loader to use to look for component definitions
147    */
 
148  1475 toggle public void initialize(ClassLoader classLoader)
149    {
150  1475 ComponentAnnotationLoader loader = new ComponentAnnotationLoader();
151  1475 loader.initialize(this, classLoader);
152   
153    // Extension point to allow component to manipulate ComponentManager initialized state.
154  1475 try {
155  1475 List<ComponentManagerInitializer> initializers = this.getInstanceList(ComponentManagerInitializer.class);
156  1475 for (ComponentManagerInitializer initializer : initializers) {
157  0 initializer.initialize(this);
158    }
159    } catch (ComponentLookupException e) {
160    // Should never happen
161  0 this.logger.error("Failed to lookup ComponentManagerInitializer components", e);
162    }
163    }
164   
 
165  236831 toggle @Override
166    public boolean hasComponent(Type role)
167    {
168  236829 return hasComponent(role, "default");
169    }
170   
 
171  1932417 toggle @Override
172    public boolean hasComponent(Type role, String hint)
173    {
174  1932384 if (this.componentEntries.containsKey(new RoleHint<>(role, hint))) {
175  811871 return true;
176    }
177   
178  1120492 return getParent() != null ? getParent().hasComponent(role, hint) : false;
179    }
180   
 
181  398092 toggle @Override
182    public <T> T getInstance(Type roleType) throws ComponentLookupException
183    {
184  398102 Test failure here return getComponentInstance(new RoleHint<T>(roleType));
185    }
186   
 
187  7999649 toggle @Override
188    public <T> T getInstance(Type roleType, String roleHint) throws ComponentLookupException
189    {
190  7999677 Test failure here return getComponentInstance(new RoleHint<T>(roleType, roleHint));
191    }
192   
 
193  113990 toggle @Override
194    public <T> List<T> getInstanceList(Type role) throws ComponentLookupException
195    {
196    // Reuse getInstanceMap to make sure to not return components from parent Component Manager overridden by this
197    // Component Manager
198  114015 Map<String, T> objects = getInstanceMap(role);
199   
200  114115 return objects.isEmpty() ? Collections.<T>emptyList() : new ArrayList<T>(objects.values());
201    }
202   
 
203  167223 toggle @Override
204    @SuppressWarnings("unchecked")
205    public <T> Map<String, T> getInstanceMap(Type role) throws ComponentLookupException
206    {
207  167234 Map<String, T> objects = new HashMap<>();
208   
209  167266 for (Map.Entry<RoleHint<?>, ComponentEntry<?>> entry : this.componentEntries.entrySet()) {
210  132412272 RoleHint<?> roleHint = entry.getKey();
211   
212  132334204 if (role.equals(roleHint.getRoleType())) {
213  410751 try {
214  410751 objects.put(roleHint.getHint(), getComponentInstance((ComponentEntry<T>) entry.getValue()));
215    } catch (Exception e) {
216  1 throw new ComponentLookupException("Failed to lookup component [" + roleHint + "]", e);
217    }
218    }
219    }
220   
221    // Add parent's list of components
222  167354 if (getParent() != null) {
223    // If the hint already exists in the children Component Manager then don't add the one from the parent.
224  34662 for (Map.Entry<String, T> entry : getParent().<T>getInstanceMap(role).entrySet()) {
225  136979 if (!objects.containsKey(entry.getKey())) {
226  136977 objects.put(entry.getKey(), entry.getValue());
227    }
228    }
229    }
230   
231  167370 return objects;
232    }
233   
 
234  3208 toggle @Override
235    @SuppressWarnings("unchecked")
236    public <T> ComponentDescriptor<T> getComponentDescriptor(Type role, String hint)
237    {
238  3208 ComponentDescriptor<T> result = null;
239  3208 ComponentEntry<T> componentEntry = (ComponentEntry<T>) this.componentEntries.get(new RoleHint<T>(role, hint));
240  3208 if (componentEntry == null) {
241    // Check in parent!
242  947 if (getParent() != null) {
243  841 result = getParent().getComponentDescriptor(role, hint);
244    }
245    } else {
246  2261 result = componentEntry.descriptor;
247    }
248   
249  3208 return result;
250    }
251   
 
252  18584 toggle @Override
253    @SuppressWarnings("unchecked")
254    public <T> List<ComponentDescriptor<T>> getComponentDescriptorList(Type role)
255    {
256  18584 Map<String, ComponentDescriptor<T>> descriptors = new HashMap<>();
257   
258  18584 for (Map.Entry<RoleHint<?>, ComponentEntry<?>> entry : this.componentEntries.entrySet()) {
259  12182693 if (entry.getKey().getRoleType().equals(role)) {
260  45094 descriptors.put(entry.getKey().getHint(), (ComponentDescriptor<T>) entry.getValue().descriptor);
261    }
262    }
263   
264    // Add Component Descriptors found in parent first
265  18584 if (getParent() != null) {
266  5833 List<ComponentDescriptor<T>> parentDescriptors = getParent().getComponentDescriptorList(role);
267  5833 for (ComponentDescriptor<T> parentDescriptor : parentDescriptors) {
268    // If the hint already exists in the children Component Manager then don't add the one from the parent.
269  22854 if (!descriptors.containsKey(parentDescriptor.getRoleHint())) {
270  22854 descriptors.put(parentDescriptor.getRoleHint(), parentDescriptor);
271    }
272    }
273    }
274   
275  18584 return new ArrayList<>(descriptors.values());
276    }
277   
 
278  255 toggle @Override
279    public ComponentEventManager getComponentEventManager()
280    {
281  255 return this.eventManager;
282    }
283   
 
284  1526 toggle @Override
285    public void setComponentEventManager(ComponentEventManager eventManager)
286    {
287  1526 this.eventManager = eventManager;
288    }
289   
 
290  5008608 toggle @Override
291    public ComponentManager getParent()
292    {
293  5008621 return this.parent;
294    }
295   
 
296  108 toggle @Override
297    public void setParent(ComponentManager parentComponentManager)
298    {
299  108 this.parent = parentComponentManager;
300    }
301   
 
302  342052 toggle private <T> T createInstance(ComponentDescriptor<T> descriptor) throws Exception
303    {
304  342053 T instance = descriptor.getImplementation().newInstance();
305   
306    // Set each dependency
307  342055 for (ComponentDependency<?> dependency : descriptor.getComponentDependencies()) {
308   
309    // TODO: Handle dependency cycles
310   
311    // Handle different field types
312  713534 Test failure here Object fieldValue = getDependencyInstance(descriptor, instance, dependency);
313   
314    // Set the field by introspection
315  708934 if (fieldValue != null) {
316  708935 ReflectionUtils.setFieldValue(instance, dependency.getName(), fieldValue);
317    }
318    }
319   
320    // Call Lifecycle Handlers
321  337425 for (LifecycleHandler lifecycleHandler : this.lifecycleHandlers) {
322  674869 Test failure here lifecycleHandler.handle(instance, descriptor, this);
323    }
324   
325  337384 return instance;
326    }
327   
 
328  713534 toggle protected Object getDependencyInstance(ComponentDescriptor<?> descriptor, Object parentInstance,
329    ComponentDependency<?> dependency) throws ComponentLookupException
330    {
331    // TODO: Handle dependency cycles
332   
333    // Handle different field types
334  713532 Object fieldValue;
335   
336    // Step 1: Verify if there's a Provider registered for the field type
337    // - A Provider is a component like any other (except it cannot have a field produced by itself!)
338    // - A Provider must implement the JSR330 Producer interface
339    //
340    // Step 2: Handle Logger injection.
341    //
342    // Step 3: No producer found, handle scalar and collection types by looking up standard component
343    // implementations.
344   
345  713533 Class<?> dependencyRoleClass = ReflectionUtils.getTypeClass(dependency.getRoleType());
346   
347  713543 if (dependencyRoleClass.isAssignableFrom(Logger.class)) {
348  59330 fieldValue = createLogger(parentInstance.getClass());
349  654209 } else if (dependencyRoleClass.isAssignableFrom(List.class)) {
350  504 fieldValue = getInstanceList(ReflectionUtils.getLastTypeGenericArgument(dependency.getRoleType()));
351  653715 } else if (dependencyRoleClass.isAssignableFrom(Map.class)) {
352  60 fieldValue = getInstanceMap(ReflectionUtils.getLastTypeGenericArgument(dependency.getRoleType()));
353  653655 } else if (dependencyRoleClass.isAssignableFrom(Provider.class)) {
354    // Check if there's a Provider registered for the type
355  91480 if (hasComponent(dependency.getRoleType(), dependency.getRoleHint())) {
356  76852 fieldValue = getInstance(dependency.getRoleType(), dependency.getRoleHint());
357    } else {
358  14628 fieldValue = createGenericProvider(descriptor, dependency);
359    }
360  562163 } else if (dependencyRoleClass.isAssignableFrom(ComponentDescriptor.class)) {
361  551 fieldValue = new DefaultComponentDescriptor(descriptor);
362    } else {
363  561623 Test failure here fieldValue = getInstance(dependency.getRoleType(), dependency.getRoleHint());
364    }
365   
366  708928 return fieldValue;
367    }
368   
 
369  14628 toggle protected Provider<?> createGenericProvider(ComponentDescriptor<?> descriptor, ComponentDependency<?> dependency)
370    {
371  14628 return new GenericProvider<>(this, new RoleHint<>(ReflectionUtils.getLastTypeGenericArgument(dependency
372    .getRoleType()), dependency.getRoleHint()));
373    }
374   
375    /**
376    * Create a Logger instance to inject.
377    */
 
378  58774 toggle protected Object createLogger(Class<?> instanceClass)
379    {
380  58773 return LoggerFactory.getLogger(instanceClass);
381    }
382   
 
383  8397705 toggle @SuppressWarnings("unchecked")
384    protected <T> T getComponentInstance(RoleHint<T> roleHint) throws ComponentLookupException
385    {
386  8397704 T instance;
387   
388  8397702 ComponentEntry<T> componentEntry = (ComponentEntry<T>) this.componentEntries.get(roleHint);
389   
390  8397994 if (componentEntry != null) {
391  6896901 try {
392  6896909 Test failure here instance = getComponentInstance(componentEntry);
393    } catch (Throwable e) {
394  4663 Test failure here throw new ComponentLookupException(String.format("Failed to lookup component [%s] identified by [%s]",
395    componentEntry.descriptor.getImplementation().getName(), roleHint.toString()), e);
396    }
397    } else {
398  1501053 if (getParent() != null) {
399  1431665 instance = getParent().getInstance(roleHint.getRoleType(), roleHint.getHint());
400    } else {
401  69431 Test failure here throw new ComponentLookupException("Can't find descriptor for the component [" + roleHint + "]");
402    }
403    }
404   
405  8300871 return instance;
406    }
407   
 
408  7307593 toggle private <T> T getComponentInstance(ComponentEntry<T> componentEntry) throws Exception
409    {
410  7307621 T instance;
411   
412  7307621 ComponentDescriptor<T> descriptor = componentEntry.descriptor;
413   
414  7307556 if (descriptor.getInstantiationStrategy() == ComponentInstantiationStrategy.SINGLETON) {
415  7074098 if (componentEntry.instance != null) {
416    // If the instance exists return it
417  6965431 instance = componentEntry.instance;
418    } else {
419  108670 synchronized (componentEntry) {
420    // Recheck in case it has been created while we were waiting
421  108674 if (componentEntry.instance != null) {
422  171 instance = componentEntry.instance;
423    } else {
424  108503 Test failure here componentEntry.instance = createInstance(descriptor);
425  103839 instance = componentEntry.instance;
426    }
427    }
428    }
429    } else {
430  233549 instance = createInstance(descriptor);
431    }
432   
433  7303012 return instance;
434    }
435   
436    // Add
437   
 
438  769937 toggle private <T> RoleHint<T> getRoleHint(ComponentDescriptor<T> componentDescriptor)
439    {
440  769937 return new RoleHint<T>(componentDescriptor.getRoleType(), componentDescriptor.getRoleHint());
441    }
442   
 
443  737547 toggle @Override
444    public <T> void registerComponent(ComponentDescriptor<T> componentDescriptor) throws ComponentRepositoryException
445    {
446  737547 registerComponent(componentDescriptor, null);
447    }
448   
 
449  769937 toggle @Override
450    public <T> void registerComponent(ComponentDescriptor<T> componentDescriptor, T componentInstance)
451    {
452  769937 RoleHint<T> roleHint = getRoleHint(componentDescriptor);
453   
454    // Remove any existing component associated to the provided roleHint
455  769937 removeComponentWithoutException(roleHint);
456   
457    // Register new component
458  769937 addComponent(roleHint, new DefaultComponentDescriptor<T>(componentDescriptor), componentInstance);
459    }
460   
 
461  769939 toggle private <T> void addComponent(RoleHint<T> roleHint, ComponentDescriptor<T> descriptor, T instance)
462    {
463  769939 ComponentEntry<T> componentEntry = new ComponentEntry<T>(descriptor, instance);
464   
465    // Register new component
466  769939 this.componentEntries.put(roleHint, componentEntry);
467   
468    // Send event about component registration
469  769939 if (this.eventManager != null) {
470  12306 this.eventManager.notifyComponentRegistered(descriptor, this);
471    }
472    }
473   
474    // Remove
475   
 
476  177 toggle @Override
477    public void unregisterComponent(Type role, String hint)
478    {
479  177 removeComponentWithoutException(new RoleHint<>(role, hint));
480    }
481   
 
482  138 toggle @Override
483    public void unregisterComponent(ComponentDescriptor<?> componentDescriptor)
484    {
485  138 if (Objects.equals(
486    getComponentDescriptor(componentDescriptor.getRoleType(), componentDescriptor.getRoleHint()),
487    componentDescriptor)) {
488  89 unregisterComponent(componentDescriptor.getRoleType(), componentDescriptor.getRoleHint());
489    }
490    }
491   
 
492  1564 toggle @Override
493    @SuppressWarnings("unchecked")
494    public void release(Object component) throws ComponentLifecycleException
495    {
496    // First find the descriptor matching the passed component
497  1564 RoleHint<?> key = null;
498  1564 ComponentDescriptor<?> oldDescriptor = null;
499  1564 for (Map.Entry<RoleHint<?>, ComponentEntry<?>> entry : this.componentEntries.entrySet()) {
500  1193533 if (entry.getValue().instance == component) {
501  2 key = entry.getKey();
502  2 oldDescriptor = entry.getValue().descriptor;
503  2 break;
504    }
505    }
506   
507    // Note that we're not removing inside the for loop above since it would cause a Concurrent
508    // exception since we'd modify the map accessed by the iterator.
509  1564 if (key != null) {
510    // We do the following:
511    // - fire an unregistration event, to tell the world that this reference is now dead
512    // - fire a registration event, to tell the world that it could get a new reference for this component
513    // now
514    // We need to do this since code holding a reference on the released component may need to know it's
515    // been removed and thus discard its own reference to that component and look it up again.
516    // Another solution would be to introduce a new event for Component creation/destruction (right now
517    // we only send events for Component registration/unregistration).
518  2 removeComponent(key);
519  2 addComponent((RoleHint<Object>) key, (ComponentDescriptor<Object>) oldDescriptor, null);
520    }
521    }
522   
 
523  4584 toggle private void releaseInstance(ComponentEntry<?> componentEntry) throws ComponentLifecycleException
524    {
525    // Make sure the singleton component instance can't be "lost" (impossible to dispose because returned but not
526    // stored).
527  4584 synchronized (componentEntry) {
528  4584 Object instance = componentEntry.instance;
529   
530    // Give a chance to the component to clean up
531  4584 if (instance instanceof Disposable) {
532  3 ((Disposable) instance).dispose();
533    }
534   
535  4584 componentEntry.instance = null;
536    }
537    }
538   
 
539  4584 toggle private void releaseComponentEntry(ComponentEntry<?> componentEntry) throws ComponentLifecycleException
540    {
541    // clean existing instance
542  4584 releaseInstance(componentEntry);
543    }
544   
 
545  770116 toggle private void removeComponent(RoleHint<?> roleHint) throws ComponentLifecycleException
546    {
547    // Make sure to remove the entry from the map before destroying it to reduce at the minimum the risk of
548    // lookupping something invalid
549  770116 ComponentEntry<?> componentEntry = this.componentEntries.remove(roleHint);
550   
551  770116 if (componentEntry != null) {
552  4587 ComponentDescriptor<?> oldDescriptor = componentEntry.descriptor;
553   
554    // We don't want the component manager to dispose itself just because it's not registered as component*
555    // anymore
556  4587 if (componentEntry.instance != this) {
557    // clean any resource associated to the component instance and descriptor
558  4584 releaseComponentEntry(componentEntry);
559    }
560   
561    // Send event about component unregistration
562  4587 if (this.eventManager != null && oldDescriptor != null) {
563  3097 this.eventManager.notifyComponentUnregistered(oldDescriptor, this);
564    }
565    }
566    }
567   
568    /**
569    * Note: This method shouldn't exist but register/unregister methods should throw a
570    * {@link ComponentLifecycleException} but that would break backward compatibility to add it.
571    */
 
572  770114 toggle private <T> void removeComponentWithoutException(RoleHint<T> roleHint)
573    {
574  770114 try {
575  770114 removeComponent(roleHint);
576    } catch (Exception e) {
577  0 this.logger.warn("Instance released but disposal failed. Some resources may not have been released.", e);
578    }
579    }
580   
 
581  53893377 toggle private int sortEntry(List<RoleHint<?>> keys, int index)
582    {
583  53893377 int oldIndex = index;
584  53893377 int newIndex = index;
585   
586  53893377 RoleHint<?> key = keys.get(index);
587  53893377 ComponentEntry<?> componentEntry = this.componentEntries.get(key);
588   
589  53893377 for (ComponentDependency<?> dependency : componentEntry.descriptor.getComponentDependencies()) {
590  98228108 RoleHint<?> dependencyRole = new RoleHint<Object>(dependency.getRoleType(), dependency.getRoleHint());
591   
592  98228108 int dependencyIndex = keys.indexOf(dependencyRole);
593   
594  98228108 if (dependencyIndex != -1 && dependencyIndex < newIndex) {
595  440557 dependencyIndex = sortEntry(keys, dependencyIndex);
596   
597  440557 newIndex = dependencyIndex;
598    }
599    }
600   
601  53893377 if (newIndex != oldIndex) {
602  369745 key = keys.remove(oldIndex);
603  369745 keys.add(newIndex, key);
604    }
605   
606  53893377 return newIndex;
607    }
608   
 
609  4536 toggle @Override
610    public void dispose()
611    {
612  4536 List<RoleHint<?>> keys = new ArrayList<>(this.componentEntries.keySet());
613   
614    // Exclude this component
615  4536 RoleHint<ComponentManager> cmRoleHint = new RoleHint<>(ComponentManager.class);
616  4536 ComponentEntry<?> cmEntry = this.componentEntries.get(cmRoleHint);
617  4536 if (cmEntry != null && cmEntry.instance == this) {
618  4535 keys.remove(cmRoleHint);
619    }
620   
621    // Order component based on dependencies relations
622  53457356 for (int i = 0; i < keys.size(); ++i) {
623  53452820 i = sortEntry(keys, i);
624    }
625   
626    // Sort component by DisposePriority
627  4536 Collections.sort(keys, new Comparator<RoleHint<?>>()
628    {
 
629  717733 toggle @Override
630    public int compare(RoleHint<?> rh1, RoleHint<?> rh2)
631    {
632  717733 return getPriority(rh1) - getPriority(rh2);
633    }
634   
 
635  1435466 toggle private int getPriority(RoleHint<?> rh)
636    {
637  1435466 Object instance = componentEntries.get(rh).instance;
638  1435466 if (instance == null) {
639    // The component has not been instantiated yet. We don't need to dispose it in this case... :)
640    // Return the default priority since it doesn't matter.
641  1179670 return DisposePriority.DEFAULT_PRIORITY;
642    } else {
643  255796 DisposePriority priorityAnnotation = instance.getClass().getAnnotation(DisposePriority.class);
644  255796 return (priorityAnnotation == null) ? DisposePriority.DEFAULT_PRIORITY : priorityAnnotation.value();
645    }
646    }
647    });
648   
649    // Dispose old components
650  4536 for (RoleHint<?> key : keys) {
651  719049 ComponentEntry<?> componentEntry = this.componentEntries.get(key);
652   
653  719049 synchronized (componentEntry) {
654  719049 Object instance = componentEntry.instance;
655   
656    // Protection to prevent infinite recursion in case a component implementation points to this
657    // instance.
658  719049 if (instance instanceof Disposable && componentEntry.instance != this) {
659  1593 try {
660  1593 SHUTDOWN_LOGGER.debug("Disposing component [{}]...", instance.getClass().getName());
661  1593 ((Disposable) instance).dispose();
662  1593 SHUTDOWN_LOGGER.debug("Component [{}] has been disposed", instance.getClass().getName());
663    } catch (ComponentLifecycleException e) {
664  0 this.logger.error("Failed to dispose component with role type [{}] and role hint [{}]",
665    componentEntry.descriptor.getRoleType(), componentEntry.descriptor.getRoleHint(), e);
666    }
667    }
668    }
669    }
670   
671    // Remove disposed components from the map. Doing it in two steps to give as many chances as possible to the
672    // components that have to use a component already disposed (usually because it dynamically requires it and
673    // there is no way for the ComponentManager to know that dependency).
674  4536 for (RoleHint<?> key : keys) {
675  719049 this.componentEntries.remove(key);
676    }
677    }
678   
679    // Deprecated
680   
 
681  2 toggle @Override
682    @SuppressWarnings("unchecked")
683    @Deprecated
684    public <T> List<ComponentDescriptor<T>> getComponentDescriptorList(Class<T> role)
685    {
686  2 List<ComponentDescriptor<T>> results = new ArrayList<>();
687  2 for (Map.Entry<RoleHint<?>, ComponentEntry<?>> entry : this.componentEntries.entrySet()) {
688  6 if (entry.getKey().getRoleClass() == role) {
689  4 results.add((ComponentDescriptor<T>) entry.getValue().descriptor);
690    }
691    }
692  2 return results;
693    }
694    }