View Javadoc

1   /*$Id: EmptyCEAComponentManager.java,v 1.20 2006/03/17 17:50:58 clq2 Exp $
2    * Created on 04-May-2004
3    *
4    * Copyright (C) AstroGrid. All rights reserved.
5    *
6    * This software is published under the terms of the AstroGrid 
7    * Software License version 1.2, a copy of which has been included 
8    * with this distribution in the LICENSE.txt file.  
9    *
10  **/
11  package org.astrogrid.applications.component;
12  
13  import org.astrogrid.applications.contracts.Configuration;
14  import org.astrogrid.applications.manager.AppAuthorityIDResolver;
15  import org.astrogrid.applications.description.ApplicationDescription;
16  import org.astrogrid.applications.description.ApplicationDescriptionLibrary;
17  import org.astrogrid.applications.description.BaseApplicationDescriptionLibrary;
18  import org.astrogrid.applications.description.CompositeApplicationDescriptionLibrary;
19  import org.astrogrid.applications.description.base.ApplicationDescriptionEnvironment;
20  import org.astrogrid.applications.description.registry.RegistryAdminLocator;
21  import org.astrogrid.applications.description.registry.RegistryAdminLocatorImpl;
22  import org.astrogrid.applications.description.registry.RegistryUploader;
23  import org.astrogrid.applications.manager.ApplicationEnvironmentRetriver;
24  import org.astrogrid.applications.manager.BaseConfiguration;
25  import org.astrogrid.applications.manager.CeaThreadPool;
26  import org.astrogrid.applications.manager.ControlService;
27  import org.astrogrid.applications.manager.DefaultAppAuthorityIDResolver;
28  import org.astrogrid.applications.manager.DefaultApplicationEnvironmentRetriever;
29  import org.astrogrid.applications.manager.DefaultMetadataService;
30  import org.astrogrid.applications.manager.DefaultQueryService;
31  import org.astrogrid.applications.manager.ExecutionController;
32  import org.astrogrid.applications.manager.MetadataService;
33  import org.astrogrid.applications.manager.QueryService;
34  import org.astrogrid.applications.manager.ThreadPoolExecutionController;
35  import org.astrogrid.applications.manager.idgen.GloballyUniqueIdGen;
36  import org.astrogrid.applications.manager.idgen.IdGen;
37  import org.astrogrid.applications.manager.persist.ExecutionHistory;
38  import org.astrogrid.applications.manager.persist.FileStoreExecutionHistory;
39  import org.astrogrid.applications.manager.persist.InMemoryExecutionHistory;
40  import org.astrogrid.applications.parameter.protocol.DefaultProtocolLibrary;
41  import org.astrogrid.applications.parameter.protocol.FileProtocol;
42  import org.astrogrid.applications.parameter.protocol.FtpProtocol;
43  import org.astrogrid.applications.parameter.protocol.HttpProtocol;
44  import org.astrogrid.applications.parameter.protocol.IvornProtocol;
45  import org.astrogrid.applications.parameter.protocol.Protocol;
46  import org.astrogrid.applications.parameter.protocol.ProtocolLibrary;
47  import org.astrogrid.component.EmptyComponentManager;
48  import org.astrogrid.config.Config;
49  import org.astrogrid.config.SimpleConfig;
50  import org.astrogrid.registry.client.RegistryDelegateFactory;
51  import org.astrogrid.registry.client.admin.RegistryAdminService;
52  
53  import org.apache.commons.logging.Log;
54  import org.apache.commons.logging.LogFactory;
55  import org.picocontainer.ComponentAdapter;
56  import org.picocontainer.MutablePicoContainer;
57  import org.picocontainer.Startable;
58  
59  import EDU.oswego.cs.dl.util.concurrent.PooledExecutor;
60  
61  import java.io.File;
62  import java.net.MalformedURLException;
63  import java.net.URL;
64  import java.util.Iterator;
65  
66  /*** empty implementation of {@link org.astrogrid.applications.component.CEAComponentManager}
67   * provides implementations of the accessor methods, but no componets are registered with the container. (this should be done in subclasses).
68   * <p>
69   * This class also provides a set of static helper method that register 'clusters' of commonly-used components. These
70   * can be called from implementations of component manager to quickly set up the basic parts of the system
71   * @author Noel Winstanley nw@jb.man.ac.uk 04-May-2004
72   * @TODO might be nice to have rather fewer static methods in this design to allow for overriding in subclasses - easier for a component manager to override just a part of the standard setup.
73   * @see org.astrogrid.applications.component.JavaClassCEAComponentManager for example of how to assemble a server using this class.
74   *
75   */
76  public abstract class EmptyCEAComponentManager 
77      extends EmptyComponentManager 
78      implements CEAComponentManager{
79      /***
80       * Commons Logger for this class
81       */
82      protected static final Log logger = LogFactory
83              .getLog(EmptyCEAComponentManager.class);
84  
85      /*** Construct a new EmptyCEAComponentManager
86       * 
87       */
88      public EmptyCEAComponentManager() {
89        super();
90      }
91  
92      /***
93       * @see org.astrogrid.applications.component.CEAComponentManager#getController()
94       */
95      public final ExecutionController getExecutionController() {
96          return (ExecutionController)this.pico.getComponentInstanceOfType(ExecutionController.class);
97      }
98  
99      /***
100      * @see org.astrogrid.applications.component.CEAComponentManager#getMetaData()
101      */
102     public final MetadataService getMetadataService() {
103         return (MetadataService)this.pico.getComponentInstanceOfType(MetadataService.class);
104     }
105     
106     public final QueryService getQueryService() {
107         return (QueryService)this.pico.getComponentInstanceOfType(QueryService.class);
108     }
109     
110     public final RegistryUploader getRegistryUploaderService() {
111        return (RegistryUploader)this.pico.getComponentInstance(RegistryUploader.class);
112     }
113     
114     public final ControlService getControlService() {
115        return (ControlService) this.pico.getComponentInstanceOfType(ControlService.class);
116     }
117     
118     public final Configuration getConfiguration() {
119       return (Configuration)this.pico.getComponentInstanceOfType(Configuration.class);
120     }
121 
122     // convenience methods for regostering commnly used sets of components
123     /*** register the default top-level services core of CEA 
124      * registers default implementations of {@link QueryService}, {@link MetadataService} and {@link ExecutionController},
125      * plus the {@link ApplicationDescriptionEnvironment}
126      * also registers a composite application description library, and a container application description library.
127      * @see #registerCompositeApplicationDescriptionLibrary(MutablePicoContainer)
128      * @see #registerContainerApplicationDescriptionLibrary(MutablePicoContainer)
129      * */
130     protected  final void registerDefaultServices(MutablePicoContainer pico) {
131        log.debug("Registering default services");
132         
133        pico.registerComponentImplementation(ApplicationDescriptionEnvironment.class,ApplicationDescriptionEnvironment.class);
134        pico.registerComponentImplementation(ExecutionController.class,ThreadPoolExecutionController.class);
135        pico.registerComponentImplementation(PooledExecutor.class,CeaThreadPool.class);
136        pico.registerComponentImplementation(QueryService.class,DefaultQueryService.class);   
137        registerCompositeApplicationDescriptionLibrary(pico);
138        registerEnvironmentRetriever(pico);
139        
140        // the protocol lib
141        EmptyCEAComponentManager.registerProtocolLibrary(pico);
142        EmptyCEAComponentManager.registerStandardIndirectionProtocols(pico);
143        EmptyCEAComponentManager.registerAstrogridIndirectionProtocols(pico);
144        
145        // The persistence mechanism. This is needed to make the QueryService work.
146        this.registerDefaultPersistence(pico, SimpleConfig.getSingleton());
147        
148        // This seems to be necessary to get the ApplicationDescriptionEnvironment to work.
149        this.registerDefaultVOProvider(pico);
150        
151        log.info("Components for a generic CEC have been registered.");
152     }
153     
154     /*** registers the default implementaiton of the indirection protocol library 
155      * NB: does not register any protocols with the library. These must be added to the container separately
156      * any protocols added to the container  wil be detected and added to the library on startup
157      * @see #registerStandardIndirectionProtocols(MutablePicoContainer)
158      * @see #registerAstrogridIndirectionProtocols(MutablePicoContainer)*/
159     protected static final void registerProtocolLibrary(final MutablePicoContainer pico) {
160         log.debug("Registering default indirection protocol library");
161         pico.registerComponentImplementation(ProtocolLibrary.class,DefaultProtocolLibrary.class);
162         // on startup (i.e. after everythinig has been registered, this throwaway component will add all known indirection protocols to the library).
163         pico.registerComponentInstance(new Startable() {
164             public void start() {
165                 DefaultProtocolLibrary lib = (DefaultProtocolLibrary) pico.getComponentInstanceOfType(DefaultProtocolLibrary.class);
166                 for (Iterator i = pico.getComponentAdaptersOfType(Protocol.class).iterator(); i.hasNext(); ) {
167                     ComponentAdapter ca = (ComponentAdapter)i.next();
168                     Protocol p = (Protocol)ca.getComponentInstance(pico);
169                     lib.addProtocol(p);
170                 }
171             }
172 
173             public void stop() {
174             }
175         });
176     }
177     
178     /*** registers the standard indirection protocols - http:, ftp:, file: */
179     protected static final void registerStandardIndirectionProtocols(MutablePicoContainer pico) {
180         pico.registerComponentImplementation(HttpProtocol.class);
181         pico.registerComponentImplementation(FtpProtocol.class);
182         pico.registerComponentImplementation(FileProtocol.class);
183     }
184     
185     /*** registers the astorgird-specific protocols - ivo: and agsl:*/
186     protected static final void registerAstrogridIndirectionProtocols(MutablePicoContainer pico) {
187         pico.registerComponentImplementation(IvornProtocol.class);
188     }
189     
190     /*** key used to determing from config where to store execution history files
191      * @see #registerDefaultPersistence(MutablePicoContainer, Config) */
192     public static final String FILESTORE_BASEDIR = "cea.filestore.basedir";
193     
194     /*** key used to determine which persistence back-end to use -
195      * <br> valid values - <tt>file</tt>, <tt>memory</tt>
196      * <br>optional- defaults to <tt>file</tt>*/
197     public static final String PERSISTENCE_BACKEND = "cea.persistence.backend";
198     
199     /*** register the standard persistence system - globally unique id generation, and file-based exection history 
200      * configured by {@link #FILESTORE_BASEDIR}
201      * */
202     protected static final void registerDefaultPersistence(MutablePicoContainer pico, final Config config) {
203 
204         String backend = System.getProperty(PERSISTENCE_BACKEND,"file").toLowerCase().trim();
205         if (backend.equals("memory")) {
206             log.warn("Only using memory-based persistence system - all history will be lost on restart");
207             pico.registerComponentImplementation(ExecutionHistory.class,InMemoryExecutionHistory.class);
208         } else {
209             if (! backend.equals("file")) {
210                 log.error("Unrecognized value '" + backend + "' for key " +  PERSISTENCE_BACKEND + " - defaulting to file-based persistence");
211             }
212             log.info("Registering file-based persistence system");
213             pico.registerComponentImplementation(ExecutionHistory.class,FileStoreExecutionHistory.class);
214         } 
215         pico.registerComponentImplementation(IdGen.class,GloballyUniqueIdGen.class);        
216     }
217     
218     /***
219      * key to look in config under for the authorityid to add provided
220      * applications to (optional, defaults to 'org.astrogrid.localhost')
221      * 
222      * @see #registerDefaultVOProvider(MutablePicoContainer, Config)
223      */
224     public final static String AUTHORITY_NAME = "cea.application.authorityid";
225 
226     /*** register the standard VO Provider - the component that generates the registry entry.
227      *  standard provider operates by constructing VODecription from applicationDescriptions in library
228      */
229     protected static final void registerDefaultVOProvider(MutablePicoContainer pico) {
230         log.info("Registering default vo provider - note that this is now the MetadataService");
231         registerVOProvider(pico, DefaultMetadataService.class);        
232   
233     }    
234     /***
235     * @param pico
236     */
237    protected static void registerVOProvider(MutablePicoContainer pico,
238                                             final Class MetadataServ) {
239      // This method can get called twice for some variants, so allow
240      // overriding of the registrations.
241      pico.unregisterComponent(MetadataService.class);
242      pico.unregisterComponent(AppAuthorityIDResolver.class);
243      pico.registerComponentImplementation(MetadataService.class,
244                                           MetadataServ);
245      pico.registerComponentImplementation(AppAuthorityIDResolver.class, 
246                                           DefaultAppAuthorityIDResolver.class); 
247    }
248 
249    /*** register optional component that uploads vodescription to registry on startup.  */
250     protected static final void registerDefaultRegistryUploader(MutablePicoContainer pico) {
251         log.info("Registering default registry uploader");
252         pico.registerComponentImplementation(RegistryUploader.class);    
253         pico.registerComponentImplementation(RegistryAdminLocator.class,
254                                              RegistryAdminLocatorImpl.class);
255     }
256     
257     /*** register the {@link CompositeApplicationDescriptionLibrary} - this will assemble other implementations of {@link ApplicationDescriptionLibrary}
258      *  registered in the container into a single unified library - allowing multiple 
259      * providers to be merged.
260      * <p/>
261      * For this to work, other app description libs must be registered with pico under their own classname - <b>not</b>
262      * the interface {@link ApplicationDescriptionLIbrary}
263      * @param pico
264      */
265     protected static final void registerCompositeApplicationDescriptionLibrary(final MutablePicoContainer pico) {
266         pico.registerComponentImplementation(ApplicationDescriptionLibrary.class,CompositeApplicationDescriptionLibrary.class);
267         // on startup (i.e. after everythinig has been registered, this throwaway component will add all other application description libraries to this one
268         pico.registerComponentInstance(new Startable() {
269             public void start() {
270                 logger.info("Registering application description libraries in composite");
271                 CompositeApplicationDescriptionLibrary uberLib = (CompositeApplicationDescriptionLibrary)pico.getComponentInstanceOfType(CompositeApplicationDescriptionLibrary.class);
272                 for (Iterator i = pico.getComponentAdaptersOfType(ApplicationDescriptionLibrary.class).iterator(); i.hasNext(); ) {
273                     ComponentAdapter ca = (ComponentAdapter)i.next();
274                     ApplicationDescriptionLibrary lib = (ApplicationDescriptionLibrary)ca.getComponentInstance(pico);
275                     // watch out for self.
276                     if (lib != uberLib) {
277                         uberLib.addLibrary(lib);
278                     }
279                 }
280             }
281 
282             public void stop() {
283             }
284         });        
285     }
286     /*** register an {@link ApplicationDescriptionLibrary} that will assemble all {@link ApplicationDescription} components registered with the container 
287      *  - this allows applicatonDescriptions to be setup and configured individually at the picocontainer level.
288      * @author Noel Winstanley nw@jb.man.ac.uk 05-Jul-2004
289      *
290      */
291    public static void registerContainerApplicationDescriptionLibrary(final MutablePicoContainer pico) {
292        pico.registerComponentImplementation(BaseApplicationDescriptionLibrary.class);
293        // register a throwaway component that adds all applicationDescriptions in the container into the library on container startup.
294        pico.registerComponentInstance(new Startable() {
295 
296         public void start() {
297             BaseApplicationDescriptionLibrary lib = (BaseApplicationDescriptionLibrary)pico.getComponentInstanceOfType(BaseApplicationDescriptionLibrary.class);
298             for (Iterator i = pico.getComponentAdaptersOfType(ApplicationDescription.class).iterator(); i.hasNext();) {
299                 ComponentAdapter ca = (ComponentAdapter)i.next();
300                 ApplicationDescription appDesc = (ApplicationDescription)ca.getComponentInstance(pico);
301                 lib.addApplicationDescription(appDesc);
302             }
303         }
304         public void stop() {
305         }
306        }); 
307     }
308 
309    public void registerEnvironmentRetriever(final MutablePicoContainer pico)
310    {
311       logger.info("registering Default Environment Retriever");
312       pico.registerComponentImplementation(ApplicationEnvironmentRetriver.class, DefaultApplicationEnvironmentRetriever.class);
313    }
314    
315 
316 }
317 
318 
319 /* 
320 $Log: EmptyCEAComponentManager.java,v $
321 Revision 1.20  2006/03/17 17:50:58  clq2
322 gtr_1489_cea correted version
323 
324 Revision 1.18  2006/03/07 21:45:26  clq2
325 gtr_1489_cea
326 
327 Revision 1.14.20.7  2006/01/31 21:39:07  gtr
328 Refactored. I have altered the configuration code slightly so that the JUnit tests can impose a Configuration instance to configure the tests. I have also fixed up almost all the bad tests for commandline and http.
329 
330 Revision 1.14.20.6  2006/01/26 13:19:04  gtr
331 Refactored.
332 
333 Revision 1.14.20.5  2006/01/26 11:05:19  gtr
334 The new configuration service is used instead of the separate configuration interfaces.
335 
336 Revision 1.14.20.4  2006/01/25 17:04:32  gtr
337 Refactored: the configuration is now a fixed structure based at the configurable location cea.base.dir.
338 
339 Revision 1.14.20.3  2005/12/22 13:57:56  gtr
340 registerVOProvider() can now be called more than once; it deregisters and reregisters components as necessary,
341 
342 Revision 1.14.20.2  2005/12/19 18:12:30  gtr
343 Refactored: changes in support of the fix for 1492.
344 
345 Revision 1.14.20.1  2005/12/18 14:48:24  gtr
346 Refactored to allow the component managers to pass their unit tests and the fingerprint JSP to work. See BZ1492.
347 
348 Revision 1.14  2005/08/10 14:45:37  clq2
349 cea_pah_1317
350 
351 Revision 1.13.6.1  2005/07/21 15:10:22  pah
352 changes to acommodate contol component, and starting to change some of the static methods to dynamic
353 
354 Revision 1.13  2005/07/05 08:26:57  clq2
355 paul's 559b and 559c for wo/apps and jes
356 
357 Revision 1.12.42.2  2005/06/14 09:49:32  pah
358 make the http cec only register itself as a ceaservice - do not try to reregister any cea applications that it finds
359 
360 Revision 1.12.42.1  2005/06/09 08:47:32  pah
361 result of merging branch cea_pah_559b into HEAD
362 
363 Revision 1.12.28.2  2005/06/03 16:01:48  pah
364 first try at getting commandline execution log bz#1058
365 
366 Revision 1.12.28.1  2005/06/02 14:57:28  pah
367 merge the ProvidesVODescription interface into the MetadataService interface
368 
369 Revision 1.12  2005/03/13 07:13:39  clq2
370 merging jes-nww-686 common-nww-686 workflow-nww-996 scripting-nww-995 cea-nww-994
371 
372 Revision 1.11.26.1  2005/03/11 11:21:13  nw
373 adjusted to fit with pico 1.1
374 
375 Revision 1.11  2004/11/27 13:20:03  pah
376 result of merge of pah_cea_bz561 branch
377 
378 Revision 1.10  2004/11/05 13:07:04  nw
379 added option to use memory-backed execution history.
380 
381 Revision 1.9  2004/09/22 10:52:50  pah
382 getting rid of some unused imports
383 
384 Revision 1.8  2004/09/17 01:20:22  nw
385 added lifecycle listener and threadpool
386 
387 Revision 1.7.20.1  2004/09/14 13:45:38  nw
388 made thread-pooled executor the default.
389 
390 Revision 1.7  2004/08/27 10:56:38  nw
391 removed container-inspecting applicationDescriptionLibrary from default setup - cea-commandline doesn't like it.
392 
393 Revision 1.6  2004/08/11 16:50:56  nw
394 added in default application description libraries.
395 
396 Revision 1.5  2004/07/26 12:07:38  nw
397 renamed indirect package to protocol,
398 renamed classes and methods within protocol package
399 javadocs
400 
401 Revision 1.4  2004/07/23 13:21:21  nw
402 Javadocs
403 
404 Revision 1.3  2004/07/05 18:45:09  nw
405 added helper method to assemble lib from registered descriptions
406 
407 Revision 1.2  2004/07/01 11:16:22  nw
408 merged in branch
409 nww-itn06-componentization
410 
411 Revision 1.1.2.3  2004/07/01 01:42:46  nw
412 final version, before merge
413 
414 Revision 1.1.2.2  2004/06/17 09:21:23  nw
415 finished all major functionality additions to core
416 
417 Revision 1.1.2.1  2004/06/14 08:56:58  nw
418 factored applications into sub-projects,
419 got packaging of wars to work again
420 
421 Revision 1.1.2.2  2004/05/28 10:23:11  nw
422 checked in early, broken version - but it builds and tests (fail)
423 
424 Revision 1.1.2.1  2004/05/21 12:00:22  nw
425 merged in latest changes from HEAD. start of refactoring effort
426  
427 */