Project

General

Profile

1 87 jones
/**
2 203 jones
 *  '$RCSfile$'
3
 *    Purpose: A Class that transforms an XML text document
4
 *             into a another type using XSL
5
 *  Copyright: 2000 Regents of the University of California and the
6
 *             National Center for Ecological Analysis and Synthesis
7
 *    Authors: Matt Jones
8 87 jones
 *
9 1929 brooke
 * '$Author$'
10
 * '$Date$'
11 203 jones
 * '$Revision$'
12 669 jones
 *
13
 * This program is free software; you can redistribute it and/or modify
14
 * it under the terms of the GNU General Public License as published by
15
 * the Free Software Foundation; either version 2 of the License, or
16
 * (at your option) any later version.
17
 *
18
 * This program is distributed in the hope that it will be useful,
19
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21
 * GNU General Public License for more details.
22
 *
23
 * You should have received a copy of the GNU General Public License
24
 * along with this program; if not, write to the Free Software
25
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
26 87 jones
 */
27
28
package edu.ucsb.nceas.metacat;
29
30 5752 leinfelder
import java.io.File;
31
import java.io.FileInputStream;
32
import java.io.FileNotFoundException;
33
import java.io.IOException;
34
import java.io.OutputStreamWriter;
35
import java.io.StringReader;
36
import java.io.Writer;
37
import java.sql.SQLException;
38 1688 tao
import java.util.Enumeration;
39 1664 tao
import java.util.Hashtable;
40 3675 barteau
import java.util.Iterator;
41
import java.util.Map;
42 87 jones
43 906 berkley
import javax.xml.transform.TransformerFactory;
44
import javax.xml.transform.Transformer;
45
import javax.xml.transform.stream.StreamSource;
46
import javax.xml.transform.stream.StreamResult;
47
48 2663 sgarg
import org.apache.log4j.Logger;
49 906 berkley
import org.apache.xerces.parsers.DOMParser;
50
import org.w3c.dom.NamedNodeMap;
51
import org.w3c.dom.NodeList;
52
import org.w3c.dom.Document;
53
import org.w3c.dom.Node;
54
import org.xml.sax.InputSource;
55
import org.apache.xpath.XPathAPI;
56
57 5030 daigle
import edu.ucsb.nceas.metacat.properties.PropertyService;
58
import edu.ucsb.nceas.metacat.properties.SkinPropertyService;
59 4080 daigle
import edu.ucsb.nceas.metacat.util.SystemUtil;
60
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
61 4327 leinfelder
import edu.ucsb.nceas.utilities.SortedProperties;
62 4080 daigle
63 1716 berkley
/**
64 87 jones
 * A Class that transforms XML documents utitlizing XSL style sheets
65
 */
66
public class DBTransform {
67
68 7859 leinfelder
69 832 jones
  private String 	configDir = null;
70
  private String	defaultStyle = null;
71 2663 sgarg
  private Logger logMetacat = Logger.getLogger(DBTransform.class);
72 3780 daigle
  private String httpServer = null;
73 3725 tao
  private String contextURL = null;
74 3780 daigle
  private String servletURL = null;
75 2663 sgarg
76 87 jones
  /**
77
   * construct a DBTransform instance.
78
   *
79
   * Generally, one calls transformXMLDocument() after constructing the instance
80
   *
81
   * @param conn the database connection from which to lookup the public ids
82
   */
83 1716 berkley
  public DBTransform()
84
                  throws IOException,
85
                         SQLException,
86 4080 daigle
                         ClassNotFoundException,
87
                         PropertyNotFoundException
88 87 jones
  {
89 4080 daigle
    configDir = SystemUtil.getStyleSkinsDir();
90
    defaultStyle = PropertyService.getProperty("application.default-style");
91
    httpServer = SystemUtil.getServerURL();
92
    contextURL = SystemUtil.getContextURL();
93
    servletURL = SystemUtil.getServletURL();
94 87 jones
  }
95 1716 berkley
96 87 jones
  /**
97
   * Transform an XML document using the stylesheet reference from the db
98
   *
99
   * @param doc the document to be transformed
100
   * @param sourcetype the document type of the source
101
   * @param targettype the target document type
102 832 jones
   * @param qformat the name of the style set to use
103
   * @param pw the PrintWriter to which output is printed
104 1664 tao
   * @param params some parameters for eml2 transformation
105 87 jones
   */
106 1716 berkley
  public void transformXMLDocument(String doc, String sourceType,
107
                                   String targetType, String qformat,
108 5752 leinfelder
                                   Writer w, Hashtable<String, String[]> param,
109 1716 berkley
                                   String sessionid)
110 1664 tao
 {
111 1716 berkley
112 5752 leinfelder
	  String xslSystemId = getStyleSystemId(qformat, sourceType, targetType);
113
	  try {
114
		  // Look up the stylesheet for this type combination
115
		  if (xslSystemId != null) {
116
			// Create a stylesheet from the system id that was found
117
			doc = removeDOCTYPE(doc);
118 7860 leinfelder
			StreamSource xml = new StreamSource(new StringReader(doc));
119 5752 leinfelder
			StreamResult result = new StreamResult(w);
120
			doTransform(xml, result, xslSystemId, param, qformat, sessionid);
121
		  }
122
		  else {
123
			  // No stylesheet registered form this document type, so just return the
124
			  // XML stream we were passed
125
			  w.write(doc);
126
		  }
127 2088 tao
      }
128
      catch (Exception e)
129
      {
130 5752 leinfelder
    	  try {
131 7258 leinfelder
    		  String msg = xslSystemId + ": Error transforming document in " +
132
	           "DBTransform.transformXMLDocument: " +
133
	           e.getMessage();
134
    		  w.write(msg);
135
    		  w.flush();
136
    		  logMetacat.error(msg, e);
137 5752 leinfelder
		} catch (IOException e1) {
138
			logMetacat.error(e1.getMessage(), e1);
139
		}
140 1716 berkley
141 87 jones
      }
142 5752 leinfelder
143 87 jones
  }
144 941 tao
145 1716 berkley
146 3675 barteau
  /**
147
   * Reads skin's config file if it exists, and populates Transformer paramaters
148
   * with its contents.
149
   * It then adds the parameters passed to it via Hashtable param to the Transformer.
150
   * It then calls the Transformer.transform method.
151 2088 tao
   */
152 7860 leinfelder
  private void doTransform(StreamSource xml,
153 3675 barteau
          StreamResult resultOutput,
154
          String xslSystemId,
155 5025 daigle
          Hashtable<String, String[]> param,
156 3675 barteau
          String qformat,
157
          String sessionid)
158
          throws Exception {
159
160 4327 leinfelder
      SortedProperties skinOptions;
161 3675 barteau
      TransformerFactory tFactory;
162
      Transformer transformer;
163
      String key, value;
164 5025 daigle
      Enumeration<String> en;
165
      Iterator<Map.Entry<String, String>> iterIt;
166
      Map.Entry<String, String> entry;
167 3675 barteau
168
      if (xslSystemId != null) {
169
        tFactory = TransformerFactory.newInstance();
170
        transformer = tFactory.newTransformer(new StreamSource(xslSystemId));
171
172 2088 tao
        transformer.setParameter("qformat", qformat);
173 5167 daigle
        logMetacat.info("DBTransform.doTransform - qformat: " + qformat);
174 2893 sgarg
175 4327 leinfelder
        skinOptions = SkinPropertyService.getProperties(qformat);
176
        if (skinOptions != null) {
177
            iterIt = skinOptions.getProperties().entrySet().iterator();
178 3675 barteau
            while (iterIt.hasNext()) {
179 5025 daigle
                entry = iterIt.next();
180
                key = entry.getKey();
181
                value = entry.getValue();
182 4327 leinfelder
                //only include the plain properties
183
                if (key.indexOf('.') == -1) {
184
                	transformer.setParameter(key, value);
185
                }
186 3675 barteau
            }
187
        }
188 2893 sgarg
189 3675 barteau
        if (sessionid != null && !sessionid.equals("null")) {
190 2088 tao
          transformer.setParameter("sessid", sessionid);
191
        }
192 3675 barteau
193 3733 leinfelder
        //set up the default params (can be overridden by the passed in params)
194 4080 daigle
        String cgiPrefix = SystemUtil.getCGI_URL();
195 5167 daigle
        logMetacat.debug("DBTransform.doTransform - cgi-prefix: " + cgiPrefix);
196
        logMetacat.debug("DBTransform.doTransform - httpServer: " + httpServer);
197
        logMetacat.debug("DBTransform.doTransform - contextURL: " + contextURL);
198
        logMetacat.debug("DBTransform.doTransform - serletURL: " + servletURL);
199 3733 leinfelder
        transformer.setParameter("cgi-prefix", cgiPrefix);
200 3780 daigle
        transformer.setParameter("httpServer", httpServer);
201 3733 leinfelder
        transformer.setParameter("contextURL", contextURL);
202 3780 daigle
        transformer.setParameter("servletURL", servletURL);
203 3733 leinfelder
204 2088 tao
        // Set up parameter for transformation
205 3675 barteau
        if ( param != null) {
206
          en = param.keys();
207
          while (en.hasMoreElements()) {
208 5025 daigle
            key = en.nextElement();
209
            value = (param.get(key))[0];
210 5167 daigle
            logMetacat.info("DBTransform.doTransform - param: " + key + " -- " + value);
211 2088 tao
            transformer.setParameter(key, value);
212
          }
213
        }
214 7860 leinfelder
        transformer.transform(xml, resultOutput);
215 2088 tao
    }
216
  }//doTransform
217
218
219 1716 berkley
  /**
220 906 berkley
   * gets the content of a tag in a given xml file with the given path
221
   * @param f the file to parse
222
   * @param path the path to get the content from
223
   */
224 1716 berkley
  public static NodeList getPathContent(File f, String path)
225 906 berkley
  {
226
    if(f == null)
227
    {
228
      return null;
229
    }
230 1716 berkley
231 906 berkley
    DOMParser parser = new DOMParser();
232
    InputSource in;
233
    FileInputStream fs;
234 1716 berkley
235 906 berkley
    try
236 1716 berkley
    {
237 906 berkley
      fs = new FileInputStream(f);
238
      in = new InputSource(fs);
239
    }
240
    catch(FileNotFoundException fnf)
241
    {
242
      fnf.printStackTrace();
243
      return null;
244
    }
245 1716 berkley
246 906 berkley
    try
247
    {
248
      parser.parse(in);
249
      fs.close();
250
    }
251
    catch(Exception e1)
252
    {
253 1716 berkley
      System.err.println("File: " + f.getPath() + " : parse threw: " +
254 906 berkley
                         e1.toString());
255
      return null;
256
    }
257 1716 berkley
258 906 berkley
    Document doc = parser.getDocument();
259 1716 berkley
260 906 berkley
    try
261
    {
262
      NodeList docNodeList = XPathAPI.selectNodeList(doc, path);
263
      return docNodeList;
264
    }
265
    catch(Exception se)
266
    {
267 1716 berkley
      System.err.println("file: " + f.getPath() + " : parse threw: " +
268 906 berkley
                         se.toString());
269
      return null;
270
    }
271
  }
272 87 jones
273
  /**
274
   * Lookup a stylesheet reference from the db catalog
275
   *
276 832 jones
   * @param qformat    the named style-set format
277
   * @param sourcetype the document type of the source
278
   * @param targettype the document type of the target
279
   */
280 1716 berkley
  public String getStyleSystemId(String qformat, String sourcetype,
281 832 jones
                String targettype) {
282
    String systemId = null;
283
284
    if ((qformat == null) || (qformat.equals("html"))) {
285
      qformat = defaultStyle;
286
    }
287
288
    // Load the style-set map for this qformat into a DOM
289
    try {
290 906 berkley
      boolean breakflag = false;
291 1929 brooke
      String filename = configDir + "/" + qformat + "/" + qformat + ".xml";
292 5167 daigle
      logMetacat.info("DBTransform.getStyleSystemId - Trying style-set file: " + filename);
293 906 berkley
      File f = new File(filename);
294
      NodeList nlDoctype = getPathContent(f, "/style-set/doctype");
295
      NodeList nlDefault = getPathContent(f, "/style-set/default-style");
296
      Node nDefault = nlDefault.item(0);
297
      systemId = nDefault.getFirstChild().getNodeValue(); //set the default
298 1716 berkley
299 906 berkley
      for(int i=0; i<nlDoctype.getLength(); i++)
300
      { //look for the right sourcetype
301
        Node nDoctype = nlDoctype.item(i);
302
        NamedNodeMap atts = nDoctype.getAttributes();
303
        Node nAtt = atts.getNamedItem("publicid");
304
        String doctype = nAtt.getFirstChild().getNodeValue();
305
        if(doctype.equals(sourcetype))
306
        { //found the right sourcetype now we need to get the target type
307
          NodeList nlChildren = nDoctype.getChildNodes();
308
          for(int j=0; j<nlChildren.getLength(); j++)
309
          {
310
            Node nChild = nlChildren.item(j);
311
            String childName = nChild.getNodeName();
312
            if(childName.equals("target"))
313
            {
314
              NamedNodeMap childAtts = nChild.getAttributes();
315
              Node nTargetPublicId = childAtts.getNamedItem("publicid");
316
              String target = nTargetPublicId.getFirstChild().getNodeValue();
317
              if(target.equals(targettype))
318
              { //we found the right target type
319
                NodeList nlTarget = nChild.getChildNodes();
320
                for(int k=0; k<nlTarget.getLength(); k++)
321
                {
322
                  Node nChildText = nlTarget.item(k);
323
                  if(nChildText.getNodeType() == Node.TEXT_NODE)
324
                  { //get the text from the target node
325
                    systemId = nChildText.getNodeValue();
326
                    breakflag = true;
327
                    break;
328
                  }
329
                }
330 832 jones
              }
331
            }
332 1716 berkley
333 906 berkley
            if(breakflag)
334
            {
335
              break;
336
            }
337 832 jones
          }
338
        }
339 1716 berkley
340 906 berkley
        if(breakflag)
341
        {
342
          break;
343
        }
344 832 jones
      }
345
    }
346 906 berkley
    catch(Exception e)
347
    {
348
      System.out.println("Error parsing style-set file: " + e.getMessage());
349
      e.printStackTrace();
350
    }
351 3725 tao
352
    //Check if the systemId is relative path, add a postfix - the contextULR to systemID.
353
    if (systemId != null && systemId.indexOf("http://" ) == -1)
354
    {
355
    	systemId = contextURL+systemId;
356
    }
357 832 jones
    // Return the system ID for this particular source document type
358 5167 daigle
    logMetacat.info("DBTransform.getStyleSystemId - style system id is: " + systemId);
359 832 jones
    return systemId;
360
  }
361
362 5025 daigle
// /* Method to modified the system id of xml input -- make sure it
363
//    points to system id in xml_catalog table
364
//  */
365
//  private void modifiedXmlStreamSource(StreamSource xml, String publicId)
366
//                                       throws Exception
367
//  {
368
//    // make sure the xml is not null
369
//    if (xml == null || publicId == null)
370
//    {
371
//      return;
372
//    }
373
//    logMetacat.info("public id of input stream is " +publicId);
374
//    // Get system id from xml_catalog table
375
//    String systemId = DBEntityResolver.getDTDSystemID(publicId);
376
//    logMetacat.info("system id of input stream from xml_catalog"
377
//                               +"table is " +systemId);
378
//    //set system id to input stream
379
//    xml.setSystemId(systemId);
380
//  }
381 2088 tao
382 1903 tao
  /*
383
   * removes the DOCTYPE element and its contents from a Sting
384 2088 tao
   * used to avoid problems with incorrect SystemIDs
385 1903 tao
   */
386 2088 tao
  private String removeDOCTYPE(String in) {
387 1903 tao
    String ret = "";
388
    int startpos = in.indexOf("<!DOCTYPE");
389
    if (startpos>-1) {
390 2088 tao
      int stoppos = in.indexOf(">", startpos + 8);
391 1903 tao
      ret = in.substring(0,startpos) + in.substring(stoppos+1,in.length());
392
    } else {
393
      return in;
394
    }
395 2088 tao
    return ret;
396 1903 tao
  }
397 99 jones
398
  /**
399
   * the main routine used to test the transform utility.
400
   *
401 184 jones
   * Usage: java DBTransform
402 99 jones
   */
403
  static public void main(String[] args) {
404 1716 berkley
405 184 jones
     if (args.length > 0)
406 99 jones
     {
407
        System.err.println("Wrong number of arguments!!!");
408 184 jones
        System.err.println("USAGE: java DBTransform");
409 99 jones
        return;
410
     } else {
411
        try {
412 1716 berkley
413 99 jones
          // Create a test document
414
          StringBuffer testdoc = new StringBuffer();
415 5752 leinfelder
          String encoding = "UTF-8";
416
          testdoc.append("<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>");
417 99 jones
          testdoc.append("<eml-dataset><metafile_id>NCEAS-0001</metafile_id>");
418
          testdoc.append("<dataset_id>DS001</dataset_id>");
419
          testdoc.append("<title>My test doc</title></eml-dataset>");
420
421
          // Transform the document to the new doctype
422 5752 leinfelder
          Writer w = new OutputStreamWriter(System.out, encoding);
423 1217 tao
          DBTransform dbt = new DBTransform();
424 1716 berkley
          dbt.transformXMLDocument(testdoc.toString(),
425
                                   "-//NCEAS//eml-dataset//EN",
426
                                   "-//W3C//HTML//EN",
427 832 jones
                                   "knb",
428 5752 leinfelder
                                   w, null, null);
429 99 jones
430
        } catch (Exception e) {
431
          System.err.println("EXCEPTION HANDLING REQUIRED");
432
          System.err.println(e.getMessage());
433
          e.printStackTrace(System.err);
434
        }
435
     }
436
  }
437 1716 berkley
438 5025 daigle
//  private void dbg(int position) {
439
//    System.err.println("Debug flag: " + position);
440
//  }
441 99 jones
442 87 jones
}