KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > jcorporate > expresso > kernel > DefaultContainerImpl


1 /* ====================================================================
2  * The Jcorporate Apache Style Software License, Version 1.2 05-07-2002
3  *
4  * Copyright (c) 1995-2003 Jcorporate Ltd. All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  *
10  * 1. Redistributions of source code must retain the above copyright
11  * notice, this list of conditions and the following disclaimer.
12  *
13  * 2. Redistributions in binary form must reproduce the above copyright
14  * notice, this list of conditions and the following disclaimer in
15  * the documentation and/or other materials provided with the
16  * distribution.
17  *
18  * 3. The end-user documentation included with the redistribution,
19  * if any, must include the following acknowledgment:
20  * "This product includes software developed by Jcorporate Ltd.
21  * (http://www.jcorporate.com/)."
22  * Alternately, this acknowledgment may appear in the software itself,
23  * if and wherever such third-party acknowledgments normally appear.
24  *
25  * 4. "Jcorporate" and product names such as "Expresso" must
26  * not be used to endorse or promote products derived from this
27  * software without prior written permission. For written permission,
28  * please contact info@jcorporate.com.
29  *
30  * 5. Products derived from this software may not be called "Expresso",
31  * or other Jcorporate product names; nor may "Expresso" or other
32  * Jcorporate product names appear in their name, without prior
33  * written permission of Jcorporate Ltd.
34  *
35  * 6. No product derived from this software may compete in the same
36  * market space, i.e. framework, without prior written permission
37  * of Jcorporate Ltd. For written permission, please contact
38  * partners@jcorporate.com.
39  *
40  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
41  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
42  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
43  * DISCLAIMED. IN NO EVENT SHALL JCORPORATE LTD OR ITS CONTRIBUTORS
44  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
45  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
46  * TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
47  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
48  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
49  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
50  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
51  * SUCH DAMAGE.
52  * ====================================================================
53  *
54  * This software consists of voluntary contributions made by many
55  * individuals on behalf of the Jcorporate Ltd. Contributions back
56  * to the project(s) are encouraged when you make modifications.
57  * Please send them to support@jcorporate.com. For more information
58  * on Jcorporate Ltd. and its products, please see
59  * <http://www.jcorporate.com/>.
60  *
61  * Portions of this software are based upon other open source
62  * products and are subject to their respective licenses.
63  */

64 package com.jcorporate.expresso.kernel;
65
66 import EDU.oswego.cs.dl.util.concurrent.ConcurrentReaderHashMap;
67 import EDU.oswego.cs.dl.util.concurrent.ReadWriteLock;
68 import EDU.oswego.cs.dl.util.concurrent.WriterPreferenceReadWriteLock;
69 import com.jcorporate.expresso.kernel.exception.InstallationException;
70 import com.jcorporate.expresso.kernel.internal.ContainerImplBase;
71 import org.apache.log4j.Logger;
72
73 import java.util.ArrayList JavaDoc;
74 import java.util.Collections JavaDoc;
75 import java.util.HashMap JavaDoc;
76 import java.util.Iterator JavaDoc;
77 import java.util.List JavaDoc;
78 import java.util.Map JavaDoc;
79
80 /**
81  * This class is the default Container Implementation used by the Expresso
82  * Framework. You can change this by modifying the SystemFactory.
83  * <p>It provides basic container usability such as component location,
84  * component management, component listeners, etc </p>
85  *
86  * @author Michael Rimov
87  */

88 public class DefaultContainerImpl extends ContainerImplBase {
89
90     /**
91      * Read Write lock on the container
92      */

93     private ReadWriteLock containerLock = new WriterPreferenceReadWriteLock();
94
95     /**
96      * The parent container of this component.
97      */

98     private ComponentContainer parent = null;
99
100     /**
101      * A map of child components keyed by the component name. (java.lang.String)
102      */

103     private Map childComponents = new ConcurrentReaderHashMap();
104
105     /**
106      * List of all listeners... this map must be locked before using.
107      */

108     private List JavaDoc containerListeners = new ArrayList JavaDoc();
109
110     /**
111      * Logger instance
112      */

113     private static final Logger log = Logger.getLogger(DefaultContainerImpl.class);
114
115     /**
116      * Basic constructor.
117      */

118     public DefaultContainerImpl() {
119         super();
120     }
121
122     /**
123      * Removes a component from this container.
124      *
125      * @param componentName The name of the component to remove.
126      */

127     public void removeComponent(String JavaDoc componentName) {
128         try {
129             containerLock.writeLock().acquire();
130         } catch (InterruptedException JavaDoc ex) {
131             log.error("Interrupted waiting for write lock. Aborting method", ex);
132             return;
133         }
134
135         try {
136             childComponents.remove(componentName);
137         } finally {
138             containerLock.writeLock().release();
139         }
140     }
141
142     /**
143      * Retrieves a list of instances of all contained ExpressoComponents. Use
144      * this for iterating through the components of a current 'context'. Do not
145      * attempt to modify the map given. Either add or remove a component through
146      * the addComponent or removeComponent methods.
147      *
148      * @return Read only map of the components.
149      */

150     public Map getChildComponents() {
151         try {
152             containerLock.readLock().acquire();
153         } catch (InterruptedException JavaDoc ex) {
154             log.error("Interrupted waiting for read lock. Aborting method", ex);
155             return new HashMap();
156         }
157         try {
158             return Collections.unmodifiableMap(childComponents);
159         } finally {
160             containerLock.readLock().release();
161         }
162     }
163
164     /**
165      * Locates an Expresso Service for use by a client.
166      *
167      * @param componentName the name of the service to locate.
168      * @return ExpressoService.
169      * @throws IllegalArgumentException if the service cannot be found.
170      * @throws IllegalStateException if the service exists, but is not in a
171      * 'runnable' state due to some configuration error or other unforeseen
172      * issue.
173      */

174     public ExpressoComponent locateComponent(String JavaDoc componentName) {
175         try {
176             containerLock.readLock().acquire();
177         } catch (InterruptedException JavaDoc ex) {
178             log.error("Interrupted waiting for read lock. Aborting method", ex);
179             return null;
180         }
181
182         try {
183             ExpressoComponent returnValue = (ExpressoComponent) childComponents.get(componentName);
184             if (returnValue == null && _getParentContainer() != null) {
185                 returnValue = _getParentContainer().locateComponent(componentName);
186             }
187
188             return returnValue;
189         } finally {
190             containerLock.readLock().release();
191         }
192     }
193
194     /**
195      * Install a component into the system. If newComponent implements <code>
196      * installable</code> then it shall be installed. After that, the component
197      * is added.
198      *
199      * @param newComponent An instance of the component to install.
200      * @param installOptions any installation options [optional]
201      * @param installLog a Logger-like interface to a component tha records the process
202      * of the installation including any errors, etc.
203      */

204     public void installComponent(ExpressoComponent newComponent,
205                                  InstallationOptions installOptions,
206                                  InstallLog installLog) {
207         if (log.isInfoEnabled()) {
208             log.info("Installing component: " + newComponent.getMetaData().getName() +
209                     " class: " + newComponent.getClass().getName());
210         }
211         try {
212             containerLock.writeLock().acquire();
213         } catch (InterruptedException JavaDoc ex) {
214             log.error("Interrupted waiting for write lock. Aborting method", ex);
215             installLog.error("Error getting container lock, Aborting Installation", ex);
216             return;
217         }
218
219         try {
220             this.addComponent(newComponent);
221
222             try {
223                 if (newComponent instanceof Installable) {
224                     Installable i = (Installable) newComponent;
225                     i.install(installOptions, installLog);
226                 }
227
228                 if (log.isInfoEnabled()) {
229                     log.info("Successfully installed component: " + newComponent.getMetaData().getName());
230                 }
231             } catch (InstallationException ex) {
232                 log.error("Error installing component: " + newComponent.getClass().getName());
233                 this.removeComponent(newComponent.getMetaData().getName());
234             }
235         } finally {
236             containerLock.writeLock().release();
237         }
238     }
239
240     /**
241      * Uninstalls the component. If the component implements <code>
242      * installable</code> then it shall be uninstalled. After that, it shall
243      * be removed.
244      *
245      * @param componentName the name of the component to uninstall
246      * @param installLog a Logger-like interface to a component tha records the process
247      * of the installation including any errors, etc.
248      * @param installOptions any installation options to use.
249      */

250     public void uninstallComponent(String JavaDoc componentName,
251                                    InstallationOptions installOptions,
252                                    InstallLog installLog) {
253         if (log.isInfoEnabled()) {
254             log.info("Installing component: " + componentName);
255         }
256
257         try {
258             containerLock.writeLock().acquire();
259         } catch (InterruptedException JavaDoc ex) {
260             log.error("Interrupted waiting for write lock. Aborting method", ex);
261             installLog.error("Error getting container lock, Aborting Installation", ex);
262             return;
263         }
264
265         ExpressoComponent removeComponent = null;
266         try {
267
268             removeComponent = (ExpressoComponent) childComponents.get(componentName);
269             if (removeComponent == null) {
270                 throw new IllegalArgumentException JavaDoc("Component: '" + componentName +
271                         "' does not exist in this container");
272             }
273
274             if (removeComponent instanceof Installable) {
275                 Installable i = (Installable) removeComponent;
276                 i.uninstall(installOptions, installLog);
277             }
278
279             if (log.isInfoEnabled()) {
280                 log.info("Successfully installed component: " + removeComponent.getMetaData().getName());
281             }
282         } catch (InstallationException ex) {
283
284             log.error("Error installing component: " + componentName);
285             this.removeComponent(removeComponent.getMetaData().getName());
286         } finally {
287             containerLock.writeLock().release();
288         }
289
290     }
291
292     /**
293      * Query the container to see if a particular service name is installed
294      * in the system
295      *
296      * @param componentName the name of the component to query for.
297      * @return true if the service is installed and running.
298      */

299     public boolean isComponentExists(String JavaDoc componentName) {
300         try {
301             containerLock.readLock().acquire();
302         } catch (InterruptedException JavaDoc ex) {
303             log.error("Interrupted waiting for read lock. Aborting method", ex);
304             return false;
305         }
306         try {
307             return _isComponentExists(componentName);
308         } finally {
309             containerLock.readLock().release();
310         }
311
312     }
313
314
315     /**
316      * Version of isComponentExists without the locking. Prevents deadlocks
317      * for internal use.
318      *
319      * @param componentName the name of the component
320      * @return true if the component exists
321      */

322     protected boolean _isComponentExists(String JavaDoc componentName) {
323         boolean returnValue = childComponents.containsKey(componentName);
324         if (returnValue == false && _getParentContainer() != null) {
325             returnValue = _getParentContainer().isComponentExists(componentName);
326         }
327         return returnValue;
328     }
329
330     /**
331      * To register the component for control by the Component Manager. This will
332      * in essense transfer the control of ther service to the Component Manager.
333      * This will often be called by the Configuration Bootstrap system.
334      *
335      * @param newComponent the component to install
336      */

337     public void addComponent(ExpressoComponent newComponent) {
338         if (newComponent == null) {
339             throw new IllegalArgumentException JavaDoc("newComponent must not be null");
340         }
341
342         try {
343             containerLock.writeLock().acquire();
344         } catch (InterruptedException JavaDoc ex) {
345             log.error("Interrupted waiting for read lock. Aborting method", ex);
346             return;
347         }
348
349         try {
350
351             if (this._isComponentExists(newComponent.getMetaData().getName())) {
352                 throw new IllegalArgumentException JavaDoc("Error adding component: " +
353                         newComponent.getClass().getName() + " of name " +
354                         newComponent.getMetaData().getName()
355                         + " already exists in the container.");
356             }
357
358
359             childComponents.put(newComponent.getMetaData().getName(), newComponent);
360         } finally {
361             containerLock.writeLock().release();
362         }
363     }
364
365     /**
366      * Return the parent container
367      *
368      * @return ContainerImpl interface
369      */

370     public ComponentContainer getParentContainer() {
371         try {
372             containerLock.readLock().acquire();
373         } catch (InterruptedException JavaDoc ex) {
374             log.error("Interrupted waiting for read lock. Aborting method", ex);
375             return null;
376         }
377
378         try {
379             return parent;
380         } finally {
381             containerLock.readLock().release();
382         }
383     }
384
385     /**
386      * getParentContainer without the locking
387      *
388      * @return ComponentContainer instance
389      */

390     protected ComponentContainer _getParentContainer() {
391         return parent;
392     }
393
394     /**
395      * Set the parent container of this container
396      *
397      * @param newParent the new Parent Container
398      */

399     public void setParentContainer(ComponentContainer newParent) {
400         try {
401             containerLock.writeLock().acquire();
402         } catch (InterruptedException JavaDoc ex) {
403             log.error("Interrupted waiting for read lock. Aborting method", ex);
404             return;
405         }
406
407         try {
408             parent = newParent;
409         } finally {
410             containerLock.writeLock().release();
411         }
412     }
413
414     /**
415      * Global Container Destruction. Iterate depth first through all the subcompoennts,
416      * possibly calling stop, and possibly calling destroy.
417      */

418     public void destroyContainer() {
419         try {
420             containerLock.writeLock().acquire();
421         } catch (InterruptedException JavaDoc ex) {
422             log.error("Interrupted waiting for read lock. Aborting method", ex);
423             return;
424         }
425
426         try {
427             if (log.isInfoEnabled()) {
428                 log.info("Destroying Container " + this.getClass().getName());
429             }
430
431             for (Iterator JavaDoc i = childComponents.values().iterator(); i.hasNext();) {
432                 Object JavaDoc nextObject = i.next();
433                 String JavaDoc componentName = nextObject.getClass().getName();
434                 if (nextObject instanceof Startable) {
435                     if (log.isInfoEnabled()) {
436                         log.info("Stopping : " + componentName);
437                     }
438
439                     try {
440                         ((Startable) nextObject).stop();
441                     } catch (Throwable JavaDoc ex) {
442                         log.error("Error stopping component: " +
443                                 nextObject.getClass().getName(), ex);
444                     }
445                 }
446
447                 if (nextObject instanceof Containable) {
448                     try {
449                         ((Containable) nextObject).getContainerImplementation().destroyContainer();
450                     } catch (Throwable JavaDoc ex) {
451                         log.error("Error destroying container: " +
452                                 nextObject.getClass().getName(), ex);
453                     }
454                 }
455
456                 if (nextObject instanceof ComponentLifecycle) {
457                     if (log.isInfoEnabled()) {
458                         log.info("Destroying : " + componentName);
459                         try {
460                             ((ComponentLifecycle) nextObject).destroy();
461                         } catch (Throwable JavaDoc ex) {
462                             log.error("Error destroying component: " +
463                                     nextObject.getClass().getName(), ex);
464                         }
465                     }
466
467                 }
468             }
469
470             childComponents.clear();
471         } catch (Throwable JavaDoc t) {
472             log.error("Error destroying component", t);
473         } finally {
474             containerLock.writeLock().release();
475         }
476     }
477
478     /**
479      * Just in case..... if all references to the root container have been
480      * released and GC is running, then make sure we 'cleanly' destroy all
481      * nested components. Of course, since finalize() doesn't necessarily
482      * get called, this isn't a guaranteed fixit.. but at least it's a shot
483      * in the right direction
484      */

485     protected void finalize() throws java.lang.Throwable JavaDoc {
486         if (childComponents != null && !childComponents.isEmpty()) {
487             if (log != null) {
488                 log.warn("Container getting GC'ed and subcomponents " +
489                         "have not been destroyed.");
490             }
491             destroyContainer();
492         }
493
494         super.finalize();
495     }
496
497
498 }
Popular Tags