View Javadoc

1   package org.astrogrid.warehouse.ogsadai;
2   
3   import java.io.IOException;
4   import java.io.FileNotFoundException;
5   import java.net.URL;
6   import java.util.Properties;
7   import javax.xml.namespace.QName;
8   import org.apache.axis.client.Stub;
9   import org.globus.ogsa.utils.AnyHelper;
10  import org.gridforum.ogsi.EntryType;
11  import org.gridforum.ogsi.ExtensibilityType;
12  import org.gridforum.ogsi.HandleType;
13  import org.gridforum.ogsi.LocatorType;
14  import org.w3c.dom.Document;
15  import uk.org.ogsadai.common.XMLUtilities;
16  import uk.org.ogsadai.wsdl.gds.GDSPortType;
17  import uk.org.ogsadai.wsdl.gds.GDSServiceGridLocator;
18  import org.apache.log4j.Logger;
19  import uk.org.ogsadai.service.OGSADAIConstants;
20  import uk.org.ogsadai.service.daiservicegroups.DAIServiceGroupRegistrationPortType;
21  import uk.org.ogsadai.service.daiservicegroups.DAIServiceGroupRegistrationServiceLocator;
22  import uk.org.ogsadai.service.daiservicegroups.helpers.DAIServiceGroupQueryHelper;
23  
24  
25  /***
26   * A delegate for the Grid Data Service (GDS) of OGSA-DAI.
27   * This delegate provides a sub-set of the GDS' functions
28   * that are useful to AstroGrid's data warehouse.
29   *
30   * This class is based on GridServiceDelegate in the same package,
31   * the latter being copied verbatim from the "Anglo-Australian
32   * Demonstration" (AAD) produced by AstroGrid and AusVO in 2003.
33   *
34   * On construction, the GSH of the service factory is not set
35   * in the delegate.  The caller must either set this GSH directly,
36   * using {@link setFactoryHandle} or tell the delegate to obtain
37   * it from the OGSA-DAI registry using {@link setFactoryGshFromRegistry}.
38   *
39   * THIS CLASS HAS BEEN DEPRECATED AND IS NO LONGER IN USE.
40   *
41   * @deprecated
42   */
43  public class GdsDelegate extends GridServiceDelegate {
44  
45    /***
46     * Configuration properties for the service.
47     * These use the GdsDelegate.properties file to discover
48     * the location of the OGSA-DAI warehouse services, configure
49     * OGSA-DAI input etc.
50     */
51    private Properties serviceProperties = null;
52    static Logger logger = Logger.getLogger("GdsLogger");
53  
54    /***
55     * Grid Service Handle for the registry of 
56     * Grid Data Service Factories.  This is used in the
57     * no-argument form of {@link setFactoryGshFromRegistry}.
58     */
59    private String registryGsh = null;
60  
61    private ExtensibilityType factoryHandle = null;
62  
63  	    
64    /***
65     * Initialises the GdsDelegate using values in its properties file
66     * GdsDelegate.properties.
67     */
68    public GdsDelegate() throws Exception {
69  
70      // Create and load default properties
71      serviceProperties = new Properties();
72      try {
73        serviceProperties.load(GdsDelegate.class.getResourceAsStream(
74            "GdsDelegate.properties"));
75      }
76      catch (FileNotFoundException e) {
77  	  logger.error("File not found. Couldn't find properties file " +
78  	  	"GdsDelegate.properties: " + e);
79        throw new Exception(
80          "Couldn't find properties file GdsDelegate.properties", e);
81      }
82      catch (IOException e) {
83        logger.error("IOException. Couldn't load properties from " +
84        	"GdsDelegate.properties: " + e.getMessage(), e);
85        throw new Exception(
86          "Couldn't load properties from GdsDelegate.properties: " +
87             e.getMessage(), e);
88      }
89    }
90  
91  
92    /***
93     * Returns the Grid Service Handle for the registry of 
94     * service factories.  This property is used by the
95     * no-argument form of {@link setFactoryGshFromRegistry}.
96     */
97    public String getRegistryGsh() {
98      return this.registryGsh;
99    }
100 
101   /***
102    * Sets the Grid Service Handle for the registry of 
103    * service factories.  This property is used by the
104    * no-argument form of {@link setFactoryGshFromRegistry}.
105    */
106   public void setRegistryGsh(String gsh) {
107     this.registryGsh = gsh;
108   }
109 
110 
111   /***
112    * Invokes an SQL select statement on the GDS instance. The
113    * SQL is passed  to the GDS in a "perform" document that is 
114    * created internally. The GDS' reply, is a "response" and this
115    * is returned as the method result
116    *
117    * @param query The SQL SELECT statment.
118    *
119    * @return The OGSA-DAI response document.
120    */  
121   public ExtensibilityType performSelect (String query) throws Exception {
122   
123     // Build the perform document.
124     ExtensibilityType document = null;
125     try {
126       String performDoc = this.makeXMLPerformDoc(query);
127       Document msgDoc = XMLUtilities.xmlStringToDOM(performDoc, false);
128       document = AnyHelper.getExtensibility(msgDoc.getDocumentElement());
129     }
130     catch (Exception e) {
131       logger.error("Cannot build the perform document "
132 	  + "for the Grid Data Service; query aborted.", e);
133       throw new Exception("Cannot build the perform document "
134                           + "for the Grid Data Service; query aborted.", e);
135     }
136 
137     // Submit the document and get the response.
138     // applicationPort is the stub for the GDS set in place by
139     // {@link connect}. Use a long timeout because the call is synchronous
140     // and the query may take a while.
141     ExtensibilityType result = null;
142     try {
143       ((Stub) this.applicationPort).setTimeout(30*60*1000);  // 30 min timeout
144       result = ((GDSPortType) this.applicationPort).perform(document);
145     }
146     catch (Exception e) {
147       String errorMessage =
148            "The Grid Data Service failed to execute the query: " +
149            "OGSA-DAI error is '" + e.getMessage() + "'";
150        logger.error(errorMessage);
151        throw new Exception(errorMessage,e);
152     }
153     return result;
154   }
155   
156   /***
157    * Creates a GDS instance and locates its application port.
158    * Records the port in the applicationPort attribute.
159    */
160   public void connect () throws Exception {
161     
162     logger.info("GdsDelegate: connecting...");
163     logger.info("Finding the factory port...");
164     this.findFactoryPort();
165     logger.info("Creating the service instance");
166     this.createServiceInstance();
167 	logger.info("Locating the service...");
168     GDSServiceGridLocator g = new GDSServiceGridLocator();
169     GDSPortType port = g.getGDSPort(this.instanceLocator);
170     this.applicationPort = port;
171 	logger.info("GdsDelegate: connected.");
172   }
173   
174   /***
175    * Imports a credential and attaches it to the service.
176    */
177   /*
178   public void attachGss() throws Exception {
179     GSSCredential cred = null;
180     ExtendedGSSManager manager =
181        (ExtendedGSSManager)ExtendedGSSManager.getInstance();
182     cred = manager.createCredential(GSSCredential.INITIATE_AND_ACCEPT);
183 
184     if ( cred == null ) {
185       throw new Exception("Cannot create a GSS Credential "
186                           + "for the Grid Data Service; operation aborted.");
187     }
188 
189     ((Stub) this.applicationPort)._setProperty(
190              Constants.GSI_SEC_CONV, Constants.SIGNATURE );
191     ((Stub) this.applicationPort)._setProperty(
192             GSIConstants.GSI_MODE, GSIConstants.GSI_MODE_LIMITED_DELEG );
193     ((Stub) this.applicationPort)._setProperty(
194             Constants.AUTHORIZATION, NoAuthorization.getInstance());
195     ((Stub) this.applicationPort)._setProperty(
196             GSIConstants.GSI_CREDENTIALS, cred );
197    }
198    */
199 
200 
201   /***
202    * Obtains the grid data service factory handle from the specified 
203    * registry and records it in the delegate.
204    *
205    * The GSH for the registry must previously have been set by
206    * a call to {@link setRegistryGsh}.
207    * 
208    * @throws Exception
209    */
210   public void setFactoryGshFromRegistry () throws Exception {
211     this.setFactoryGshFromRegistry(this.registryGsh, 15);
212   }
213 
214 
215   /***
216    * Obtains the grid data service factory handle from the specified 
217    * registry and sets it to a factory service handle.
218    * 
219    * @param registryUrl The URL of the registry.
220    * @param timeoutValue The timeout value in seconds
221    * @return void
222    * @throws Exception
223    */
224   public void setFactoryGshFromRegistry( 
225 	  String registryUrl, int timeoutValue ) throws Exception {
226 
227     // Ask the GDSR for information about registered GDSFs 
228     DAIServiceGroupRegistrationServiceLocator gdsrLocator = null;
229     DAIServiceGroupRegistrationPortType gdsrGpt = null;
230     try {
231       gdsrLocator = new DAIServiceGroupRegistrationServiceLocator();
232       gdsrGpt = gdsrLocator.getDAIServiceGroupRegistrationPort(
233           new URL(registryUrl));
234    
235       // Set timeout of SOAP calls
236       ((Stub) gdsrGpt).setTimeout(timeoutValue * 1000);
237 
238       QName[] portTypes = new QName[1];
239       portTypes[0] = OGSADAIConstants.GDSF_PORT_TYPE;
240       ExtensibilityType query = 
241           DAIServiceGroupQueryHelper.getPortTypeQuery(portTypes);
242       ExtensibilityType result = gdsrGpt.findServiceData(query);
243       String gsh = this.chooseFactoryFromRegistry(result);
244       this.setFactoryHandle(gsh);
245     }
246     catch (Exception e) {
247       throw new Exception("Can't get the GSH for the GDS factory "
248                           + " from the OGSA-DAI registry at "
249                           + registryUrl);
250     }
251 
252   }
253 
254 
255   /***
256    * Chooses a GDS factory from a list of factories.
257    * The list is in the form returned by the registry.
258    *
259    * @param queryResult the structure returned from the 
260    *                    query on the registry.
261    * @return the factory GSH.
262    */
263   String chooseFactoryFromRegistry (ExtensibilityType queryResult)
264       throws Exception {
265 
266     String factoryURLString = null;
267     boolean haveFoundFactoryUrl = false;
268     try {
269       Object[] entries = AnyHelper.getAsObject(queryResult, EntryType.class);
270 
271         if (entries == null || entries.length == 0){
272                         logger.error("No locators.");
273             throw new Exception("No locators.");
274         }
275 
276         // Chose which factory to use.  If message level security is
277         // on prefer URLs that contain the work secure.  If message
278         // level security is off prefer URLs that do not contain the
279         // work secure.
280         for( int i = 0; i<entries.length && !haveFoundFactoryUrl; ++i )
281         {
282             EntryType someEntry = (EntryType) entries[i];
283             LocatorType locator = someEntry.getMemberServiceLocator();
284             HandleType[] handles = locator.getHandle();
285             if (handles == null || handles.length == 0)
286             {
287                 logger.error("No handles.");
288                 throw new Exception("No handles.");
289             }
290             else {
291                factoryURLString = handles[0].toString();
292             }
293 
294             // Check to see if finished looking for factory URLs
295             if ( factoryURLString.toUpperCase().indexOf( "SECURE") >= 0 ) {
296                 // This is a factory for a secure GDS.  We will
297                 // consider this to be the best URL if message level
298                 // security is set.
299                 //if ( mIsMessageLevelSecurity ) //TOFIX - security flag
300                 if ( false ) {
301                     haveFoundFactoryUrl = true;
302                 }
303             }
304             else
305             {
306                 // This is a factory for a non-secure GDS.  We will
307                 // consider this to be the best bet if message level
308                 // security is off.
309                 //if ( !mIsMessageLevelSecurity ) //TOFIX - security flag
310                 if ( true ) {
311                     haveFoundFactoryUrl = true;
312                 }
313             }
314         }
315     }
316     catch (Exception e) {
317       logger.error("No factories registered at the OGSA-DAI registry.", e);
318       throw new Exception(
319          "No factories registered at the OGSA-DAI registry.", e);
320     }
321     if (!haveFoundFactoryUrl) {
322       logger.error("Couldn't find factory URL at the OGSA-DAI registry.");
323       throw new Exception(
324          "Couldn't find factory URL at the OGSA-DAI registry at ");
325     }
326 
327     logger.info("Chosen GDSF: " + factoryURLString);    
328     return factoryURLString;
329   }
330 
331 
332 
333 
334 
335   /***
336    * Converts an SQL string into an XML Perform document for OGSA-DAI.
337    * Doesn't touch the actual SQL query, just wraps it up in suitable XML.
338    *
339    * @param sqlString  A string containing a pure SQL query.
340    */
341   private String makeXMLPerformDoc(String sqlString) {
342 
343     return
344 
345       serviceProperties.getProperty(
346           "PERFORM_HEAD", DEFAULT_PERFORM_HEAD) +
347 
348       serviceProperties.getProperty(
349           "PERFORM_QUERY_START", DEFAULT_PERFORM_QUERY_START) +
350 
351       sqlString +
352 
353       serviceProperties.getProperty(
354           "PERFORM_QUERY_END", DEFAULT_PERFORM_QUERY_END) +
355 
356       serviceProperties.getProperty(
357           "PERFORM_FOOT", DEFAULT_PERFORM_FOOT);
358   }
359 
360 
361   private final String DEFAULT_PERFORM_HEAD = 
362       "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" + 
363       "<gridDataServicePerform " +
364       "xmlns=\"http://ogsadai.org.uk/namespaces/2003/07/gds/types\" " +
365       "xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" " +
366       "xsi:schemaLocation=\"http://ogsadai.org.uk/namespaces/2003/07/gds/types"+
367       //" ../../../../schema/ogsadai/xsd/activities/activities.xsd\">";
368       // TOFIX HOW SHOULD WE SET THIS PATH?  VIA PROPERTIES?
369       // SHOULD WE PUT THE SCHEMA ON AN ASTROGRID URL?
370       " /data/cass123a/kea/ogsadai-src/schema/ogsadai/xsd/activities/activities.xsd\">";
371 
372   private final String DEFAULT_PERFORM_QUERY_START = 
373       "<sqlQueryStatement name=\"statement\"><expression>";
374 
375   private final String DEFAULT_PERFORM_QUERY_END = 
376       "</expression><webRowSetStream name=\"statementOutput\"/>" +
377       "</sqlQueryStatement>";
378 
379   private final String DEFAULT_PERFORM_FOOT = "</gridDataServicePerform>";
380 }