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