View Javadoc

1   /*$Id: RegistryToolLocator.java,v 1.17 2005/08/01 08:15:52 clq2 Exp $
2    * Created on 08-Mar-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.jes.jobscheduler.locator;
12  
13  import org.astrogrid.component.descriptor.ComponentDescriptor;
14  import org.astrogrid.jes.JesException;
15  import org.astrogrid.jes.jobscheduler.Locator;
16  import org.astrogrid.registry.RegistryException;
17  //import org.astrogrid.registry.beans.resource.IdentifierType;
18  import org.astrogrid.registry.client.RegistryDelegateFactory;
19  import org.astrogrid.registry.client.query.RegistryService;
20  import org.astrogrid.workflow.beans.v1.Step;
21  import org.astrogrid.workflow.beans.v1.Tool;
22  
23  import org.apache.axis.utils.XMLUtils;
24  import org.apache.commons.logging.Log;
25  import org.apache.commons.logging.LogFactory;
26  import org.w3c.dom.Document;
27  import org.w3c.dom.NodeList;
28  
29  import java.io.StringWriter;
30  import java.net.MalformedURLException;
31  import java.net.URL;
32  import java.util.ArrayList;
33  import java.util.Arrays;
34  import java.util.Collections;
35  import java.util.HashSet;
36  import java.util.List;
37  import java.util.Random;
38  import java.util.Set;
39  
40  import junit.framework.Test;
41  
42  /*** Tool locator that resolves tools using the registry.
43   * @author Noel Winstanley nw@jb.man.ac.uk 08-Mar-2004
44   * @todo needs to be re-thought to allow calling of different types of service - resolving to endpoints is still valid - however, many registered services will have a single reg entry, 
45   * rather than cea-application and cea-service - so query pattern is different
46   *
47   */
48  public class RegistryToolLocator implements Locator, ComponentDescriptor {
49      private static final Log logger = LogFactory.getLog(RegistryToolLocator.class);
50      /*** interface to configure registry with */
51      public interface RegistryEndpoint {
52          URL getURL();
53      }
54      
55      public RegistryToolLocator(RegistryEndpoint endpoint) {
56          url = endpoint.getURL();
57          delegate = RegistryDelegateFactory.createQuery(url);
58      }
59      
60      protected final URL url;
61      protected final RegistryService delegate;
62      protected final Random rand = new Random();
63  
64      /***
65       * @see org.astrogrid.jes.jobscheduler.Locator#locateTool(org.astrogrid.workflow.beans.v1.Step)
66       */    
67      public String[] locateTool(Tool tool) throws JesException{           
68              String name =tool.getName();
69              logger.info("Locating service endpoints for cea application  " + name);            
70              // retrieve the cea application entry first - verify it exists.
71              if (name == null ) {
72                  throw reportError("Unnamed application - cannot locate it");
73              }                        
74              Document toolDocument;
75              try {
76                  toolDocument = delegate.getResourceByIdentifier(name);
77              }
78              catch (RegistryException e) {
79                  throw reportError("Could not find registry entry for cea application " + name,e);
80              }            
81          // @todo not quite sure why we're doing this - already have the identifier of the cea application entry.    
82          String toolId = null;
83          //try {           
84              String[] toolIds = getIdentifiers(toolDocument);
85              if (toolIds.length == 0) {
86                  throw reportError("No identifiers in registry entry for cea application" + name);
87              }           
88              toolId = toolIds[0];
89          /*
90          } catch (CastorException e) {
91              throw reportError("Could not parse return document for cea application" + name,e);
92          } 
93          */           
94              logger.debug("found cea application: " + toolId);
95        //@todo use original application name in here instead..
96              
97              // now query registry for all entries the provide this tool.
98              String queryString = buildQueryString(toolId);
99              logger.debug("ADQL Query to find services " + queryString);
100             Document results = null;
101             try {
102                //results = delegate.submitQuery(queryString);
103                 results = delegate.searchFromSADQL(queryString);
104             } catch (RegistryException e) {
105                 throw reportError("Failed to query registry for services providing tool " + name,e);
106             }
107             // found identifiers
108             String[] serviceIds = null;
109             //try {
110                 serviceIds = getIdentifiers(results);
111                 logger.info("Found " + serviceIds.length + " matching cea services");
112                 if (serviceIds.length == 0) {
113                     throw reportError("Tool " + name + " has no known service providers");
114                 }
115             /*
116             } catch (CastorException e) {
117                 throw reportError("Failed to extract identifiers from query document",e);
118             }
119             */
120             
121             // see what endpoints we can get from the services..
122             logger.debug("Resolving services to endpoints");
123             Set endpoints = new HashSet(); // using a set to handle duplicate endpoints.            
124             for (int i = 0; i < serviceIds.length ; i++) {
125                 String serviceName = serviceIds[i];
126                 try {
127                     // @todo inefficient? we've already got the reg entries, but here we're querying reg to resolve to endpoint
128                     // someone with better unsterstanding of reg entries could parse them directly..
129                     String endpoint = delegate.getEndPointByIdentifier(serviceName);
130                     if (endpoint != null && endpoint.trim().length() > 0) { // looks ok, add it to the list.
131                         try {                       
132                             URL ep = new URL(endpoint); // check it's a valid url..
133                             endpoints.add(ep.toString());
134                         } catch (MalformedURLException e) {
135                             logger.warn("Service " + serviceName + "has duff endpoint URL",e);
136                         }
137                     }
138                     logger.debug("Service " + serviceName + " resolved to endpoint " + endpoint);
139                 } catch (RegistryException e) {
140                     logger.warn("Resolvng endpoint for " + serviceName + " failed",e);
141                 }
142             }
143             
144 
145             if (endpoints.size() == 0) {
146                 throw reportError("No service providers for Tool " + name +" have a valid endpoint");
147             } else if (endpoints.size() == 1) {
148                 logger.info("Service Endpoints for CEA application " + name + ": " + endpoints); 
149                 return new String[]{endpoints.iterator().next().toString()};
150             } else {
151                 logger.debug("More that one available service - shuffling..");
152                 List endpointsList = new ArrayList(endpoints);
153                 Collections.shuffle(endpointsList);
154                 logger.info("Service Endpoints for CEA application " + name + ": " + endpointsList);                 
155                 return (String[])endpointsList.toArray(new String[endpointsList.size()]);
156             }
157     }
158     
159     
160     private JesException reportError(String s, Exception e) {
161         logger.error(s,e);
162         return new JesException(s,e);
163     }
164     private JesException reportError(String s) {
165         logger.error(s);
166         return new JesException(s);
167     }    
168     
169 
170     private String buildQueryString(String toolId) {
171         String queryString = "Select * from Registry where " +
172         "cea:ManagedApplications/cea:ApplicationReference='" + toolId + "'";
173         return queryString;
174  
175     }
176     
177     /***
178      queries registry to get tool entry, extract details from this.
179      */
180     private String[] getIdentifiers(Document doc) {
181             logger.debug("Extracting Identifiers");
182             NodeList nl = doc.getElementsByTagNameNS("*","Resource");
183             String[] results = new String[nl.getLength()];
184             for (int i = 0; i < nl.getLength(); i++) {
185                 results[i] = ((org.w3c.dom.Element)nl.item(i)).getElementsByTagNameNS("*","identifier")
186                              .item(0).getFirstChild().getNodeValue();
187                 logger.debug(results[i]);
188             }            
189             return results;
190     }
191         
192     /***
193      * @see org.astrogrid.jes.jobscheduler.Locator#getToolInterface(org.astrogrid.workflow.beans.v1.Step)
194      */
195     public String getToolInterface(Step js) throws JesException {
196         logger.error("Deprecated method, not used");
197         return null;
198     }
199     /***
200      * @see org.astrogrid.jes.component.ComponentDescriptor#getName()
201      */
202     public String getName() {
203         return "Registry Tool Locator";
204     }
205     /***
206      * @see org.astrogrid.jes.component.ComponentDescriptor#getDescription()
207      */
208     public String getDescription() {
209         return "Resolve Tool locations using an astrogrid registry" +
210             "\n Currently looking in registry at " + url.toString();
211     }
212     /*** @todo check we can resolve endpoint 
213      * @see org.astrogrid.jes.component.ComponentDescriptor#getInstallationTest()
214      */
215     public Test getInstallationTest() {
216         return null;
217     }
218 }
219 
220 
221 /* 
222 $Log: RegistryToolLocator.java,v $
223 Revision 1.17  2005/08/01 08:15:52  clq2
224 Kmb 1293/1279/intTest1 FS/FM/Jes/Portal/IntTests
225 
226 Revision 1.16.20.1  2005/07/20 08:15:52  KevinBenson
227 now reflects 0.10 registry and does no longer require 0.9 and the 0.9 translation that the registry client was doing.
228 
229 Revision 1.16  2005/05/09 11:37:51  nw
230 fixed bug spotted by kona.
231 
232 Revision 1.15  2005/03/30 15:19:19  nw
233 fixed type cast problem
234 
235 Revision 1.14  2005/03/13 07:13:39  clq2
236 merging jes-nww-686 common-nww-686 workflow-nww-996 scripting-nww-995 cea-nww-994
237 
238 Revision 1.13.2.2  2005/03/11 15:21:35  nw
239 adjusted locator so that it returns a list of endpoints to connect to.
240 we can get round-robin by shuffling the list.
241 dispatcher tries each endpoint in the list until can connect to one wihout throwing an exception.
242 
243 Revision 1.13.2.1  2005/03/11 14:05:00  nw
244 random-selection of application server if more than oneavailable.
245 
246 Revision 1.13  2005/03/02 15:02:24  clq2
247 for v10 missing '
248 
249 Revision 1.11.36.2  2005/03/02 14:32:26  KevinBenson
250 *** empty log message ***
251 
252 Revision 1.11.36.1  2005/03/02 12:03:15  KevinBenson
253 changing to do adql queries now
254 
255 Revision 1.11  2004/10/08 20:03:19  pah
256 optimize the tool query to use namespaces - better performance than using wildcard
257 
258 Revision 1.10  2004/09/16 21:48:28  nw
259 tried to optimize query bulding
260 
261 Revision 1.9  2004/08/25 11:42:12  KevinBenson
262 changed to use prefixes
263 
264 Revision 1.8  2004/08/03 16:31:25  nw
265 simplified interface to dispatcher and locator components.
266 removed redundant implementations.
267 
268 Revision 1.7  2004/07/01 21:15:00  nw
269 added results-listener interface to jes
270 
271 Revision 1.6  2004/04/21 10:05:51  nw
272 implemented correctly - passes integration testing
273 
274 Revision 1.5  2004/04/08 14:43:26  nw
275 added delete and abort job functionality
276 
277 Revision 1.4  2004/03/15 01:30:45  nw
278 factored component descriptor out into separate package
279 
280 Revision 1.3  2004/03/15 00:06:57  nw
281 removed SchedulerNotifier interface - replaced references to it by references to JobScheduler interface - identical
282 
283 Revision 1.2  2004/03/09 14:41:44  nw
284 updated to track changes to registry delegate
285 
286 Revision 1.1  2004/03/08 00:37:07  nw
287 preliminary implementation of registry tool locatr
288  
289 */