Project

General

Profile

1 15 jones
/**
2 203 jones
 *  '$RCSfile$'
3
 *    Purpose: A Class that represents an XML node and its contents
4
 *  Copyright: 2000 Regents of the University of California and the
5
 *             National Center for Ecological Analysis and Synthesis
6
 *    Authors: Matt Jones
7 15 jones
 *
8 203 jones
 *   '$Author$'
9
 *     '$Date$'
10
 * '$Revision$'
11 669 jones
 *
12
 * This program is free software; you can redistribute it and/or modify
13
 * it under the terms of the GNU General Public License as published by
14
 * the Free Software Foundation; either version 2 of the License, or
15
 * (at your option) any later version.
16
 *
17
 * This program is distributed in the hope that it will be useful,
18
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20
 * GNU General Public License for more details.
21
 *
22
 * You should have received a copy of the GNU General Public License
23
 * along with this program; if not, write to the Free Software
24
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25 15 jones
 */
26
27 75 jones
package edu.ucsb.nceas.metacat;
28 15 jones
29
import java.sql.*;
30
import java.util.Hashtable;
31
import java.util.Enumeration;
32 2663 sgarg
import org.apache.log4j.Logger;
33 461 bojilova
import org.xml.sax.SAXException;
34 15 jones
35 4335 daigle
import edu.ucsb.nceas.metacat.service.DatabaseService;
36 747 bojilova
37 2358 sgarg
/**
38 137 jones
 * A Class that represents an XML node and its contents and
39 31 jones
 * can write its own representation to a database connection
40
 */
41 137 jones
public class DBSAXNode extends BasicNode {
42 15 jones
43 1217 tao
  private DBConnection	connection;
44 176 jones
  private DBSAXNode	parentNode;
45 2663 sgarg
  private Logger logMetacat = Logger.getLogger(DBSAXNode.class);
46 15 jones
47 2358 sgarg
  /**
48 136 jones
   * Construct a new node instance for DOCUMENT nodes
49 133 jones
   *
50
   * @param conn the JDBC Connection to which all information is written
51
   */
52 1217 tao
  public DBSAXNode (DBConnection conn, String docid) throws SAXException {
53 747 bojilova
54 408 jones
    super();
55 1217 tao
    this.connection = conn;
56 176 jones
    this.parentNode = null;
57 457 bojilova
    writeChildNodeToDB("DOCUMENT", null, null, docid);
58 758 bojilova
    updateRootNodeID(getNodeID());
59 136 jones
  }
60
61 2358 sgarg
  /**
62 136 jones
   * Construct a new node instance for ELEMENT nodes
63
   *
64
   * @param conn the JDBC Connection to which all information is written
65
   * @param tagname the name of the node
66
   * @param parentNode the parent node for this node being created
67
   */
68 1217 tao
  public DBSAXNode (DBConnection conn, String qName, String lName,
69 2358 sgarg
                    DBSAXNode parentNode, long rootnodeid,
70
                    String docid, String doctype)
71 826 bojilova
                                               throws SAXException {
72 21 jones
73 826 bojilova
    super(lName);
74 1217 tao
    this.connection = conn;
75 747 bojilova
    this.parentNode = parentNode;
76 136 jones
    setParentID(parentNode.getNodeID());
77 457 bojilova
    setRootNodeID(rootnodeid);
78
    setDocID(docid);
79 136 jones
    setNodeIndex(parentNode.incChildNum());
80 826 bojilova
    writeChildNodeToDB("ELEMENT", qName, null, docid);
81 471 bojilova
    //No writing XML Index from here. New Thread used instead.
82
    //updateNodeIndex(docid, doctype);
83 133 jones
  }
84 2358 sgarg
85
  /**
86 1803 tao
   * Construct a new node instance for DTD nodes
87
   * This Node will write docname, publicId and systemId into db. Only
88
   * handle systemid  existed.(external dtd)
89
   *
90
   * @param conn the JDBC Connection to which all information is written
91
   * @param tagname the name of the node
92
   * @param parentNode the parent node for this node being created
93
   */
94 2358 sgarg
  public DBSAXNode (DBConnection conn, String docName, String publicId,
95
                    String systemId, DBSAXNode parentNode, long rootnodeid,
96
                    String docid) throws SAXException
97 1803 tao
  {
98
99
    super();
100
    this.connection = conn;
101
    this.parentNode = parentNode;
102
    setParentID(parentNode.getNodeID());
103
    setRootNodeID(rootnodeid);
104
    setDocID(docid);
105
    // insert dtd node only for external dtd definiation
106
    if (systemId != null)
107
    {
108
      //write docname to DB
109
      if (docName != null)
110
      {
111
        setNodeIndex(parentNode.incChildNum());
112
        writeDTDNodeToDB(DocumentImpl.DOCNAME, docName, docid);
113
      }
114
      //write publicId to DB
115
      if (publicId != null)
116
      {
117
        setNodeIndex(parentNode.incChildNum());
118
        writeDTDNodeToDB(DocumentImpl.PUBLICID, publicId, docid);
119
      }
120
      //write systemId to DB
121
      setNodeIndex(parentNode.incChildNum());
122
      writeDTDNodeToDB(DocumentImpl.SYSTEMID, systemId, docid);
123
    }
124
  }
125 2358 sgarg
126 133 jones
  /** creates SQL code and inserts new node into DB connection */
127 1416 tao
  public long writeChildNodeToDB(String nodetype, String nodename,
128 2358 sgarg
                                 String data, String docid)
129
                                 throws SAXException
130 1416 tao
  {
131
    long nid = -1;
132 2358 sgarg
    try
133 1416 tao
    {
134 2358 sgarg
135 133 jones
      PreparedStatement pstmt;
136 2358 sgarg
137 133 jones
      if (nodetype == "DOCUMENT") {
138 1217 tao
        pstmt = connection.prepareStatement(
139 133 jones
            "INSERT INTO xml_nodes " +
140 826 bojilova
            "(nodetype, nodename, nodeprefix, docid) " +
141
            "VALUES (?, ?, ?, ?)");
142 2358 sgarg
143 1217 tao
        // Increase DBConnection usage count
144
        connection.increaseUsageCount(1);
145 2663 sgarg
        logMetacat.info("INSERTING DOCNAME: " + nodename);
146 133 jones
      } else {
147 2364 sgarg
          if(data != null && !data.trim().equals("")
148 3197 tao
             && !data.trim().equals("NaN") && !data.trim().equalsIgnoreCase("Infinity")){
149 2358 sgarg
              try{
150
                  double numberData = Double.parseDouble(data);
151
                  pstmt = connection.prepareStatement(
152
                      "INSERT INTO xml_nodes " +
153
                      "(nodetype, nodename, nodeprefix, docid, " +
154
                      "rootnodeid, parentnodeid, nodedata, nodeindex, nodedatanumerical) " +
155
                      "VALUES (?, ?, ?, ?, ?, ?, ?, ?, "+ numberData +")");
156
              } catch (NumberFormatException nfe) {
157
                  pstmt = connection.prepareStatement(
158
                      "INSERT INTO xml_nodes " +
159
                      "(nodetype, nodename, nodeprefix, docid, " +
160
                      "rootnodeid, parentnodeid, nodedata, nodeindex) " +
161
                      "VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
162
              }
163
          } else {
164
              pstmt = connection.prepareStatement(
165
                  "INSERT INTO xml_nodes " +
166
                  "(nodetype, nodename, nodeprefix, docid, " +
167
                  "rootnodeid, parentnodeid, nodedata, nodeindex) " +
168
                  "VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
169
          }
170 1217 tao
        // Increase DBConnection usage count
171
        connection.increaseUsageCount(1);
172 133 jones
      }
173 19 jones
174 133 jones
      // Bind the values to the query
175 758 bojilova
      pstmt.setString(1, nodetype);
176 826 bojilova
      int idx;
177
      if ( nodename != null && (idx = nodename.indexOf(":")) != -1 ) {
178
        pstmt.setString(2, nodename.substring(idx+1));
179
        pstmt.setString(3, nodename.substring(0,idx));
180
      } else {
181
        pstmt.setString(2, nodename);
182
        pstmt.setString(3, null);
183
      }
184
      pstmt.setString(4, docid);
185 408 jones
      if (nodetype == "DOCUMENT") {
186 758 bojilova
        // moved it to separate method updateRootNodeID
187
        //pstmt.setLong(4, nid);
188 408 jones
      } else {
189 133 jones
        if (nodetype == "ELEMENT") {
190 826 bojilova
          pstmt.setLong(5, getRootNodeID());
191
          pstmt.setLong(6, getParentID());
192
          pstmt.setString(7, data);
193
          pstmt.setInt(8, getNodeIndex());
194 133 jones
        } else {
195 826 bojilova
          pstmt.setLong(5, getRootNodeID());
196
          pstmt.setLong(6, getNodeID());
197
          pstmt.setString(7, data);
198
          pstmt.setInt(8, incChildNum());
199 72 bojilova
        }
200 133 jones
      }
201
      // Do the insertion
202 4661 daigle
      logMetacat.debug("SQL insert: " + pstmt.toString());
203 133 jones
      pstmt.execute();
204
      pstmt.close();
205 758 bojilova
206
      // get the generated unique id afterward
207 4335 daigle
      nid = DatabaseService.getDBAdapter().getUniqueID(connection.getConnections(), "xml_nodes");
208 1217 tao
      //should incease connection usage!!!!!!
209 2358 sgarg
210
211 408 jones
      if (nodetype.equals("DOCUMENT")) {
212
        // Record the root node id that was generated from the database
213
        setRootNodeID(nid);
214
      }
215
216 177 jones
      if (nodetype.equals("DOCUMENT") || nodetype.equals("ELEMENT")) {
217 176 jones
218 177 jones
        // Record the node id that was generated from the database
219
        setNodeID(nid);
220 176 jones
221 177 jones
        // Record the node type that was passed to the method
222
        setNodeType(nodetype);
223
224
      }
225
226 133 jones
    } catch (SQLException e) {
227 4661 daigle
      logMetacat.error("Error in DBSaxNode.writeChildNodeToDB");
228
      logMetacat.error("Error inserting node: (" + nodetype + ", " +
229 2358 sgarg
                                                     nodename + ", " +
230 136 jones
                                                     data + ")" );
231 4661 daigle
      logMetacat.error(e.getMessage());
232 915 berkley
      e.printStackTrace(System.err);
233 461 bojilova
      throw new SAXException(e.getMessage());
234 110 bojilova
    }
235 1416 tao
    return nid;
236 133 jones
  }
237 110 bojilova
238 2358 sgarg
  /**
239 758 bojilova
   * update rootnodeid=nodeid for 'DOCUMENT' type of nodes only
240
   */
241
  public void updateRootNodeID(long nodeid) throws SAXException {
242
      try {
243
        PreparedStatement pstmt;
244 1217 tao
        pstmt = connection.prepareStatement(
245 758 bojilova
              "UPDATE xml_nodes set rootnodeid = ? " +
246
              "WHERE nodeid = ?");
247 1217 tao
        // Increase DBConnection usage count
248
        connection.increaseUsageCount(1);
249 758 bojilova
250
        // Bind the values to the query
251
        pstmt.setLong(1, nodeid);
252
        pstmt.setLong(2, nodeid);
253
        // Do the update
254
        pstmt.execute();
255
        pstmt.close();
256
      } catch (SQLException e) {
257 2358 sgarg
        System.out.println("Error in DBSaxNode.updateRootNodeID: " +
258 758 bojilova
                           e.getMessage());
259
        throw new SAXException(e.getMessage());
260
      }
261
  }
262
263 2358 sgarg
  /**
264
   * creates SQL code to put nodename for the document node
265
   * into DB connection
266 133 jones
   */
267 461 bojilova
  public void writeNodename(String nodename) throws SAXException {
268 133 jones
      try {
269
        PreparedStatement pstmt;
270 1217 tao
        pstmt = connection.prepareStatement(
271 133 jones
              "UPDATE xml_nodes set nodename = ? " +
272
              "WHERE nodeid = ?");
273 1217 tao
        // Increase DBConnection usage count
274
        connection.increaseUsageCount(1);
275 16 jones
276 133 jones
        // Bind the values to the query
277
        pstmt.setString(1, nodename);
278 134 jones
        pstmt.setLong(2, getNodeID());
279 133 jones
        // Do the insertion
280
        pstmt.execute();
281
        pstmt.close();
282
      } catch (SQLException e) {
283 2358 sgarg
        System.out.println("Error in DBSaxNode.writeNodeName: " +
284 675 berkley
                           e.getMessage());
285 461 bojilova
        throw new SAXException(e.getMessage());
286 133 jones
      }
287
  }
288 16 jones
289 1803 tao
 /** creates SQL code and inserts new node into DB connection */
290 2358 sgarg
  public long writeDTDNodeToDB(String nodename, String data, String docid)
291
                                 throws SAXException
292 1803 tao
  {
293
    long nid = -1;
294 2358 sgarg
    try
295 1803 tao
    {
296 2358 sgarg
297 1803 tao
      PreparedStatement pstmt;
298 2663 sgarg
      logMetacat.info("Insert dtd into db: "+nodename +" "+data);
299 2358 sgarg
      if(data != null && !data.trim().equals("")){
300
            try{
301
                double numberData = Double.parseDouble(data);
302
                pstmt = connection.prepareStatement(
303
                    "INSERT INTO xml_nodes " +
304
                    "(nodetype, nodename, docid, " +
305
                    "rootnodeid, parentnodeid, nodedata, nodeindex, nodedatanumerical) " +
306
                    "VALUES (?, ?, ?, ?, ?, ?, ?, "+ numberData +")");
307
            } catch (NumberFormatException nfe) {
308
                pstmt = connection.prepareStatement(
309
                    "INSERT INTO xml_nodes " +
310
                    "(nodetype, nodename,  docid, " +
311
                    "rootnodeid, parentnodeid, nodedata, nodeindex) " +
312
                    "VALUES (?, ?, ?, ?, ?, ?, ?)");
313
            }
314
        } else {
315
            pstmt = connection.prepareStatement(
316
                  "INSERT INTO xml_nodes " +
317
                  "(nodetype, nodename, docid, " +
318
                  "rootnodeid, parentnodeid, nodedata, nodeindex) " +
319
                  "VALUES (?, ?, ?, ?, ?, ?, ?)");
320
        }
321
322 1803 tao
       // Increase DBConnection usage count
323
      connection.increaseUsageCount(1);
324 2358 sgarg
325 1803 tao
      // Bind the values to the query
326
      pstmt.setString(1, DocumentImpl.DTD);
327
      pstmt.setString(2, nodename);
328
      pstmt.setString(3, docid);
329
      pstmt.setLong(4, getRootNodeID());
330
      pstmt.setLong(5, getParentID());
331
      pstmt.setString(6, data);
332
      pstmt.setInt(7, getNodeIndex());
333 2358 sgarg
334 1803 tao
      // Do the insertion
335
      pstmt.execute();
336
      pstmt.close();
337
338
      // get the generated unique id afterward
339 4335 daigle
      nid = DatabaseService.getDBAdapter().getUniqueID(connection.getConnections(), "xml_nodes");
340 1803 tao
      //should incease connection usage!!!!!!
341 2358 sgarg
342 1803 tao
    } catch (SQLException e) {
343
      System.out.println("Error in DBSaxNode.writeDTDNodeToDB");
344
      System.err.println("Error inserting node: (" + DocumentImpl.DTD + ", " +
345 2358 sgarg
                                                     nodename + ", " +
346 1803 tao
                                                     data + ")" );
347
      System.err.println(e.getMessage());
348
      e.printStackTrace(System.err);
349
      throw new SAXException(e.getMessage());
350
    }
351
    return nid;
352
  }
353 2358 sgarg
354
355 174 bojilova
  /** get next node id from DB connection */
356 461 bojilova
  private long generateNodeID() throws SAXException {
357 174 bojilova
      long nid=0;
358 133 jones
      Statement stmt;
359 1217 tao
      DBConnection dbConn = null;
360
      int serialNumber = -1;
361 133 jones
      try {
362 1217 tao
        // Get DBConnection
363
        dbConn=DBConnectionPool.getDBConnection("DBSAXNode.generateNodeID");
364
        serialNumber=dbConn.getCheckOutSerialNumber();
365
        stmt = dbConn.createStatement();
366 174 bojilova
        stmt.execute("SELECT xml_nodes_id_seq.nextval FROM dual");
367 133 jones
        ResultSet rs = stmt.getResultSet();
368
        boolean tableHasRows = rs.next();
369
        if (tableHasRows) {
370 174 bojilova
          nid = rs.getLong(1);
371 19 jones
        }
372 133 jones
        stmt.close();
373
      } catch (SQLException e) {
374 2358 sgarg
        System.out.println("Error in DBSaxNode.generateNodeID: " +
375 675 berkley
                            e.getMessage());
376 461 bojilova
        throw new SAXException(e.getMessage());
377 15 jones
      }
378 1217 tao
      finally
379
      {
380
        // Return DBconnection
381
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
382
      }//finally
383 15 jones
384 174 bojilova
      return nid;
385 133 jones
  }
386 18 jones
387 137 jones
  /** Add a new attribute to this node, or set its value */
388 1416 tao
  public long setAttribute(String attName, String attValue, String docid)
389 2358 sgarg
              throws SAXException
390 1416 tao
  {
391
    long nodeId = -1;
392 2358 sgarg
    if (attName != null)
393 1416 tao
    {
394 133 jones
      // Enter the attribute in the hash table
395
      super.setAttribute(attName, attValue);
396 18 jones
397 133 jones
      // And enter the attribute in the database
398 1416 tao
      nodeId = writeChildNodeToDB("ATTRIBUTE", attName, attValue, docid);
399 2358 sgarg
    }
400
    else
401 1416 tao
    {
402 133 jones
      System.err.println("Attribute name must not be null!");
403 461 bojilova
      throw new SAXException("Attribute name must not be null!");
404 18 jones
    }
405 1416 tao
    return nodeId;
406 133 jones
  }
407 176 jones
408 821 bojilova
  /** Add a namespace to this node */
409 1416 tao
  public long setNamespace(String prefix, String uri, String docid)
410 2358 sgarg
              throws SAXException
411 1416 tao
  {
412
    long nodeId = -1;
413 2358 sgarg
    if (prefix != null)
414 1416 tao
    {
415 821 bojilova
      // Enter the namespace in a hash table
416
      super.setNamespace(prefix, uri);
417
      // And enter the namespace in the database
418 1416 tao
      nodeId = writeChildNodeToDB("NAMESPACE", prefix, uri, docid);
419 2358 sgarg
    }
420
    else
421 1416 tao
    {
422 821 bojilova
      System.err.println("Namespace prefix must not be null!");
423
      throw new SAXException("Namespace prefix must not be null!");
424
    }
425 1416 tao
    return nodeId;
426 821 bojilova
  }
427
428 176 jones
429 2358 sgarg
430
  /**
431 471 bojilova
   * USED FROM SEPARATE THREAD RUNNED from DBSAXHandler on endDocument()
432
   * Update the node index (xml_index) for this node by generating
433
   * test strings that represent all of the relative and absolute
434
   * paths through the XML tree from document root to this node
435
   */
436 2358 sgarg
  public void updateNodeIndex(DBConnection conn, String docid, String doctype)
437 471 bojilova
               throws SAXException
438
  {
439
    Hashtable pathlist = new Hashtable();
440
    boolean atStartingNode = true;
441
    boolean atRootDocumentNode = false;
442
    DBSAXNode nodePointer = this;
443
    StringBuffer currentPath = new StringBuffer();
444
    int counter = 0;
445
446
    // Create a Hashtable of all of the paths to reach this node
447
    // including absolute paths and relative paths
448
    while (!atRootDocumentNode) {
449
      if (atStartingNode) {
450
        currentPath.insert(0, nodePointer.getTagName());
451
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
452
        counter++;
453
        atStartingNode = false;
454
      } else {
455
        currentPath.insert(0, "/");
456
        currentPath.insert(0, nodePointer.getTagName());
457
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
458
        counter++;
459
      }
460
461
      // advance to the next parent node
462
      nodePointer = nodePointer.getParentNode();
463
464
      // If we're at the DOCUMENT node (root of DOM tree), add
465
      // the root "/" to make the absolute path
466
      if (nodePointer.getNodeType().equals("DOCUMENT")) {
467
        currentPath.insert(0, "/");
468
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
469
        counter++;
470
        atRootDocumentNode = true;
471 2358 sgarg
      }
472 471 bojilova
    }
473
474
    try {
475
      // Create an insert statement to reuse for all of the path insertions
476
      PreparedStatement pstmt = conn.prepareStatement(
477 2358 sgarg
              "INSERT INTO xml_index (nodeid, path, docid, doctype, " +
478
               "parentnodeid) " +
479 471 bojilova
              "VALUES (?, ?, ?, ?, ?)");
480 1217 tao
      // Increase usage count
481
      conn.increaseUsageCount(1);
482 2358 sgarg
483 471 bojilova
      pstmt.setString(3, docid);
484
      pstmt.setString(4, doctype);
485
      pstmt.setLong(5, getParentID());
486 2358 sgarg
487 471 bojilova
      // Step through the hashtable and insert each of the path values
488 176 jones
      Enumeration en = pathlist.keys();
489
      while (en.hasMoreElements()) {
490
        String path = (String)en.nextElement();
491
        Long nodeid = (Long)pathlist.get(path);
492
        pstmt.setLong(1, nodeid.longValue());
493
        pstmt.setString(2, path);
494 2358 sgarg
495 457 bojilova
        pstmt.executeUpdate();
496 176 jones
      }
497
      // Close the database statement
498
      pstmt.close();
499
    } catch (SQLException sqe) {
500 675 berkley
      System.err.println("SQL Exception while inserting path to index in " +
501 899 berkley
                         "DBSAXNode.updateNodeIndex for document " + docid);
502 176 jones
      System.err.println(sqe.getMessage());
503 461 bojilova
      throw new SAXException(sqe.getMessage());
504 176 jones
    }
505
  }
506 2358 sgarg
507 176 jones
  /** get the parent of this node */
508
  public DBSAXNode getParentNode() {
509
    return parentNode;
510
  }
511 15 jones
}