View Javadoc

1   /*
2    * $Id: RegistryEntryBuilder.java,v 1.5 2004/11/27 13:20:03 pah Exp $
3    * 
4    * Created on 22-Mar-2004 by Paul Harrison (pah@jb.man.ac.uk)
5    *
6    * Copyright 2004 AstroGrid. All rights reserved.
7    *
8    * This software is published under the terms of the AstroGrid 
9    * Software License version 1.2, a copy of which has been included 
10   * with this distribution in the LICENSE.txt file.  
11   *
12   */
13  
14  package org.astrogrid.applications.description.registry;
15  
16  import org.astrogrid.applications.beans.v1.ApplicationBase;
17  import org.astrogrid.applications.beans.v1.ApplicationList;
18  import org.astrogrid.applications.component.ProvidesVODescription;
19  import org.astrogrid.applications.description.ApplicationDescription;
20  import org.astrogrid.applications.description.ApplicationDescriptionLibrary;
21  import org.astrogrid.applications.description.DescriptionUtils;
22  import org.astrogrid.applications.description.exception.ApplicationDescriptionNotFoundException;
23  import org.astrogrid.component.descriptor.ComponentDescriptor;
24  import org.astrogrid.registry.beans.cea.ApplicationDefinition;
25  import org.astrogrid.registry.beans.cea.CeaApplicationType;
26  import org.astrogrid.registry.beans.cea.CeaServiceType;
27  import org.astrogrid.registry.beans.cea.ManagedApplications;
28  import org.astrogrid.registry.beans.cea.Parameters;
29  import org.astrogrid.registry.beans.resource.AccessURLType;
30  import org.astrogrid.registry.beans.resource.VODescription;
31  import org.astrogrid.registry.beans.resource.types.AccessURLTypeUseType;
32  
33  import org.apache.axis.utils.XMLUtils;
34  import org.apache.commons.logging.Log;
35  import org.apache.commons.logging.LogFactory;
36  import org.exolab.castor.xml.CastorException;
37  import org.exolab.castor.xml.MarshalException;
38  import org.exolab.castor.xml.Marshaller;
39  import org.exolab.castor.xml.Unmarshaller;
40  import org.exolab.castor.xml.ValidationException;
41  import org.w3c.dom.Document;
42  import org.xml.sax.InputSource;
43  
44  import java.io.IOException;
45  import java.io.InputStreamReader;
46  import java.io.StringReader;
47  import java.io.StringWriter;
48  import java.net.URL;
49  
50  import junit.framework.Test;
51  import junit.framework.TestCase;
52  
53  /***
54   * Creates a VODescription  based on the contents of an ApplicationDescriptionLibrary.
55   * 
56   * Requires a template file of the VODescription that contains the basic CeaApplication and CeaService entries to fill in.
57   * @author Noel Winstanley
58   * @author Paul Harrison (pah@jb.man.ac.uk) 22-Mar-2004
59   * @version $Name:  $
60   * @since iteration5
61   * @see org.astrogrid.applications.component.ProvidesVODescription
62   * @todo this could do with a bit of a refactor - its quite messy still. Probably best to wait until the registry schema changes anyway..
63   */
64  public class RegistryEntryBuilder implements ProvidesVODescription , ComponentDescriptor{
65      /***
66       * Commons Logger for this class
67       */
68      private static final Log logger = LogFactory.getLog(RegistryEntryBuilder.class);
69     /*** configuration settings */
70     private URLs urls;
71  
72    /*** library to generate description for */
73     private final ApplicationDescriptionLibrary lib;
74  private VODescription template;
75  private String serverID;
76  private String authorityID;
77  
78      /*** Configuration interface - specifies location of resources required by {@link RegistryEntryBuilder}
79       * @author Noel Winstanley nw@jb.man.ac.uk 26-Jul-2004
80       *
81       */
82      public interface URLs {
83          /*** url of the template registry entry to use */
84          URL getRegistryTemplate();
85          /*** url of the endpoint of the current cea service */
86          URL getServiceEndpoint();
87      }
88  
89  
90      /***
91       *  Construct a new RegistryEntryBuilder
92       * @param lib the library of descriptions to build a registry entry for
93       * @param urls configuration urls
94       */
95     public RegistryEntryBuilder(ApplicationDescriptionLibrary lib, URLs urls) {
96        this.lib = lib;
97        this.urls = urls;
98        try {
99           //FIXME need to read the template to get hold of the AuthorityID and the serverID to have those set early
100          template = makeTemplate();
101       }
102       catch (Exception e) {
103          logger.error("error with template", e);
104       }
105    }
106 
107    /***
108     * Create the registry entry....
109     * @return a vodescription.
110     */
111    public VODescription makeEntry() throws MarshalException, ValidationException, IOException, ApplicationDescriptionNotFoundException {
112       VODescription vodesc = new VODescription();
113       CeaApplicationType applicationTemplate =
114          (CeaApplicationType)template.getResource(0);
115       CeaServiceType serviceTemplate = (CeaServiceType)template.getResource(1);
116 
117       CeaServiceType service = cloneTemplate(serviceTemplate);
118       //set the service idetifier just in case this has been redefined from the UI
119       service.getIdentifier().setAuthorityID(getAuthorityID());
120       service.getIdentifier().setResourceKey(serverID);
121       ManagedApplications managedApplications = new ManagedApplications();
122       service.setManagedApplications(managedApplications);
123       ApplicationList applist = makeApplist(lib);
124       //add each of the application definitions.
125       for (int i = 0; i < applist.getApplicationDefnCount(); i++) {
126 
127          ApplicationBase theapp = applist.getApplicationDefn(i);
128          ApplicationDescription theAppDesc  = lib.getDescription(theapp.getName());
129          
130          if (theapp.getName() != null) { //TODO this test is only here to get round a bug in the container, where a null application seems to be instantiated.
131             CeaApplicationType appentry = makeApplicationEntry(
132                     applicationTemplate, theapp);
133             appentry.getSummary().setDescription(theAppDesc.getAppDescription());
134             appentry.getSummary().setReferenceURL(theAppDesc.getReferenceURL());
135             appentry.setTitle(theAppDesc.getUIName());
136             appentry.setShortName(theAppDesc.getUIName());//this is probably not appropriate
137             vodesc.addResource(appentry);
138             //add this application to the list of managed applications.
139             managedApplications.addApplicationReference(appentry
140                     .getIdentifier());
141         }
142 
143       }
144       //add the service description
145       AccessURLType accessurl = new AccessURLType();
146       accessurl.setContent(urls.getServiceEndpoint().toString()) ;     
147       accessurl.setUse(AccessURLTypeUseType.BASE);
148       service.getInterface().setAccessURL(accessurl);
149       vodesc.addResource(service);
150       return vodesc;
151 
152    }
153 
154    /***
155     * Create and populate a new application entry. 
156     * @param template The template on which the general application information in the entry is based.
157     * @param app Specific application information to be added to the entry.
158     * @return
159     * @throws MarshalException
160     * @throws ValidationException
161     */
162    private CeaApplicationType makeApplicationEntry(
163       CeaApplicationType template,
164       ApplicationBase app)
165       throws MarshalException, ValidationException {
166 
167       CeaApplicationType entry = cloneTemplate(template);
168       entry.getIdentifier().setResourceKey(stripAuthorityFragment(app.getName()));
169       entry.getIdentifier().setAuthorityID(getAuthorityFragment(app.getName()));
170       //TODO need to get the long description in here too
171       ApplicationDefinition applicationDefinition = new ApplicationDefinition();
172       // set the interfaces - easy it is the same type...     
173       applicationDefinition.setInterfaces(app.getInterfaces());
174       
175       //parameters not quite so nice REFACTORME - perhaps the schema could be refactored....
176       Parameters regpar = new Parameters();
177       regpar.setParameterDefinition(app.getParameters().getParameter());
178       applicationDefinition.setParameters(regpar);
179       
180 
181       entry.setApplicationDefinition(applicationDefinition);
182       return entry;
183    }
184    
185    /*** strips authority fragment, if present */
186    private String stripAuthorityFragment(String s) {
187        if (s.indexOf('/') != -1) {
188            return s.substring(s.indexOf('/') + 1);
189        } else {
190            return s;
191        }
192    }
193    private String getAuthorityFragment(String s)
194    {
195       if (s.indexOf('/') != -1) {
196          return s.substring(0, s.indexOf('/'));
197      } else {
198          return null;
199      }
200 
201    }
202 
203    /***
204     * Create a clone of the given object. Does this by using the castor marshalling/unmarshalling on the object.
205     * @param app
206     * @return
207     * @throws MarshalException
208     * @throws ValidationException
209     */
210    private CeaApplicationType cloneTemplate(CeaApplicationType app)
211       throws MarshalException, ValidationException {
212       StringWriter sw = new StringWriter();
213       CeaApplicationType newapp = null;
214       app.marshal(sw);
215       StringReader sr = new StringReader(sw.toString());
216       InputSource is = new InputSource(sr);
217       Unmarshaller um = new Unmarshaller(CeaApplicationType.class);
218       newapp = (CeaApplicationType)um.unmarshal(is);
219 
220       return newapp;
221 
222    }
223 
224    /***
225     *  Create a clone of the given object. Does this by using the castor marshalling/unmarshalling on the object.
226     * @param serv
227     * @return
228     * @throws MarshalException
229     * @throws ValidationException
230     */
231    private CeaServiceType cloneTemplate(CeaServiceType serv)
232       throws MarshalException, ValidationException {
233       CeaServiceType newserv = null;
234       StringWriter sw = new StringWriter();
235       serv.marshal(sw);
236       StringReader sr = new StringReader(sw.toString());
237       InputSource is = new InputSource(sr);
238       Unmarshaller um = new Unmarshaller(CeaServiceType.class);
239       newserv = (CeaServiceType)um.unmarshal(is);
240 
241       return newserv;
242    }
243 
244    /***
245     * Make an ApplicationList from a full configuration. This is a deep copy - new instances of the ApplicationBase objecst are created.
246     * @param clecConfig a configuration for a command line execution controller
247     * @return
248     * @TODO might be better to refactor the original schema so that there was a base type for the common execution contoller configs...
249     */
250    private ApplicationList makeApplist(ApplicationDescriptionLibrary lib) throws ApplicationDescriptionNotFoundException { 
251       ApplicationList result = new ApplicationList();
252       String names[] = lib.getApplicationNames();
253       for (int i = 0; i < names.length; i++) {
254           ApplicationDescription descr = lib.getDescription(names[i]);
255           ApplicationBase base = DescriptionUtils.applicationDescription2ApplicationBase(descr);
256          result.addApplicationDefn(base);
257       }
258       return result;
259    }
260    
261  
262 
263 /***
264     * Create a clone of an ApplicationBase object. This is done via the castor marshalling framework. In most cases this will be a downcast copy.
265     * @param in This can (and in most cases will) be one of the derived classes from ApplicationBase
266     * @return
267     */
268 /* not used - just left in for reference
269    private ApplicationBase cloneApplication(ApplicationBase in) throws IOException, MarshalException, ValidationException
270    {
271       ApplicationBase result = null;
272 // TODO write a castor wiki page about this....      
273       StringWriter sw = new StringWriter();
274       Marshaller mar = new Marshaller(sw);
275       mar.setMarshalExtendedType(false);
276       mar.setSuppressXSIType(false);
277       mar.setMarshalAsDocument(true);
278       mar.marshal(in);
279 //      System.err.print(sw.toString());
280       
281      Unmarshaller um = new Unmarshaller(ApplicationBase.class);
282      um.setIgnoreExtraAttributes(true);
283      um.setIgnoreExtraElements(true);
284      StringReader sr = new StringReader(sw.toString());
285      InputSource is = new InputSource(sr);
286      result = (ApplicationBase)um.unmarshal(is);
287 
288       
289       
290       return result;
291    }
292 */
293 /***
294  * @see org.astrogrid.applications.component.ProvidesVODescription#getDescription()
295  * @todo could cache the result.
296  */
297 public VODescription getVODescription() throws CastorException,  ApplicationDescriptionNotFoundException, IOException {    
298     return makeEntry();
299 }
300 /*** loads template fron url, builds objects from it */
301 private VODescription makeTemplate() throws IOException, MarshalException, ValidationException  {
302     logger.info("using " + urls.getRegistryTemplate() + " as registry template");
303     InputStreamReader iStream = new InputStreamReader(urls.getRegistryTemplate().openStream());
304     VODescription temp = VODescription.unmarshalVODescription(iStream);
305     //reset the authorityID and the server ID from the server entry
306      if( temp.getResource(1) instanceof CeaServiceType )  
307      {
308         CeaServiceType service = (CeaServiceType)temp.getResource(1);
309         authorityID = service.getIdentifier().getAuthorityID();
310         serverID = service.getIdentifier().getResourceKey();
311         logger.info("from template the service is called "+service.getIdentifier().toString());
312      }
313      else
314      {
315         logger.error("template not in expected format - resulting VODescriptions may be wrong");
316      }
317     return temp;
318 }
319 
320 public void reloadTemplate() throws MarshalException, ValidationException, IOException
321 {
322    template=makeTemplate();
323 }
324 
325     /* (non-Javadoc)
326      * @see org.astrogrid.applications.component.ProvidesVODescription#getAuthorityID()
327      */
328     public String getAuthorityID() {
329        return authorityID;
330     }
331     /* (non-Javadoc)
332      * @see org.astrogrid.applications.component.ProvidesVODescription#setServerID(java.lang.String)
333      */
334     public String setServerID(String id) {
335        serverID = id;
336        return serverID;
337     }
338 /***
339  * @see org.astrogrid.component.descriptor.ComponentDescriptor#getName()
340  */
341 public String getName() {
342     return "Default VODescription Provider";
343 }
344 
345 /***
346  * @see org.astrogrid.component.descriptor.ComponentDescriptor#getDescription()
347  */
348 public String getDescription() {
349     try {
350         VODescription desc = this.getVODescription();
351         Document doc = XMLUtils.newDocument();
352         Marshaller.marshal(desc,doc);
353         StringWriter sw = new StringWriter();
354         XMLUtils.PrettyDocumentToWriter(doc,sw);
355         return "VODescription \n" + XMLUtils.xmlEncodeString(sw.toString());
356     } catch (Exception e) {
357         return "Could not display description: " + e.getMessage();
358     }
359     
360 }
361 
362 /***
363  * @see org.astrogrid.component.descriptor.ComponentDescriptor#getInstallationTest()
364  */
365 public Test getInstallationTest() {
366     return new InstallationTest("testGetDescription");
367 }
368 
369 /*** Installation test - checks that {@link RegistryEntryBuilder#getVODescription()} works correctly 
370  * @author Noel Winstanley nw@jb.man.ac.uk 26-Jul-2004
371  *
372  */
373 public class InstallationTest extends TestCase {
374 
375     public InstallationTest(String arg0) {
376         super(arg0);
377     }
378     
379     public void testGetDescription() throws Exception {
380         VODescription desc = getVODescription();
381         assertNotNull(desc);
382     }
383 
384 }
385 
386 }