Project

General

Profile

1
/**
2
 *  '$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
 *
9
 * '$Author: leinfelder $'
10
 * '$Date: 2015-11-03 14:36:34 -0800 (Tue, 03 Nov 2015) $'
11
 * '$Revision: 9391 $'
12
 *
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
 */
27

    
28
package edu.ucsb.nceas.metacat;
29

    
30
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
import java.util.Enumeration;
39
import java.util.Hashtable;
40
import java.util.Iterator;
41
import java.util.Map;
42

    
43
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
import org.apache.log4j.Logger;
49
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
import edu.ucsb.nceas.metacat.properties.PropertyService;
58
import edu.ucsb.nceas.metacat.properties.SkinPropertyService;
59
import edu.ucsb.nceas.metacat.util.SystemUtil;
60
import edu.ucsb.nceas.utilities.PropertyNotFoundException;
61
import edu.ucsb.nceas.utilities.SortedProperties;
62

    
63
/**
64
 * A Class that transforms XML documents utitlizing XSL style sheets
65
 */
66
public class DBTransform {
67

    
68

    
69
  private String 	configDir = null;
70
  private String	defaultStyle = null;
71
  private Logger logMetacat = Logger.getLogger(DBTransform.class);
72
  private String httpServer = null;
73
  private String contextURL = null;
74
  private String servletURL = null;
75
  private String userManagementURL = null;
76
  
77
  /**
78
   * construct a DBTransform instance.
79
   *
80
   * Generally, one calls transformXMLDocument() after constructing the instance
81
   *
82
   * @param conn the database connection from which to lookup the public ids
83
   */
84
  public DBTransform()
85
                  throws IOException,
86
                         SQLException,
87
                         ClassNotFoundException,
88
                         PropertyNotFoundException
89
  {
90
    configDir = SystemUtil.getStyleSkinsDir();
91
    defaultStyle = PropertyService.getProperty("application.default-style");
92
    httpServer = SystemUtil.getServerURL();
93
    contextURL = SystemUtil.getContextURL();
94
    servletURL = SystemUtil.getServletURL();
95
    userManagementURL = PropertyService.getProperty("auth.userManagementUrl");
96
  }
97

    
98
  /**
99
   * Transform an XML document using the stylesheet reference from the db
100
   *
101
   * @param doc the document to be transformed
102
   * @param sourcetype the document type of the source
103
   * @param targettype the target document type
104
   * @param qformat the name of the style set to use
105
   * @param pw the PrintWriter to which output is printed
106
   * @param params some parameters for eml2 transformation
107
   */
108
  public void transformXMLDocument(String doc, String sourceType,
109
                                   String targetType, String qformat,
110
                                   Writer w, Hashtable<String, String[]> param,
111
                                   String sessionid)
112
 {
113

    
114
	  String xslSystemId = getStyleSystemId(qformat, sourceType, targetType);
115
	  try {
116
		  // Look up the stylesheet for this type combination
117
		  if (xslSystemId != null) {
118
			// Create a stylesheet from the system id that was found
119
			doc = removeDOCTYPE(doc);
120
			StreamSource xml = new StreamSource(new StringReader(doc));
121
			StreamResult result = new StreamResult(w);
122
			doTransform(xml, result, xslSystemId, param, qformat, sessionid);
123
		  }
124
		  else {
125
			  // No stylesheet registered form this document type, so just return the
126
			  // XML stream we were passed
127
			  w.write(doc);
128
		  }
129
      }
130
      catch (Exception e)
131
      {
132
    	  try {
133
    		  String msg = xslSystemId + ": Error transforming document in " +
134
	           "DBTransform.transformXMLDocument: " +
135
	           e.getMessage();
136
    		  w.write(msg);
137
    		  w.flush();
138
    		  logMetacat.error(msg, e);
139
		} catch (IOException e1) {
140
			logMetacat.error(e1.getMessage(), e1);
141
		}
142

    
143
      }
144
    
145
  }
146

    
147

    
148
  /**
149
   * Reads skin's config file if it exists, and populates Transformer paramaters
150
   * with its contents.
151
   * It then adds the parameters passed to it via Hashtable param to the Transformer.
152
   * It then calls the Transformer.transform method.
153
   */
154
  private void doTransform(StreamSource xml, 
155
          StreamResult resultOutput,
156
          String xslSystemId, 
157
          Hashtable<String, String[]> param,
158
          String qformat, 
159
          String sessionid) 
160
          throws Exception {
161
      
162
      SortedProperties skinOptions;
163
      TransformerFactory tFactory;
164
      Transformer transformer;
165
      String key, value;
166
      Enumeration<String> en;
167
      Iterator<Map.Entry<String, String>> iterIt;
168
      Map.Entry<String, String> entry;
169
      
170
      if (xslSystemId != null) {
171
        tFactory = TransformerFactory.newInstance();
172
        transformer = tFactory.newTransformer(new StreamSource(xslSystemId));
173
        
174
        transformer.setParameter("qformat", qformat);
175
        logMetacat.info("DBTransform.doTransform - qformat: " + qformat);
176
        
177
        skinOptions = SkinPropertyService.getProperties(qformat);
178
        if (skinOptions != null) {            
179
            iterIt = skinOptions.getProperties().entrySet().iterator();
180
            while (iterIt.hasNext()) {
181
                entry = iterIt.next();
182
                key = entry.getKey();
183
                value = entry.getValue();
184
                //only include the plain properties
185
                if (key.indexOf('.') == -1) {
186
                	transformer.setParameter(key, value);
187
                }
188
            }
189
        }
190
        
191
        if (sessionid != null && !sessionid.equals("null")) {
192
          transformer.setParameter("sessid", sessionid);
193
        }
194
        
195
        //set up the default params (can be overridden by the passed in params)
196
        String cgiPrefix = SystemUtil.getCGI_URL();
197
        logMetacat.debug("DBTransform.doTransform - cgi-prefix: " + cgiPrefix);
198
        logMetacat.debug("DBTransform.doTransform - httpServer: " + httpServer);
199
        logMetacat.debug("DBTransform.doTransform - contextURL: " + contextURL);
200
        logMetacat.debug("DBTransform.doTransform - serletURL: " + servletURL);
201
        logMetacat.debug("DBTransform.doTransform - userManagementURL: " + userManagementURL);
202
        transformer.setParameter("cgi-prefix", cgiPrefix);
203
        transformer.setParameter("httpServer", httpServer);
204
        transformer.setParameter("contextURL", contextURL);
205
        transformer.setParameter("servletURL", servletURL);
206
        transformer.setParameter("userManagementURL", userManagementURL);
207
        // Set up parameter for transformation
208
        if ( param != null) {
209
          en = param.keys();
210
          while (en.hasMoreElements()) {
211
            key = en.nextElement();
212
            value = (param.get(key))[0];
213
            logMetacat.info("DBTransform.doTransform - param: " + key + " -- " + value);
214
            transformer.setParameter(key, value);
215
          }
216
        }
217
        transformer.transform(xml, resultOutput);
218
    }
219
  }//doTransform
220

    
221

    
222
  /**
223
   * gets the content of a tag in a given xml file with the given path
224
   * @param f the file to parse
225
   * @param path the path to get the content from
226
   */
227
  public static NodeList getPathContent(File f, String path)
228
  {
229
    if(f == null)
230
    {
231
      return null;
232
    }
233

    
234
    DOMParser parser = new DOMParser();
235
    InputSource in;
236
    FileInputStream fs;
237

    
238
    try
239
    {
240
      fs = new FileInputStream(f);
241
      in = new InputSource(fs);
242
    }
243
    catch(FileNotFoundException fnf)
244
    {
245
      fnf.printStackTrace();
246
      return null;
247
    }
248

    
249
    try
250
    {
251
      parser.parse(in);
252
      fs.close();
253
    }
254
    catch(Exception e1)
255
    {
256
      System.err.println("File: " + f.getPath() + " : parse threw: " +
257
                         e1.toString());
258
      return null;
259
    }
260

    
261
    Document doc = parser.getDocument();
262

    
263
    try
264
    {
265
      NodeList docNodeList = XPathAPI.selectNodeList(doc, path);
266
      return docNodeList;
267
    }
268
    catch(Exception se)
269
    {
270
      System.err.println("file: " + f.getPath() + " : parse threw: " +
271
                         se.toString());
272
      return null;
273
    }
274
  }
275

    
276
  /**
277
   * Lookup a stylesheet reference from the db catalog
278
   *
279
   * @param qformat    the named style-set format
280
   * @param sourcetype the document type of the source
281
   * @param targettype the document type of the target
282
   */
283
  public String getStyleSystemId(String qformat, String sourcetype,
284
                String targettype) {
285
    String systemId = null;
286

    
287
    if ((qformat == null) || (qformat.equals("html"))) {
288
      qformat = defaultStyle;
289
    }
290

    
291
    // Load the style-set map for this qformat into a DOM
292
    try {
293
      boolean breakflag = false;
294
      String filename = configDir + "/" + qformat + "/" + qformat + ".xml";
295
      logMetacat.info("DBTransform.getStyleSystemId - Trying style-set file: " + filename);
296
      File f = new File(filename);
297
      NodeList nlDoctype = getPathContent(f, "/style-set/doctype");
298
      NodeList nlDefault = getPathContent(f, "/style-set/default-style");
299
      Node nDefault = nlDefault.item(0);
300
      systemId = nDefault.getFirstChild().getNodeValue(); //set the default
301

    
302
      for(int i=0; i<nlDoctype.getLength(); i++)
303
      { //look for the right sourcetype
304
        Node nDoctype = nlDoctype.item(i);
305
        NamedNodeMap atts = nDoctype.getAttributes();
306
        Node nAtt = atts.getNamedItem("publicid");
307
        String doctype = nAtt.getFirstChild().getNodeValue();
308
        if(doctype.equals(sourcetype))
309
        { //found the right sourcetype now we need to get the target type
310
          NodeList nlChildren = nDoctype.getChildNodes();
311
          for(int j=0; j<nlChildren.getLength(); j++)
312
          {
313
            Node nChild = nlChildren.item(j);
314
            String childName = nChild.getNodeName();
315
            if(childName.equals("target"))
316
            {
317
              NamedNodeMap childAtts = nChild.getAttributes();
318
              Node nTargetPublicId = childAtts.getNamedItem("publicid");
319
              String target = nTargetPublicId.getFirstChild().getNodeValue();
320
              if(target.equals(targettype))
321
              { //we found the right target type
322
                NodeList nlTarget = nChild.getChildNodes();
323
                for(int k=0; k<nlTarget.getLength(); k++)
324
                {
325
                  Node nChildText = nlTarget.item(k);
326
                  if(nChildText.getNodeType() == Node.TEXT_NODE)
327
                  { //get the text from the target node
328
                    systemId = nChildText.getNodeValue();
329
                    breakflag = true;
330
                    break;
331
                  }
332
                }
333
              }
334
            }
335

    
336
            if(breakflag)
337
            {
338
              break;
339
            }
340
          }
341
        }
342

    
343
        if(breakflag)
344
        {
345
          break;
346
        }
347
      }
348
    }
349
    catch(Exception e)
350
    {
351
      System.out.println("Error parsing style-set file: " + e.getMessage());
352
      e.printStackTrace();
353
    }
354
    
355
    //Check if the systemId is relative path, add a postfix - the contextULR to systemID. 
356
    if (systemId != null && !systemId.startsWith("http"))
357
    {
358
    	systemId = contextURL+systemId;
359
    }
360
    // Return the system ID for this particular source document type
361
    logMetacat.info("DBTransform.getStyleSystemId - style system id is: " + systemId);
362
    return systemId;
363
  }
364

    
365
// /* Method to modified the system id of xml input -- make sure it
366
//    points to system id in xml_catalog table
367
//  */
368
//  private void modifiedXmlStreamSource(StreamSource xml, String publicId)
369
//                                       throws Exception
370
//  {
371
//    // make sure the xml is not null
372
//    if (xml == null || publicId == null)
373
//    {
374
//      return;
375
//    }
376
//    logMetacat.info("public id of input stream is " +publicId);
377
//    // Get system id from xml_catalog table
378
//    String systemId = DBEntityResolver.getDTDSystemID(publicId);
379
//    logMetacat.info("system id of input stream from xml_catalog"
380
//                               +"table is " +systemId);
381
//    //set system id to input stream
382
//    xml.setSystemId(systemId);
383
//  }
384

    
385
  /*
386
   * removes the DOCTYPE element and its contents from a Sting
387
   * used to avoid problems with incorrect SystemIDs
388
   */
389
  private String removeDOCTYPE(String in) {
390
    String ret = "";
391
    int startpos = in.indexOf("<!DOCTYPE");
392
    if (startpos>-1) {
393
      int stoppos = in.indexOf(">", startpos + 8);
394
      ret = in.substring(0,startpos) + in.substring(stoppos+1,in.length());
395
    } else {
396
      return in;
397
    }
398
    return ret;
399
  }
400

    
401
  /**
402
   * the main routine used to test the transform utility.
403
   *
404
   * Usage: java DBTransform
405
   */
406
  static public void main(String[] args) {
407

    
408
     if (args.length > 0)
409
     {
410
        System.err.println("Wrong number of arguments!!!");
411
        System.err.println("USAGE: java DBTransform");
412
        return;
413
     } else {
414
        try {
415

    
416
          // Create a test document
417
          StringBuffer testdoc = new StringBuffer();
418
          String encoding = "UTF-8";
419
          testdoc.append("<?xml version=\"1.0\" encoding=\"" + encoding + "\"?>");
420
          testdoc.append("<eml-dataset><metafile_id>NCEAS-0001</metafile_id>");
421
          testdoc.append("<dataset_id>DS001</dataset_id>");
422
          testdoc.append("<title>My test doc</title></eml-dataset>");
423

    
424
          // Transform the document to the new doctype
425
          Writer w = new OutputStreamWriter(System.out, encoding);
426
          DBTransform dbt = new DBTransform();
427
          dbt.transformXMLDocument(testdoc.toString(),
428
                                   "-//NCEAS//eml-dataset//EN",
429
                                   "-//W3C//HTML//EN",
430
                                   "knb",
431
                                   w, null, null);
432

    
433
        } catch (Exception e) {
434
          System.err.println("EXCEPTION HANDLING REQUIRED");
435
          System.err.println(e.getMessage());
436
          e.printStackTrace(System.err);
437
        }
438
     }
439
  }
440

    
441
//  private void dbg(int position) {
442
//    System.err.println("Debug flag: " + position);
443
//  }
444

    
445
}
(21-21/64)