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