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 457 bojilova
import oracle.jdbc.driver.*;
35 461 bojilova
import org.xml.sax.SAXException;
36 15 jones
37 747 bojilova
import edu.ucsb.nceas.dbadapter.DBAdapter;
38
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 176 jones
  private Connection	conn;
46
  private DBSAXNode	parentNode;
47 747 bojilova
  private static final DBAdapter 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 461 bojilova
  public DBSAXNode (Connection conn, String docid) throws SAXException {
55 747 bojilova
56 408 jones
    super();
57 136 jones
    this.conn = 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 176 jones
  public DBSAXNode (Connection conn, String tagname, DBSAXNode parentNode,
71 461 bojilova
                    long rootnodeid, String docid, String doctype)
72
                    throws SAXException {
73 21 jones
74 136 jones
    super(tagname);
75 747 bojilova
    this.conn = conn;
76
    this.parentNode = parentNode;
77 136 jones
    setParentID(parentNode.getNodeID());
78 457 bojilova
    setRootNodeID(rootnodeid);
79
    setDocID(docid);
80 136 jones
    setNodeIndex(parentNode.incChildNum());
81 457 bojilova
    writeChildNodeToDB("ELEMENT", getTagName(), null, docid);
82 471 bojilova
    //No writing XML Index from here. New Thread used instead.
83
    //updateNodeIndex(docid, doctype);
84 133 jones
  }
85 15 jones
86 133 jones
  /** creates SQL code and inserts new node into DB connection */
87
  public void writeChildNodeToDB(String nodetype, String nodename,
88 461 bojilova
                                 String data, String docid)
89
                                 throws SAXException {
90 133 jones
    try {
91
      PreparedStatement pstmt;
92
      if (nodetype == "DOCUMENT") {
93
        pstmt = conn.prepareStatement(
94
            "INSERT INTO xml_nodes " +
95 758 bojilova
            "(nodetype, nodename, docid) " +
96
            "VALUES (?, ?, ?)");
97 204 jones
        MetaCatUtil.debugMessage("INSERTING DOCNAME: " + nodename);
98 133 jones
      } else {
99
        pstmt = conn.prepareStatement(
100
            "INSERT INTO xml_nodes " +
101 758 bojilova
            "(nodetype, nodename, docid, " +
102 457 bojilova
            "rootnodeid, parentnodeid, nodedata, nodeindex) " +
103 758 bojilova
            "VALUES (?, ?, ?, ?, ?, ?, ?)");
104 133 jones
      }
105 19 jones
106 133 jones
      // Bind the values to the query
107 747 bojilova
      // NOT USED; USED DBAdapter.getUniqueID() instead
108
      //long nid = generateNodeID();
109 758 bojilova
      // NOT USED
110
      //let the db generate it: using identity key or through
111
      //the db trigger xml_nodes_before_insert using sequence
112
      //long nid = dbAdapter.getUniqueID(conn, "xml_nodes");
113
      //pstmt.setLong(1, nid);
114
      pstmt.setString(1, nodetype);
115
      pstmt.setString(2, nodename);
116
      pstmt.setString(3, docid);
117 408 jones
      if (nodetype == "DOCUMENT") {
118 758 bojilova
        // moved it to separate method updateRootNodeID
119
        //pstmt.setLong(4, nid);
120 408 jones
      } else {
121 133 jones
        if (nodetype == "ELEMENT") {
122 758 bojilova
          pstmt.setLong(4, getRootNodeID());
123
          pstmt.setLong(5, getParentID());
124
          pstmt.setString(6, data);
125
          pstmt.setInt(7, getNodeIndex());
126 133 jones
        } else {
127 758 bojilova
          pstmt.setLong(4, getRootNodeID());
128
          pstmt.setLong(5, getNodeID());
129 452 bojilova
          if ( nodetype == "TEXT" && getTagName().equals("meta_file_id") ) {
130 758 bojilova
            pstmt.setString(6, getDocID());
131 452 bojilova
          } else {
132 758 bojilova
            pstmt.setString(6, data);
133 452 bojilova
          }
134 758 bojilova
          pstmt.setInt(7, incChildNum());
135 72 bojilova
        }
136 133 jones
      }
137
      // Do the insertion
138
      pstmt.execute();
139
      pstmt.close();
140 758 bojilova
141
      // get the generated unique id afterward
142
      long nid = dbAdapter.getUniqueID(conn, "xml_nodes");
143 174 bojilova
144 408 jones
      if (nodetype.equals("DOCUMENT")) {
145
        // Record the root node id that was generated from the database
146
        setRootNodeID(nid);
147
      }
148
149 177 jones
      if (nodetype.equals("DOCUMENT") || nodetype.equals("ELEMENT")) {
150 176 jones
151 177 jones
        // Record the node id that was generated from the database
152
        setNodeID(nid);
153 176 jones
154 177 jones
        // Record the node type that was passed to the method
155
        setNodeType(nodetype);
156
157
      }
158
159 133 jones
    } catch (SQLException e) {
160 675 berkley
      System.out.println("Error in DBSaxNode.writeChildNodeToDB");
161 133 jones
      System.err.println("Error inserting node: (" + nodetype + ", " +
162
                                                     nodename + ", " +
163 136 jones
                                                     data + ")" );
164 133 jones
      System.err.println(e.getMessage());
165 461 bojilova
      throw new SAXException(e.getMessage());
166 110 bojilova
    }
167 133 jones
  }
168 110 bojilova
169 133 jones
  /**
170 758 bojilova
   * update rootnodeid=nodeid for 'DOCUMENT' type of nodes only
171
   */
172
  public void updateRootNodeID(long nodeid) throws SAXException {
173
      try {
174
        PreparedStatement pstmt;
175
        pstmt = conn.prepareStatement(
176
              "UPDATE xml_nodes set rootnodeid = ? " +
177
              "WHERE nodeid = ?");
178
179
        // Bind the values to the query
180
        pstmt.setLong(1, nodeid);
181
        pstmt.setLong(2, nodeid);
182
        // Do the update
183
        pstmt.execute();
184
        pstmt.close();
185
      } catch (SQLException e) {
186
        System.out.println("Error in DBSaxNode.updateRootNodeID: " +
187
                           e.getMessage());
188
        throw new SAXException(e.getMessage());
189
      }
190
  }
191
192
  /**
193 133 jones
   * creates SQL code to put nodename for the document node
194
   * into DB connection
195
   */
196 461 bojilova
  public void writeNodename(String nodename) throws SAXException {
197 133 jones
      try {
198
        PreparedStatement pstmt;
199
        pstmt = conn.prepareStatement(
200
              "UPDATE xml_nodes set nodename = ? " +
201
              "WHERE nodeid = ?");
202 16 jones
203 133 jones
        // Bind the values to the query
204
        pstmt.setString(1, nodename);
205 134 jones
        pstmt.setLong(2, getNodeID());
206 133 jones
        // Do the insertion
207
        pstmt.execute();
208
        pstmt.close();
209
      } catch (SQLException e) {
210 675 berkley
        System.out.println("Error in DBSaxNode.writeNodeName: " +
211
                           e.getMessage());
212 461 bojilova
        throw new SAXException(e.getMessage());
213 133 jones
      }
214
  }
215 16 jones
216 174 bojilova
  /** get next node id from DB connection */
217 461 bojilova
  private long generateNodeID() throws SAXException {
218 174 bojilova
      long nid=0;
219 133 jones
      Statement stmt;
220
      try {
221
        stmt = conn.createStatement();
222 174 bojilova
        stmt.execute("SELECT xml_nodes_id_seq.nextval FROM dual");
223 133 jones
        ResultSet rs = stmt.getResultSet();
224
        boolean tableHasRows = rs.next();
225
        if (tableHasRows) {
226 174 bojilova
          nid = rs.getLong(1);
227 19 jones
        }
228 133 jones
        stmt.close();
229
      } catch (SQLException e) {
230 675 berkley
        System.out.println("Error in DBSaxNode.generateNodeID: " +
231
                            e.getMessage());
232 461 bojilova
        throw new SAXException(e.getMessage());
233 15 jones
      }
234
235 174 bojilova
      return nid;
236 133 jones
  }
237 18 jones
238 137 jones
  /** Add a new attribute to this node, or set its value */
239 461 bojilova
  public void setAttribute(String attName, String attValue, String docid)
240
              throws SAXException {
241 133 jones
    if (attName != null) {
242
      // Enter the attribute in the hash table
243
      super.setAttribute(attName, attValue);
244 18 jones
245 133 jones
      // And enter the attribute in the database
246 457 bojilova
      writeChildNodeToDB("ATTRIBUTE", attName, attValue, docid);
247 133 jones
    } else {
248
      System.err.println("Attribute name must not be null!");
249 461 bojilova
      throw new SAXException("Attribute name must not be null!");
250 18 jones
    }
251 133 jones
  }
252 176 jones
253
  /**
254 471 bojilova
   * NOT USED
255 176 jones
   * Update the node index (xml_index) for this node by generating
256
   * test strings that represent all of the relative and absolute
257
   * paths through the XML tree from document root to this node
258
   */
259 461 bojilova
  private void updateNodeIndex(String docid, String doctype)
260
               throws SAXException
261
  {
262 176 jones
    Hashtable pathlist = new Hashtable();
263
    boolean atStartingNode = true;
264
    boolean atRootDocumentNode = false;
265
    DBSAXNode nodePointer = this;
266
    StringBuffer currentPath = new StringBuffer();
267 457 bojilova
    int counter = 0;
268 176 jones
269
    // Create a Hashtable of all of the paths to reach this node
270
    // including absolute paths and relative paths
271
    while (!atRootDocumentNode) {
272
      if (atStartingNode) {
273
        currentPath.insert(0, nodePointer.getTagName());
274
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
275 457 bojilova
        counter++;
276 176 jones
        atStartingNode = false;
277
      } else {
278
        currentPath.insert(0, "/");
279
        currentPath.insert(0, nodePointer.getTagName());
280
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
281 457 bojilova
        counter++;
282 176 jones
      }
283
284
      // advance to the next parent node
285
      nodePointer = nodePointer.getParentNode();
286
287
      // If we're at the DOCUMENT node (root of DOM tree), add
288
      // the root "/" to make the absolute path
289
      if (nodePointer.getNodeType().equals("DOCUMENT")) {
290
        currentPath.insert(0, "/");
291
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
292 457 bojilova
        counter++;
293 176 jones
        atRootDocumentNode = true;
294
      }
295
    }
296
297
    try {
298
      // Create an insert statement to reuse for all of the path insertions
299
      PreparedStatement pstmt = conn.prepareStatement(
300 449 berkley
              "INSERT INTO xml_index (nodeid, path, docid, doctype, " +
301
               "parentnodeid) " +
302
              "VALUES (?, ?, ?, ?, ?)");
303 457 bojilova
      ((OraclePreparedStatement)pstmt).setExecuteBatch(counter);
304 176 jones
305 314 bojilova
      pstmt.setString(3, docid);
306
      pstmt.setString(4, doctype);
307 449 berkley
      pstmt.setLong(5, getParentID());
308 314 bojilova
309 176 jones
      // Step through the hashtable and insert each of the path values
310 471 bojilova
      Enumeration en = pathlist.keys();
311
      while (en.hasMoreElements()) {
312
        String path = (String)en.nextElement();
313
        Long nodeid = (Long)pathlist.get(path);
314
        pstmt.setLong(1, nodeid.longValue());
315
        pstmt.setString(2, path);
316
        pstmt.executeUpdate();
317
318
        //System.out.println(nodeid + " ==> " + path);
319
      }
320
321
      // Close the database statement
322
      pstmt.close();
323
    } catch (SQLException sqe) {
324 675 berkley
      System.err.println("SQL Exception while inserting path to index in " +
325
                         "DBSAXNode.updateNodeIndex");
326 471 bojilova
      System.err.println(sqe.getMessage());
327
      throw new SAXException(sqe.getMessage());
328
    }
329
  }
330
331
  /**
332
   * USED FROM SEPARATE THREAD RUNNED from DBSAXHandler on endDocument()
333
   * Update the node index (xml_index) for this node by generating
334
   * test strings that represent all of the relative and absolute
335
   * paths through the XML tree from document root to this node
336
   */
337
  public void updateNodeIndex(Connection conn, String docid, String doctype)
338
               throws SAXException
339
  {
340
    Hashtable pathlist = new Hashtable();
341
    boolean atStartingNode = true;
342
    boolean atRootDocumentNode = false;
343
    DBSAXNode nodePointer = this;
344
    StringBuffer currentPath = new StringBuffer();
345
    int counter = 0;
346
347
    // Create a Hashtable of all of the paths to reach this node
348
    // including absolute paths and relative paths
349
    while (!atRootDocumentNode) {
350
      if (atStartingNode) {
351
        currentPath.insert(0, nodePointer.getTagName());
352
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
353
        counter++;
354
        atStartingNode = false;
355
      } else {
356
        currentPath.insert(0, "/");
357
        currentPath.insert(0, nodePointer.getTagName());
358
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
359
        counter++;
360
      }
361
362
      // advance to the next parent node
363
      nodePointer = nodePointer.getParentNode();
364
365
      // If we're at the DOCUMENT node (root of DOM tree), add
366
      // the root "/" to make the absolute path
367
      if (nodePointer.getNodeType().equals("DOCUMENT")) {
368
        currentPath.insert(0, "/");
369
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
370
        counter++;
371
        atRootDocumentNode = true;
372
      }
373
    }
374
375
    try {
376
      // Create an insert statement to reuse for all of the path insertions
377
      PreparedStatement pstmt = conn.prepareStatement(
378
              "INSERT INTO xml_index (nodeid, path, docid, doctype, " +
379
               "parentnodeid) " +
380
              "VALUES (?, ?, ?, ?, ?)");
381
      ((OraclePreparedStatement)pstmt).setExecuteBatch(counter);
382
383
      pstmt.setString(3, docid);
384
      pstmt.setString(4, doctype);
385
      pstmt.setLong(5, getParentID());
386
387
      // Step through the hashtable and insert each of the path values
388 176 jones
      Enumeration en = pathlist.keys();
389
      while (en.hasMoreElements()) {
390
        String path = (String)en.nextElement();
391
        Long nodeid = (Long)pathlist.get(path);
392
        pstmt.setLong(1, nodeid.longValue());
393
        pstmt.setString(2, path);
394 457 bojilova
        pstmt.executeUpdate();
395 176 jones
396
        //System.out.println(nodeid + " ==> " + path);
397
      }
398
399
      // Close the database statement
400
      pstmt.close();
401
    } catch (SQLException sqe) {
402 675 berkley
      System.err.println("SQL Exception while inserting path to index in " +
403
                         "DBSAXNode.updateNodeIndex");
404 176 jones
      System.err.println(sqe.getMessage());
405 461 bojilova
      throw new SAXException(sqe.getMessage());
406 176 jones
    }
407
  }
408
409
  /** get the parent of this node */
410
  public DBSAXNode getParentNode() {
411
    return parentNode;
412
  }
413 15 jones
}