View Javadoc

1   /*
2      Copyright 2008 Ramon Servadei
3   
4      Licensed under the Apache License, Version 2.0 (the "License");
5      you may not use this file except in compliance with the License.
6      You may obtain a copy of the License at
7   
8          http://www.apache.org/licenses/LICENSE-2.0
9   
10     Unless required by applicable law or agreed to in writing, software
11     distributed under the License is distributed on an "AS IS" BASIS,
12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13     See the License for the specific language governing permissions and
14     limitations under the License.
15   */
16  package fulmine.context;
17  
18  import static fulmine.util.Utils.logException;
19  import static fulmine.util.Utils.safeToString;
20  
21  import java.util.Collection;
22  import java.util.Map;
23  import java.util.Set;
24  
25  import fulmine.AbstractLifeCycle;
26  import fulmine.IDomain;
27  import fulmine.IType;
28  import fulmine.Type;
29  import fulmine.model.IModelManager;
30  import fulmine.model.container.ContainerFactory;
31  import fulmine.model.container.IContainer;
32  import fulmine.model.container.IContainerFactory;
33  import fulmine.util.collection.CollectionFactory;
34  import fulmine.util.log.AsyncLog;
35  import fulmine.util.reference.AutoCreatingStore;
36  import fulmine.util.reference.IAutoCreatingStore;
37  import fulmine.util.reference.IObjectBuilder;
38  
39  /**
40   * A manager for the {@link IContainer} instances created in a context. This
41   * manages both local and remote container instances. These are held in separate
42   * {@link Map} instances.
43   * 
44   * @see IFulmineContext
45   * @author Ramon Servadei
46   */
47  final class ModelManager extends AbstractLifeCycle implements IModelManager
48  {
49      private final static AsyncLog LOG = new AsyncLog(DistributionManager.class);
50  
51      /**
52       * All the remote {@link IContainer} instances. The containers are grouped
53       * by remote context identity, type, domain, container identity.
54       */
55      final IAutoCreatingStore<String, IAutoCreatingStore<IType, IAutoCreatingStore<IDomain, Map<String, IContainer>>>> remoteContainers;
56  
57      /**
58       * All the local {@link IContainer} instances. The containers are grouped by
59       * type, domain, container identity.
60       */
61      final IAutoCreatingStore<IType, IAutoCreatingStore<IDomain, Map<String, IContainer>>> localContainers;
62  
63      /**
64       * Builds {@link AutoCreatingStore} instances keyed by {@link IDomain}
65       * 
66       * @author Ramon Servadei
67       */
68      private static final class BuilderKeyedByDomain
69          implements
70          IObjectBuilder<IType, IAutoCreatingStore<IDomain, Map<String, IContainer>>>
71      {
72          public IAutoCreatingStore<IDomain, Map<String, IContainer>> create(
73              IType key)
74          {
75              return new AutoCreatingStore<IDomain, Map<String, IContainer>>(
76                  new BuilderKeyedOnString());
77          }
78      }
79  
80      /**
81       * Builds {@link AutoCreatingStore} instances keyed by {@link Type}.
82       * 
83       * @author Ramon Servadei
84       */
85      private static final class BuilderKeyedByType
86          implements
87          IObjectBuilder<String, IAutoCreatingStore<IType, IAutoCreatingStore<IDomain, Map<String, IContainer>>>>
88      {
89  
90          public IAutoCreatingStore<IType, IAutoCreatingStore<IDomain, Map<String, IContainer>>> create(
91              String key)
92          {
93              return new AutoCreatingStore<IType, IAutoCreatingStore<IDomain, Map<String, IContainer>>>(
94                  new BuilderKeyedByDomain());
95          }
96      }
97  
98      /**
99       * Builds {@link Map} instances keyed on {@link String}
100      * 
101      * @author Ramon Servadei
102      */
103     private static final class BuilderKeyedOnString implements
104         IObjectBuilder<IDomain, Map<String, IContainer>>
105     {
106         public Map<String, IContainer> create(IDomain key)
107         {
108             return CollectionFactory.newMap();
109         }
110     }
111 
112     /** The context */
113     private final IFrameworkContext context;
114 
115     /** The container factory for this context */
116     private final IContainerFactory containerFactory;
117 
118     /**
119      * Standard constructor
120      * 
121      * @param context
122      *            the context this is associated with
123      */
124     ModelManager(IFrameworkContext context)
125     {
126         super();
127         this.context = context;
128         this.containerFactory = new ContainerFactory();
129         this.localContainers =
130             new AutoCreatingStore<IType, IAutoCreatingStore<IDomain, Map<String, IContainer>>>(
131                 new BuilderKeyedByDomain());
132         this.remoteContainers =
133             new AutoCreatingStore<String, IAutoCreatingStore<IType, IAutoCreatingStore<IDomain, Map<String, IContainer>>>>(
134                 new BuilderKeyedByType());
135     }
136 
137     @Override
138     protected AsyncLog getLog()
139     {
140         return LOG;
141     }
142 
143     @Override
144     protected final void doStart()
145     {
146         if (getLog().isInfoEnabled())
147         {
148             getLog().info("Started");
149         }
150     }
151 
152     @Override
153     protected final void doDestroy()
154     {
155         clearLocalContainers();
156         clearRemoteContainers();
157         this.containerFactory.destroy();
158     }
159 
160     public IContainer getLocalContainer(String identity, IType type,
161         IDomain domain)
162     {
163         return doGet(this.context.getIdentity(), identity, type, domain,
164             this.localContainers, true);
165     }
166 
167     public boolean containsLocalContainer(String containerIdentity, IType type,
168         IDomain domain)
169     {
170         return doContainerExists(containerIdentity, type, domain,
171             this.localContainers);
172     }
173 
174     public IContainer getRemoteContainer(String remoteContextIdentity,
175         final String identity, final IType type, IDomain domain)
176     {
177         return doGet(remoteContextIdentity, identity, type, domain,
178             this.remoteContainers.get(remoteContextIdentity), false);
179     }
180 
181     public boolean containsRemoteContainer(String remoteContextIdentity,
182         String containerIdentity, IType type, IDomain domain)
183     {
184         return doContainerExists(containerIdentity, type, domain,
185             this.remoteContainers.get(remoteContextIdentity));
186     }
187 
188     public void addContainer(IContainer container)
189     {
190         if (container.isLocal())
191         {
192             doAdd(container.getIdentity(), container, this.localContainers);
193         }
194         else
195         {
196             doAdd(container.getIdentity(), container,
197                 this.remoteContainers.get(container.getNativeContextIdentity()));
198         }
199     }
200 
201     public boolean removeContainer(IContainer container)
202     {
203         if (container == null || container.getContext() == null)
204         {
205             return false;
206         }
207         if (container.isLocal())
208         {
209             return doRemove(container.getIdentity(), container.getType(),
210                 container.getDomain(), this.localContainers);
211         }
212         final boolean doRemove =
213             doRemove(container.getIdentity(), container.getType(),
214                 container.getDomain(),
215                 this.remoteContainers.get(container.getNativeContextIdentity()));
216         return doRemove;
217     }
218 
219     public Collection<IContainer> getLocalContainers()
220     {
221         return doGetAll(this.localContainers);
222     }
223 
224     public Collection<IContainer> getRemoteContainers(
225         String remoteContextIdentity)
226     {
227         return doGetAll(this.remoteContainers.get(remoteContextIdentity));
228     }
229 
230     public IContainerFactory getContainerFactory()
231     {
232         return this.containerFactory;
233     }
234 
235     /**
236      * Purge all remote containers
237      */
238     void clearRemoteContainers()
239     {
240         if (getLog().isInfoEnabled())
241         {
242             getLog().info("Removing all remote containers");
243         }
244         synchronized (this.remoteContainers)
245         {
246             final Set<String> remoteContextIdentities =
247                 CollectionFactory.newSet(this.remoteContainers.keySet());
248             for (String remoteContextIdentity : remoteContextIdentities)
249             {
250                 doClear(this.remoteContainers.get(remoteContextIdentity));
251             }
252         }
253     }
254 
255     /**
256      * Purge all local containers
257      */
258     void clearLocalContainers()
259     {
260         if (getLog().isInfoEnabled())
261         {
262             getLog().info("Removing all local containers");
263         }
264         doClear(this.localContainers);
265     }
266 
267     /**
268      * Helper method to get all containers from a cache
269      * 
270      * @param containers
271      *            the cache of containers
272      * @return a new {@link Collection} instance with all the containers in the
273      *         cache
274      */
275     private Collection<IContainer> doGetAll(
276         IAutoCreatingStore<IType, IAutoCreatingStore<IDomain, Map<String, IContainer>>> containers)
277     {
278         synchronized (containers)
279         {
280             Collection<IContainer> all = CollectionFactory.newSet();
281             final Set<IType> keySet = containers.keySet();
282             for (IType type : keySet)
283             {
284                 try
285                 {
286                     final Set<IDomain> domains = containers.get(type).keySet();
287                     for (IDomain domain : domains)
288                     {
289                         all.addAll(containers.get(type).get(domain).values());
290                     }
291                 }
292                 catch (Exception e)
293                 {
294                     logException(getLog(), type, e);
295                 }
296             }
297             return all;
298         }
299     }
300 
301     /**
302      * Helper method to get a container from a cache. If the container does not
303      * exist, it is created.
304      * 
305      * @param nativeContextIdentity
306      *            whether the container is local
307      * @param type
308      *            the container type to find
309      * @param domain
310      *            the domain of the container
311      * @param containers
312      *            the cache of containers
313      * @param local
314      *            <code>true</code> the container is local to this context
315      * @param containerIdentity
316      *            the identity of the container to find
317      * @return the container
318      */
319     private IContainer doGet(
320         String nativeContextIdentity,
321         String identity,
322         IType type,
323         IDomain domain,
324         IAutoCreatingStore<IType, IAutoCreatingStore<IDomain, Map<String, IContainer>>> containers,
325         boolean local)
326     {
327         IContainer container = null;
328         synchronized (containers)
329         {
330             container = containers.get(type).get(domain).get(identity);
331         }
332         if (container == null)
333         {
334             container =
335                 getContainerFactory().createContainer(nativeContextIdentity,
336                     identity, type, domain, this.context, local);
337             // NOTE: no need to add, creating will do this automatically
338         }
339         return container;
340     }
341 
342     /**
343      * Helper method to unregister all listeners from all containers, destroy
344      * the containers and clear the cache
345      * 
346      * @param containers
347      *            the cache of containers to clear
348      */
349     private void doClear(
350         IAutoCreatingStore<IType, IAutoCreatingStore<IDomain, Map<String, IContainer>>> containers)
351     {
352         final Collection<IContainer> all = doGetAll(containers);
353         for (IContainer container : all)
354         {
355             try
356             {
357                 container.destroy();
358             }
359             catch (Exception e)
360             {
361                 logException(getLog(), container, e);
362             }
363         }
364         synchronized (containers)
365         {
366             containers.clear();
367         }
368     }
369 
370     /**
371      * Helper method to find a container in a cache
372      * 
373      * @param containerIdentity
374      *            the identity of the container to find
375      * @param type
376      *            the container type to find
377      * @param domain
378      *            the domain to find
379      * @param containers
380      *            the cache of containers
381      * 
382      * @return <code>true</code> if the container was found in the containers
383      */
384     private boolean doContainerExists(
385         String containerIdentity,
386         IType type,
387         IDomain domain,
388         IAutoCreatingStore<IType, IAutoCreatingStore<IDomain, Map<String, IContainer>>> containers)
389     {
390         synchronized (containers)
391         {
392             if (!containers.containsKey(type))
393             {
394                 return false;
395             }
396             if (!containers.get(type).containsKey(domain))
397             {
398                 return false;
399             }
400             return containers.get(type).get(domain).containsKey(
401                 containerIdentity);
402         }
403     }
404 
405     /**
406      * Helper method to add a container to a cache
407      * 
408      * @param identity
409      *            the identity of the container to add
410      * @param container
411      *            the container to add
412      * @param containers
413      *            the cache of containers
414      */
415     private void doAdd(
416         String identity,
417         IContainer container,
418         IAutoCreatingStore<IType, IAutoCreatingStore<IDomain, Map<String, IContainer>>> containers)
419     {
420         IContainer previous = null;
421         synchronized (containers)
422         {
423             previous =
424                 containers.get(container.getType()).get(container.getDomain()).put(
425                     identity, container);
426         }
427         if (previous != null)
428         {
429             if (getLog().isInfoEnabled())
430             {
431                 getLog().info(
432                     "Previous container has been overwritten: " + previous
433                         + " with: " + safeToString(container), new Exception());
434             }
435         }
436     }
437 
438     /**
439      * Helper method to remove a container from a cache
440      * 
441      * @param identity
442      *            the container identity to remove
443      * @param type
444      *            the container type
445      * @param domain
446      *            the domain for the container
447      * @param containers
448      *            the cache to remove the container from
449      * @return <code>true</code> if the container was removed,
450      *         <code>false</code> if the container was not found
451      */
452     private boolean doRemove(
453         String identity,
454         IType type,
455         IDomain domain,
456         IAutoCreatingStore<IType, IAutoCreatingStore<IDomain, Map<String, IContainer>>> containers)
457     {
458         synchronized (containers)
459         {
460             if (containers.containsKey(type))
461             {
462                 final IAutoCreatingStore<IDomain, Map<String, IContainer>> types =
463                     containers.get(type);
464                 if (types.containsKey(domain))
465                 {
466                     final IContainer removed =
467                         types.get(domain).remove(identity);
468                     return removed != null;
469                 }
470             }
471         }
472         return false;
473     }
474 
475 }