View Javadoc
1   package org.codehaus.plexus.component.collections;
2   
3   import org.codehaus.plexus.MutablePlexusContainer;
4   import org.codehaus.plexus.classworlds.ClassWorld;
5   import org.codehaus.plexus.classworlds.realm.ClassRealm;
6   import org.codehaus.plexus.component.repository.ComponentDescriptor;
7   import org.codehaus.plexus.component.repository.exception.ComponentLookupException;
8   import org.codehaus.plexus.logging.Logger;
9   
10  import java.util.Collection;
11  import java.util.HashMap;
12  import java.util.HashSet;
13  import java.util.List;
14  import java.util.Map;
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  {
44      /** The reference to the PlexusContainer */
45      protected MutablePlexusContainer container;
46  
47      /** The type of the components held by this collection*/
48      protected final Class<T> componentType;
49  
50      /** The role of the components we are holding in this Collection. */
51      protected String role;
52  
53      /** The role hint of the components we are holding in this Collection. */
54      protected List<String> roleHints;
55  
56      /** The component that requires this collection of components */
57      protected String hostComponent;
58  
59      /** Used to log errors in the component lookup process. */
60      protected Logger logger;
61  
62      private ClassLoader tccl;
63      private Collection<ClassRealm> realms;
64  
65      private Map<String, ComponentDescriptor<T>> componentDescriptorMap;
66      private final ClassWorld world;
67  
68      public AbstractComponentCollection( final MutablePlexusContainer container,
69                                          final Class<T> componentType,
70                                          final String role,
71                                          final List<String> roleHints,
72                                          final String hostComponent )
73      {
74          this.container = container;
75  
76          this.componentType = componentType;
77  
78          this.role = role;
79  
80          this.roleHints = roleHints;
81  
82          this.hostComponent = hostComponent;
83  
84          logger = container.getLoggerManager().getLoggerForComponent( role );
85  
86          world = container.getContainerRealm().getWorld();
87      }
88  
89      private boolean realmsHaveChanged()
90      {
91          return ( tccl != Thread.currentThread().getContextClassLoader() ) ||
92                 ( realms == null ) || ( !realms.equals( world.getRealms() ) );
93      }
94  
95      protected synchronized Map<String, ComponentDescriptor<T>> getComponentDescriptorMap()
96      {
97          checkUpdate();
98  
99          return componentDescriptorMap;
100     }
101 
102     @SuppressWarnings( "unchecked" )
103     protected boolean checkUpdate()
104     {
105         if ( componentDescriptorMap != null && !realmsHaveChanged() )
106         {
107             return false;
108         }
109 
110         tccl = Thread.currentThread().getContextClassLoader();
111         Collection fromWorld = world.getRealms();
112         if ( fromWorld == null || fromWorld.isEmpty() )
113         {
114             realms = null;
115         }
116         else
117         {
118             realms = new HashSet<ClassRealm>( fromWorld );
119         }
120 
121         Map<String, ComponentDescriptor<T>> componentMap = container.getComponentDescriptorMap( componentType, role );
122         Map<String, ComponentDescriptor<T>> newComponentDescriptors =
123             new HashMap<String, ComponentDescriptor<T>>( componentMap.size() * 2 );
124 
125         if ( roleHints != null && !roleHints.isEmpty() )
126         {
127             for ( String roleHint : roleHints )
128             {
129                 ComponentDescriptor<T> componentDescriptor = componentMap.get( roleHint );
130                 if ( componentDescriptor != null )
131                 {
132                     newComponentDescriptors.put( roleHint, componentDescriptor );
133                 }
134             }
135         }
136         else
137         {
138             newComponentDescriptors.putAll( componentMap );
139         }
140 
141         if ( componentDescriptorMap == null || !newComponentDescriptors.equals( componentDescriptorMap ) )
142         {
143             componentDescriptorMap = newComponentDescriptors;
144 
145             return true;
146         }
147 
148         return false;
149     }
150 
151     protected T lookup( ComponentDescriptor<T> componentDescriptor )
152     {
153         T component = null;
154 
155         try
156         {
157             if ( componentDescriptor != null )
158             {
159                 component = container.lookup( componentDescriptor );
160             }
161         }
162         catch ( ComponentLookupException e )
163         {
164             logger.debug( "Failed to lookup a member of active collection with role: " + role + " and role-hint: "
165                 + componentDescriptor.getRoleHint(), e );
166         }
167 
168         return component;
169     }
170 
171     public synchronized void clear()
172     {
173         releaseAllCallback();
174 
175         componentDescriptorMap = null;
176 
177         tccl = null;
178         realms = null;
179     }
180 
181     protected abstract void releaseAllCallback();
182 
183 }