View Javadoc

1   /*$Id: XqlMaker.java,v 1.2 2004/10/18 13:11:30 mch Exp $
2    * Created on 27-Nov-2003
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.datacenter.queriers.xql;
12  
13  import java.io.BufferedInputStream;
14  import java.io.IOException;
15  import java.io.InputStream;
16  import java.io.StringWriter;
17  import javax.xml.parsers.ParserConfigurationException;
18  import javax.xml.transform.Transformer;
19  import javax.xml.transform.TransformerConfigurationException;
20  import javax.xml.transform.TransformerException;
21  import javax.xml.transform.TransformerFactory;
22  import javax.xml.transform.dom.DOMSource;
23  import javax.xml.transform.stream.StreamResult;
24  import javax.xml.transform.stream.StreamSource;
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.astrogrid.config.SimpleConfig;
28  import org.astrogrid.datacenter.query.Adql074Writer;
29  import org.astrogrid.datacenter.query.Query;
30  import org.astrogrid.datacenter.query.QueryException;
31  import org.astrogrid.util.DomHelper;
32  import org.w3c.dom.Element;
33  import org.xml.sax.SAXException;
34  
35  /***
36   * Creates XQL (XQuery?) from the query using transformation sheets
37   */
38  public class XqlMaker {
39  
40     private static final Log log = LogFactory.getLog(XqlMaker.class);
41  
42        
43     /***
44      * Constructs an XQL statement for the given ADQL
45      */
46     public String getXql(Query query) throws QueryException, IOException {
47  
48        Element adql = null;
49        //get the ADQL from the query
50        try {
51           adql = DomHelper.newDocument(Adql074Writer.makeAdql(query, null)).getDocumentElement();
52        }
53        catch (SAXException e) {
54           throw new RuntimeException("Query2Adql074 procuced invalid XML from query "+query,e);
55        }
56        catch (ParserConfigurationException e) {
57           throw new RuntimeException("Server configuration error:"+e,e);
58        }
59        
60        //Create DOM
61        String namespaceURI = adql.getNamespaceURI();
62        if (namespaceURI == null) {
63              // maybe not using namespace aware parser - see if we can find an xmlns attribute instead
64              namespaceURI = adql.getAttribute("xmlns");
65          }
66          if (namespaceURI == null) {
67              DomHelper.PrettyElementToStream(adql,System.out);
68              throw new IllegalArgumentException("Query body has no namespace - cannot determine language");
69          }
70          
71          String xql = useXslt(adql, namespaceURI);
72          
73          return xql;
74  
75       }
76       
77     
78       /*** Uses Xslt to do the translations */
79     public String useXslt(Element queryBody, String namespaceURI) throws QueryException {
80  
81        String xsltDoc = null;
82  
83        //work out which translator sheet to use
84        
85        //default
86        if ((namespaceURI==null) || (namespaceURI.length()==0)) {
87           throw new QueryException("No namespace specified in query document, so don't know what it is");
88        }
89        else if (namespaceURI.equals("http://tempuri.org/adql")) { //assume v0.5
90           xsltDoc = "adql05-2-sql.xsl";
91        }
92        else if (namespaceURI.equals("http://adql.ivoa.net/v0.73")) {
93           //xsltDoc = "adql073-2-sql.xsl";
94           //xsltDoc = "ADQLToXQL-0_73.xsl";
95          xsltDoc = "adql073-2-xql_fits.xsl";
96        }
97        else if (namespaceURI.equals("http://www.ivoa.net/xml/ADQL/v0.7.4")) {
98           xsltDoc = "adql074-2-xql_fits.xsl";
99        }
100 //      else if (namespaceURI.equals("http://adql.ivoa.net/v0.8")) {
101 //         xsltDoc = "adql08-2-sql.xsl";
102 //      }
103       else if (namespaceURI.equals("http://astrogrid.org/sadql/v1.1")) {
104          xsltDoc = "sadql1.1-2-sql.xsl";
105       }
106       
107       //look up in config but using above softcoded as defaults
108       String key = "datacenter.sqlmaker.xslt."+namespaceURI.replaceAll(":","_");
109       xsltDoc = SimpleConfig.getSingleton().getString(key, xsltDoc);
110       
111       if (xsltDoc == null) {
112          throw new RuntimeException("No XSLT sheet given for ADQL (namespace '"+namespaceURI+"'); set configuration key '" + key+"'");
113       }
114 
115       Transformer transformer = null;
116       try {
117          //look for transformation sheet as resource of this class (for unit tests, etc)
118          InputStream xsltIn = new BufferedInputStream(XqlMaker.class.getResourceAsStream("./xslt/"+xsltDoc));
119          
120          if (xsltIn == null) {
121             //if it's in a JAR under tomcat the above won't find it - look for it on class path
122            ClassLoader loader = this.getClass().getClassLoader();
123            xsltIn = loader.getResourceAsStream(xsltDoc);
124          }
125       
126          if (xsltIn == null) {
127             throw new QueryException("Could not find/create ADQL->XQL transformer doc "+xsltDoc);
128          }
129          
130          log.debug("Transforming ADQL ["+namespaceURI+"] using Xslt doc at './xslt/"+xsltDoc+"'");
131          TransformerFactory tFactory = TransformerFactory.newInstance();
132          transformer = tFactory.newTransformer(new StreamSource(xsltIn));
133          try {
134             tFactory.setAttribute("UseNamespaces", Boolean.FALSE);
135          }
136          catch (IllegalArgumentException iae) {
137             //ignore - if UseNamepsaces is unsupported, it will chuck an exception, and
138             //we don't want to use namespaces anyway so taht's fine
139          }
140          
141          StringWriter sw = new StringWriter();
142          transformer.transform(new DOMSource(queryBody), new StreamResult(sw));
143          String xql = sw.toString();
144         
145          //tidy it up - remove new lines and double spaces
146          xql = xql.replaceAll("\n","");
147          xql = xql.replaceAll("\r","");
148          while (xql.indexOf("  ")>-1) { xql = xql.replaceAll("  ", " "); }
149          
150          //botch botch botch - for some reason transformers sometimes add <?xml tag to beginning
151          if (xql.startsWith("<?")) {
152             xql = xql.substring(xql.indexOf("?>")+2);
153          }
154          //botch botch botch - something funny with ADQL 0.7.3 schema to do with comparisons
155          xql = xql.replaceAll("&gt;", ">").replaceAll("&lt;", "<");
156          
157          log.debug("Used '"+xsltDoc+"' to translate ADQL ("+namespaceURI+") to '"+xql+"'");
158          
159          return xql;
160       }
161       catch (TransformerConfigurationException tce) {
162          throw new QueryException(tce+" (using xslt sheet "+xsltDoc+")",tce);
163       }
164       catch (TransformerException te) {
165          throw new QueryException(te+" translating ADQL->SQL using "+xsltDoc,te);
166       }
167 
168    }
169    
170 }
171 
172 
173 /*
174 $Log: XqlMaker.java,v $
175 Revision 1.2  2004/10/18 13:11:30  mch
176 Lumpy Merge
177 
178 Revision 1.1.2.1  2004/10/15 19:59:06  mch
179 Lots of changes during trip to CDS to improve int test pass rate
180 
181 
182  
183 */