View Javadoc
1   package org.codehaus.plexus.component.collections;
2   
3   import java.util.Collection;
4   import java.util.HashMap;
5   import java.util.HashSet;
6   import java.util.List;
7   import java.util.Map;
8   
9   import org.codehaus.plexus.MutablePlexusContainer;
10  import org.codehaus.plexus.classworlds.ClassWorld;
11  import org.codehaus.plexus.classworlds.realm.ClassRealm;
12  import org.codehaus.plexus.component.repository.ComponentDescriptor;
13  import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
14  import org.codehaus.plexus.logging.Logger;
15  
16  /*
17   * Copyright 2001-2006 Codehaus Foundation.
18   *
19   * Licensed under the Apache License, Version 2.0 (the "License");
20   * you may not use this file except in compliance with the License.
21   * You may obtain a copy of the License at
22   *
23   *      http://www.apache.org/licenses/LICENSE-2.0
24   *
25   * Unless required by applicable law or agreed to in writing, software
26   * distributed under the License is distributed on an "AS IS" BASIS,
27   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
28   * See the License for the specific language governing permissions and
29   * limitations under the License.
30   */
31  
32  /** @author Jason van Zyl */
33  
34  // We need to have the collection notified when a new implementation of a given role has
35  // been added to the container. We probably need some options so that we know when new
36  // component descriptors have been added to the system, and an option to keep the collection
37  // up-to-date when new implementations are added.
38  //
39  // NOTE: This includes component additions, but also component purges from the
40  // container, as when a component realm is disposed
41  // (and PlexusContainer.removeComponentRealm(..) is called).
42  public abstract class AbstractComponentCollection<T> {
43      /** The reference to the PlexusContainer */
44      protected MutablePlexusContainer container;
45  
46      /** The type of the components held by this collection*/
47      protected final Class<T> componentType;
48  
49      /** The role of the components we are holding in this Collection. */
50      protected String role;
51  
52      /** The role hint of the components we are holding in this Collection. */
53      protected List<String> roleHints;
54  
55      /** The component that requires this collection of components */
56      protected String hostComponent;
57  
58      /** Used to log errors in the component lookup process. */
59      protected Logger logger;
60  
61      private ClassLoader tccl;
62      private Collection<ClassRealm> realms;
63  
64      private Map<String, ComponentDescriptor<T>> componentDescriptorMap;
65      private final ClassWorld world;
66  
67      public AbstractComponentCollection(
68              final MutablePlexusContainer container,
69              final Class<T> componentType,
70              final String role,
71              final List<String> roleHints,
72              final String hostComponent) {
73          this.container = container;
74  
75          this.componentType = componentType;
76  
77          this.role = role;
78  
79          this.roleHints = roleHints;
80  
81          this.hostComponent = hostComponent;
82  
83          logger = container.getLoggerManager().getLoggerForComponent(role);
84  
85          world = container.getContainerRealm().getWorld();
86      }
87  
88      private boolean realmsHaveChanged() {
89          return (tccl != Thread.currentThread().getContextClassLoader())
90                  || (realms == null)
91                  || (!realms.equals(world.getRealms()));
92      }
93  
94      protected synchronized Map<String, ComponentDescriptor<T>> getComponentDescriptorMap() {
95          checkUpdate();
96  
97          return componentDescriptorMap;
98      }
99  
100     @SuppressWarnings("unchecked")
101     protected boolean checkUpdate() {
102         if (componentDescriptorMap != null && !realmsHaveChanged()) {
103             return false;
104         }
105 
106         tccl = Thread.currentThread().getContextClassLoader();
107         Collection fromWorld = world.getRealms();
108         if (fromWorld == null || fromWorld.isEmpty()) {
109             realms = null;
110         } else {
111             realms = new HashSet<ClassRealm>(fromWorld);
112         }
113 
114         Map<String, ComponentDescriptor<T>> componentMap = container.getComponentDescriptorMap(componentType, role);
115         Map<String, ComponentDescriptor<T>> newComponentDescriptors =
116                 new HashMap<String, ComponentDescriptor<T>>(componentMap.size() * 2);
117 
118         if (roleHints != null && !roleHints.isEmpty()) {
119             for (String roleHint : roleHints) {
120                 ComponentDescriptor<T> componentDescriptor = componentMap.get(roleHint);
121                 if (componentDescriptor != null) {
122                     newComponentDescriptors.put(roleHint, componentDescriptor);
123                 }
124             }
125         } else {
126             newComponentDescriptors.putAll(componentMap);
127         }
128 
129         if (componentDescriptorMap == null || !newComponentDescriptors.equals(componentDescriptorMap)) {
130             componentDescriptorMap = newComponentDescriptors;
131 
132             return true;
133         }
134 
135         return false;
136     }
137 
138     protected T lookup(ComponentDescriptor<T> componentDescriptor) {
139         T component = null;
140 
141         try {
142             if (componentDescriptor != null) {
143                 component = container.lookup(componentDescriptor);
144             }
145         } catch (ComponentLookupException e) {
146             logger.debug(
147                     "Failed to lookup a member of active collection with role: " + role + " and role-hint: "
148                             + componentDescriptor.getRoleHint(),
149                     e);
150         }
151 
152         return component;
153     }
154 
155     public synchronized void clear() {
156         releaseAllCallback();
157 
158         componentDescriptorMap = null;
159 
160         tccl = null;
161         realms = null;
162     }
163 
164     protected abstract void releaseAllCallback();
165 }