View Javadoc

1   /*$Id: EmptyCEAComponentManager.java,v 1.11 2004/11/27 13:20:03 pah 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.apache.commons.logging.Log;
14  import org.apache.commons.logging.LogFactory;
15  
16  import org.astrogrid.applications.description.ApplicationDescription;
17  import org.astrogrid.applications.description.ApplicationDescriptionLibrary;
18  import org.astrogrid.applications.description.BaseApplicationDescriptionLibrary;
19  import org.astrogrid.applications.description.CompositeApplicationDescriptionLibrary;
20  import org.astrogrid.applications.description.base.ApplicationDescriptionEnvironment;
21  import org.astrogrid.applications.description.registry.RegistryAdminLocator;
22  import org.astrogrid.applications.description.registry.RegistryEntryBuilder;
23  import org.astrogrid.applications.description.registry.RegistryUploader;
24  import org.astrogrid.applications.manager.CeaThreadPool;
25  import org.astrogrid.applications.manager.DefaultMetadataService;
26  import org.astrogrid.applications.manager.DefaultQueryService;
27  import org.astrogrid.applications.manager.ExecutionController;
28  import org.astrogrid.applications.manager.MetadataService;
29  import org.astrogrid.applications.manager.QueryService;
30  import org.astrogrid.applications.manager.ThreadPoolExecutionController;
31  import org.astrogrid.applications.manager.idgen.GloballyUniqueIdGen;
32  import org.astrogrid.applications.manager.idgen.IdGen;
33  import org.astrogrid.applications.manager.persist.ExecutionHistory;
34  import org.astrogrid.applications.manager.persist.FileStoreExecutionHistory;
35  import org.astrogrid.applications.manager.persist.InMemoryExecutionHistory;
36  import org.astrogrid.applications.parameter.protocol.AgslProtocol;
37  import org.astrogrid.applications.parameter.protocol.DefaultProtocolLibrary;
38  import org.astrogrid.applications.parameter.protocol.FileProtocol;
39  import org.astrogrid.applications.parameter.protocol.FtpProtocol;
40  import org.astrogrid.applications.parameter.protocol.HttpProtocol;
41  import org.astrogrid.applications.parameter.protocol.IvornProtocol;
42  import org.astrogrid.applications.parameter.protocol.Protocol;
43  import org.astrogrid.applications.parameter.protocol.ProtocolLibrary;
44  import org.astrogrid.component.EmptyComponentManager;
45  import org.astrogrid.config.Config;
46  import org.astrogrid.registry.client.RegistryDelegateFactory;
47  import org.astrogrid.registry.client.admin.RegistryAdminService;
48  
49  import org.picocontainer.ComponentAdapter;
50  import org.picocontainer.MutablePicoContainer;
51  import org.picocontainer.Startable;
52  
53  import EDU.oswego.cs.dl.util.concurrent.PooledExecutor;
54  
55  import java.io.File;
56  import java.net.MalformedURLException;
57  import java.net.URL;
58  import java.util.Iterator;
59  
60  /*** empty implementation of {@link org.astrogrid.applications.component.CEAComponentManager}
61   * provides implementations of the accessor methods, but no componets are registered with the container. (this should be done in subclasses).
62   * <p>
63   * Registers a single validity-checking component, that depends on all the publicaly-accessible compoennts (i.e.QueryService, MetaData, etc).
64   * As picontainer checks that all dependencies can be resolved on startup, this component enforces the requirement that all component managers will have 
65   * instances of the publically-accesible components. How thiese components are built up and registered is left free to the subclasses.
66   * <p/>
67   * This class also provides a set of static helper method that register 'clusters' of commonly-used components. These
68   * can be called from implementations of component manager to quickly set up the basic parts of the system
69   * @author Noel Winstanley nw@jb.man.ac.uk 04-May-2004
70   * @see org.astrogrid.applications.component.JavaClassCEAComponentManager for example of how to assemble a server using this class.
71   *
72   */
73  public abstract class EmptyCEAComponentManager extends EmptyComponentManager implements CEAComponentManager{
74      /***
75       * Commons Logger for this class
76       */
77      private static final Log logger = LogFactory
78              .getLog(EmptyCEAComponentManager.class);
79  
80      /*** Construct a new EmptyCEAComponentManager
81       * 
82       */
83      public EmptyCEAComponentManager() {
84          super();
85          pico.registerComponentImplementation(VerifyRequiredComponents.class);
86      }
87  
88      /***
89       * @see org.astrogrid.applications.component.CEAComponentManager#getController()
90       */
91      public final ExecutionController getExecutionController() {
92          return (ExecutionController)this.pico.getComponentInstanceOfType(ExecutionController.class);
93      }
94  
95      /***
96       * @see org.astrogrid.applications.component.CEAComponentManager#getMetaData()
97       */
98      public final MetadataService getMetadataService() {
99          return (MetadataService)this.pico.getComponentInstanceOfType(MetadataService.class);
100     }
101     
102     public final QueryService getQueryService() {
103         return (QueryService)this.pico.getComponentInstanceOfType(QueryService.class);
104     }
105     
106     public final RegistryUploader getRegistryUploaderService() {
107        return (RegistryUploader)this.pico.getComponentInstance(RegistryUploader.class);
108     }
109     /*** dummy component that ensures required componets are registered with the container
110      * not interesting, but needs to be publc so that picocontainer can instantiate it */ 
111     public static final class VerifyRequiredComponents {
112         /***
113          * Commons Logger for this class
114          */
115         private static final Log logger = LogFactory
116                 .getLog(VerifyRequiredComponents.class);
117 
118         public VerifyRequiredComponents(ExecutionController ignored,MetadataService ignoredToo, QueryService dontcare) {
119         }
120     }
121 
122  
123 
124     // convenience methods for regostering commnly used sets of components
125     /*** register the default top-level services core of CEA 
126      * registers default implementations of {@link QueryService}, {@link MetadataService} and {@link ExecutionController},
127      * plus the {@link ApplicationDescriptionEnvironment}
128      * also registers a composite application description library, and a container application description library.
129      * @see #registerCompositeApplicationDescriptionLibrary(MutablePicoContainer)
130      * @see #registerContainerApplicationDescriptionLibrary(MutablePicoContainer)
131      * */
132     protected static final void registerDefaultServices(MutablePicoContainer pico) {
133         log.info("Registering default services");
134         pico.registerComponentImplementation(ApplicationDescriptionEnvironment.class,ApplicationDescriptionEnvironment.class);
135         // trying something a little more intelligent.. pico.registerComponentImplementation(ExecutionController.class, DefaultExecutionController.class);
136         pico.registerComponentImplementation(ExecutionController.class,ThreadPoolExecutionController.class);
137         pico.registerComponentImplementation(PooledExecutor.class,CeaThreadPool.class);
138         pico.registerComponentImplementation(MetadataService.class, DefaultMetadataService.class);     
139         pico.registerComponentImplementation(QueryService.class,DefaultQueryService.class);   
140        registerCompositeApplicationDescriptionLibrary(pico);
141        // not added by default - stiches up cea-commandline.
142         //registerContainerApplicationDescriptionLibrary(pico);
143         }
144     
145     /*** registers the default implementaiton of the indirection protocol library 
146      * NB: does not register any protocols with the library. These must be added to the container separately
147      * any protocols added to the container  wil be detected and added to the library on startup
148      * @see #registerStandardIndirectionProtocols(MutablePicoContainer)
149      * @see #registerAstrogridIndirectionProtocols(MutablePicoContainer)*/
150     protected static final void registerProtocolLibrary(final MutablePicoContainer pico) {
151         log.info("Registering default indirection protocol library");
152         pico.registerComponentImplementation(ProtocolLibrary.class,DefaultProtocolLibrary.class);
153         // on startup (i.e. after everythinig has been registered, this throwaway component will add all known indirection protocols to the library).
154         pico.registerComponentInstance(new Startable() {
155             public void start() {
156                 DefaultProtocolLibrary lib = (DefaultProtocolLibrary) pico.getComponentInstanceOfType(DefaultProtocolLibrary.class);
157                 for (Iterator i = pico.getComponentAdaptersOfType(Protocol.class).iterator(); i.hasNext(); ) {
158                     ComponentAdapter ca = (ComponentAdapter)i.next();
159                     Protocol p = (Protocol)ca.getComponentInstance();
160                     lib.addProtocol(p);
161                 }
162             }
163 
164             public void stop() {
165             }
166         });
167     }
168     
169     /*** registers the standard indirection protocols - http:, ftp:, file: */
170     protected static final void registerStandardIndirectionProtocols(MutablePicoContainer pico) {
171         pico.registerComponentImplementation(HttpProtocol.class);
172         pico.registerComponentImplementation(FtpProtocol.class);
173         pico.registerComponentImplementation(FileProtocol.class);
174     }
175     
176     /*** registers the astorgird-specific protocols - ivo: and agsl:*/
177     protected static final void registerAstrogridIndirectionProtocols(MutablePicoContainer pico) {
178         pico.registerComponentImplementation(AgslProtocol.class);
179         pico.registerComponentImplementation(IvornProtocol.class);
180     }
181     
182     /*** key used to determing from config where to store execution history files
183      * @see #registerDefaultPersistence(MutablePicoContainer, Config) */
184     public static final String FILESTORE_BASEDIR = "cea.filestore.basedir";
185     
186     /*** key used to determine which persistence back-end to use -
187      * <br> valid values - <tt>file</tt>, <tt>memory</tt>
188      * <br>optional- defaults to <tt>file</tt>*/
189     public static final String PERSISTENCE_BACKEND = "cea.persistence.backend";
190     
191     /*** register the standard persistence system - globally unique id generation, and file-based exection history 
192      * configured by {@link #FILESTORE_BASEDIR}
193      * */
194     protected static final void registerDefaultPersistence(MutablePicoContainer pico, final Config config) {
195 
196         String backend = System.getProperty(PERSISTENCE_BACKEND,"file").toLowerCase().trim();
197         if (backend.equals("memory")) {
198             log.warn("Only using memory-based persistence system - all history will be lost on restart");
199             pico.registerComponentImplementation(ExecutionHistory.class,InMemoryExecutionHistory.class);
200         } else {
201             if (! backend.equals("file")) {
202                 log.error("Unrecognized value '" + backend + "' for key " +  PERSISTENCE_BACKEND + " - defaulting to file-based persistence");
203             }
204             log.info("Registering file-based persistence system");
205             pico.registerComponentImplementation(ExecutionHistory.class,FileStoreExecutionHistory.class);
206             pico.registerComponentInstance(FileStoreExecutionHistory.StoreDir.class, new FileStoreExecutionHistory.StoreDir(){
207                 private final File dir= new File(config.getString(FILESTORE_BASEDIR,System.getProperty("java.io.tmpdir")));
208                 public File getDir() {
209                     return dir;
210                 }
211             });
212         } 
213         pico.registerComponentImplementation(IdGen.class,GloballyUniqueIdGen.class);        
214     }
215 
216     
217     /*** key to query config for the url of the registry template to use (optional, default='/CEARegistryTemplate.xml' on classpath) 
218      * @see #registerDefaultVOProvider(MutablePicoContainer, Config)*/
219     public static final String REGISTRY_TEMPLATE_URL  ="cea.registry.template.url";
220     /*** key to query config for the url of this services endpoint (optional, recommended, otherwise makes a best guess)
221      * @see #registerDefaultVOProvider(MutablePicoContainer, Config)*/
222     public static final String SERVICE_ENDPOINT_URL = "cea.service.endpoint.url";
223     
224     /***
225      * key to look in config under for the authorityid to add provided
226      * applications to (optional, defaults to 'org.astrogrid.localhost')
227      * 
228      * @see #registerDefaultVOProvider(MutablePicoContainer, Config)
229      */
230     public final static String AUTHORITY_NAME = "cea.application.authorityid";
231 
232     /*** register the standard VO Provider - the component that generates the registry entry.
233      *  standard provider operates by constructing VODecription from applicationDescriptions in library
234      * @param pico
235      * @param config
236      * @see #REGISTRY_TEMPLATE_URL
237      * @see #SERVICE_ENDPOINT_URL
238      */
239     protected static final void registerDefaultVOProvider(MutablePicoContainer pico, final Config config) {
240         log.info("Registering default vo provider");
241         try {
242         pico.registerComponentImplementation(ProvidesVODescription.class, RegistryEntryBuilder.class);
243         pico.registerComponentInstance(RegistryEntryBuilder.URLs.class, new RegistryEntryBuilder.URLs() {
244             private final URL registryTemplate = config.getUrl(REGISTRY_TEMPLATE_URL,EmptyCEAComponentManager.class.getResource("/CEARegistryTemplate.xml"));         
245             private final URL serviceEndpoint = config.getUrl(SERVICE_ENDPOINT_URL,new URL("http://localhost:8080/astrogrid-cea-server/services/CommonExecutionConnectorService"));
246             public URL getRegistryTemplate() {
247                 return registryTemplate;
248             }
249             public URL getServiceEndpoint() {
250                 return serviceEndpoint;
251             }
252         });
253         pico.registerComponentInstance(new BaseApplicationDescriptionLibrary.AppAuthorityIDResolver() {
254            protected final String auth = config.getString(AUTHORITY_NAME, "org.astrogrid.localhost");
255 
256            public String getAuthorityID() {
257                return auth;
258            }
259        });
260 
261         } catch (MalformedURLException e) {
262             // unlikely this will happen
263             log.fatal("Could could not register the vo provider " + e);
264         }        
265   
266     }    
267     /*** register optional component that uploads vodescription to registry on startup.  */
268     protected static final void registerDefaultRegistryUploader(MutablePicoContainer pico) {
269         log.info("Registering default registry uploader");
270         pico.registerComponentImplementation(RegistryUploader.class);    
271         pico.registerComponentInstance(RegistryAdminLocator.class,new RegistryAdminLocator() {
272 
273             public RegistryAdminService getClient() {                
274                 return RegistryDelegateFactory.createAdmin();
275             }
276         });        
277     }
278     
279     /*** register the {@link CompositeApplicationDescriptionLibrary} - this will assemble other implementations of {@link ApplicationDescriptionLibrary}
280      *  registered in the container into a single unified library - allowing multiple 
281      * providers to be merged.
282      * <p/>
283      * For this to work, other app description libs must be registered with pico under their own classname - <b>not</b>
284      * the interface {@link ApplicationDescriptionLIbrary}
285      * @param pico
286      */
287     protected static final void registerCompositeApplicationDescriptionLibrary(final MutablePicoContainer pico) {
288         pico.registerComponentImplementation(ApplicationDescriptionLibrary.class,CompositeApplicationDescriptionLibrary.class);
289         // on startup (i.e. after everythinig has been registered, this throwaway component will add all other application description libraries to this one
290         pico.registerComponentInstance(new Startable() {
291             public void start() {
292                 logger.info("Registering application description libraries in composite");
293                 CompositeApplicationDescriptionLibrary uberLib = (CompositeApplicationDescriptionLibrary)pico.getComponentInstanceOfType(CompositeApplicationDescriptionLibrary.class);
294                 for (Iterator i = pico.getComponentAdaptersOfType(ApplicationDescriptionLibrary.class).iterator(); i.hasNext(); ) {
295                     ComponentAdapter ca = (ComponentAdapter)i.next();
296                     ApplicationDescriptionLibrary lib = (ApplicationDescriptionLibrary)ca.getComponentInstance();
297                     // watch out for self.
298                     if (lib != uberLib) {
299                         uberLib.addLibrary(lib);
300                     }
301                 }
302             }
303 
304             public void stop() {
305             }
306         });        
307     }
308     /*** register an {@link ApplicationDescriptionLibrary} that will assemble all {@link ApplicationDescription} components registered with the container 
309      *  - this allows applicatonDescriptions to be setup and configured individually at the picocontainer level.
310      * @author Noel Winstanley nw@jb.man.ac.uk 05-Jul-2004
311      *
312      */
313    public static void registerContainerApplicationDescriptionLibrary(final MutablePicoContainer pico) {
314        pico.registerComponentImplementation(BaseApplicationDescriptionLibrary.class);
315        // register a throwaway component that adds all applicationDescriptions in the container into the library on container startup.
316        pico.registerComponentInstance(new Startable() {
317 
318         public void start() {
319             BaseApplicationDescriptionLibrary lib = (BaseApplicationDescriptionLibrary)pico.getComponentInstanceOfType(BaseApplicationDescriptionLibrary.class);
320             for (Iterator i = pico.getComponentAdaptersOfType(ApplicationDescription.class).iterator(); i.hasNext();) {
321                 ComponentAdapter ca = (ComponentAdapter)i.next();
322                 ApplicationDescription appDesc = (ApplicationDescription)ca.getComponentInstance();
323                 lib.addApplicationDescription(appDesc);
324             }
325         }
326         public void stop() {
327         }
328        }); 
329     }
330 
331 }
332 
333 
334 /* 
335 $Log: EmptyCEAComponentManager.java,v $
336 Revision 1.11  2004/11/27 13:20:03  pah
337 result of merge of pah_cea_bz561 branch
338 
339 Revision 1.10  2004/11/05 13:07:04  nw
340 added option to use memory-backed execution history.
341 
342 Revision 1.9  2004/09/22 10:52:50  pah
343 getting rid of some unused imports
344 
345 Revision 1.8  2004/09/17 01:20:22  nw
346 added lifecycle listener and threadpool
347 
348 Revision 1.7.20.1  2004/09/14 13:45:38  nw
349 made thread-pooled executor the default.
350 
351 Revision 1.7  2004/08/27 10:56:38  nw
352 removed container-inspecting applicationDescriptionLibrary from default setup - cea-commandline doesn't like it.
353 
354 Revision 1.6  2004/08/11 16:50:56  nw
355 added in default application description libraries.
356 
357 Revision 1.5  2004/07/26 12:07:38  nw
358 renamed indirect package to protocol,
359 renamed classes and methods within protocol package
360 javadocs
361 
362 Revision 1.4  2004/07/23 13:21:21  nw
363 Javadocs
364 
365 Revision 1.3  2004/07/05 18:45:09  nw
366 added helper method to assemble lib from registered descriptions
367 
368 Revision 1.2  2004/07/01 11:16:22  nw
369 merged in branch
370 nww-itn06-componentization
371 
372 Revision 1.1.2.3  2004/07/01 01:42:46  nw
373 final version, before merge
374 
375 Revision 1.1.2.2  2004/06/17 09:21:23  nw
376 finished all major functionality additions to core
377 
378 Revision 1.1.2.1  2004/06/14 08:56:58  nw
379 factored applications into sub-projects,
380 got packaging of wars to work again
381 
382 Revision 1.1.2.2  2004/05/28 10:23:11  nw
383 checked in early, broken version - but it builds and tests (fail)
384 
385 Revision 1.1.2.1  2004/05/21 12:00:22  nw
386 merged in latest changes from HEAD. start of refactoring effort
387  
388 */