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