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
      System.err.println("Error inserting node: (" + nodetype + ", " +
147
                                                     nodename + ", " +
148 136 jones
                                                     data + ")" );
149 133 jones
      System.err.println(e.getMessage());
150 461 bojilova
      throw new SAXException(e.getMessage());
151 110 bojilova
    }
152 133 jones
  }
153 110 bojilova
154 133 jones
  /**
155
   * creates SQL code to put nodename for the document node
156
   * into DB connection
157
   */
158 461 bojilova
  public void writeNodename(String nodename) throws SAXException {
159 133 jones
      try {
160
        PreparedStatement pstmt;
161
        pstmt = conn.prepareStatement(
162
              "UPDATE xml_nodes set nodename = ? " +
163
              "WHERE nodeid = ?");
164 16 jones
165 133 jones
        // Bind the values to the query
166
        pstmt.setString(1, nodename);
167 134 jones
        pstmt.setLong(2, getNodeID());
168 133 jones
        // Do the insertion
169
        pstmt.execute();
170
        pstmt.close();
171
      } catch (SQLException e) {
172
        System.out.println(e.getMessage());
173 461 bojilova
        throw new SAXException(e.getMessage());
174 133 jones
      }
175
  }
176 16 jones
177 174 bojilova
  /** get next node id from DB connection */
178 461 bojilova
  private long generateNodeID() throws SAXException {
179 174 bojilova
      long nid=0;
180 133 jones
      Statement stmt;
181
      try {
182
        stmt = conn.createStatement();
183 174 bojilova
        stmt.execute("SELECT xml_nodes_id_seq.nextval FROM dual");
184 133 jones
        ResultSet rs = stmt.getResultSet();
185
        boolean tableHasRows = rs.next();
186
        if (tableHasRows) {
187 174 bojilova
          nid = rs.getLong(1);
188 19 jones
        }
189 133 jones
        stmt.close();
190
      } catch (SQLException e) {
191
        System.out.println("Error getting id: " + e.getMessage());
192 461 bojilova
        throw new SAXException(e.getMessage());
193 15 jones
      }
194
195 174 bojilova
      return nid;
196 133 jones
  }
197 18 jones
198 137 jones
  /** Add a new attribute to this node, or set its value */
199 461 bojilova
  public void setAttribute(String attName, String attValue, String docid)
200
              throws SAXException {
201 133 jones
    if (attName != null) {
202
      // Enter the attribute in the hash table
203
      super.setAttribute(attName, attValue);
204 18 jones
205 133 jones
      // And enter the attribute in the database
206 457 bojilova
      writeChildNodeToDB("ATTRIBUTE", attName, attValue, docid);
207 133 jones
    } else {
208
      System.err.println("Attribute name must not be null!");
209 461 bojilova
      throw new SAXException("Attribute name must not be null!");
210 18 jones
    }
211 133 jones
  }
212 176 jones
213
  /**
214 471 bojilova
   * NOT USED
215 176 jones
   * Update the node index (xml_index) for this node by generating
216
   * test strings that represent all of the relative and absolute
217
   * paths through the XML tree from document root to this node
218
   */
219 461 bojilova
  private void updateNodeIndex(String docid, String doctype)
220
               throws SAXException
221
  {
222 176 jones
    Hashtable pathlist = new Hashtable();
223
    boolean atStartingNode = true;
224
    boolean atRootDocumentNode = false;
225
    DBSAXNode nodePointer = this;
226
    StringBuffer currentPath = new StringBuffer();
227 457 bojilova
    int counter = 0;
228 176 jones
229
    // Create a Hashtable of all of the paths to reach this node
230
    // including absolute paths and relative paths
231
    while (!atRootDocumentNode) {
232
      if (atStartingNode) {
233
        currentPath.insert(0, nodePointer.getTagName());
234
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
235 457 bojilova
        counter++;
236 176 jones
        atStartingNode = false;
237
      } else {
238
        currentPath.insert(0, "/");
239
        currentPath.insert(0, nodePointer.getTagName());
240
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
241 457 bojilova
        counter++;
242 176 jones
      }
243
244
      // advance to the next parent node
245
      nodePointer = nodePointer.getParentNode();
246
247
      // If we're at the DOCUMENT node (root of DOM tree), add
248
      // the root "/" to make the absolute path
249
      if (nodePointer.getNodeType().equals("DOCUMENT")) {
250
        currentPath.insert(0, "/");
251
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
252 457 bojilova
        counter++;
253 176 jones
        atRootDocumentNode = true;
254
      }
255
    }
256
257
    try {
258
      // Create an insert statement to reuse for all of the path insertions
259
      PreparedStatement pstmt = conn.prepareStatement(
260 449 berkley
              "INSERT INTO xml_index (nodeid, path, docid, doctype, " +
261
               "parentnodeid) " +
262
              "VALUES (?, ?, ?, ?, ?)");
263 457 bojilova
      ((OraclePreparedStatement)pstmt).setExecuteBatch(counter);
264 176 jones
265 314 bojilova
      pstmt.setString(3, docid);
266
      pstmt.setString(4, doctype);
267 449 berkley
      pstmt.setLong(5, getParentID());
268 314 bojilova
269 176 jones
      // Step through the hashtable and insert each of the path values
270 471 bojilova
      Enumeration en = pathlist.keys();
271
      while (en.hasMoreElements()) {
272
        String path = (String)en.nextElement();
273
        Long nodeid = (Long)pathlist.get(path);
274
        pstmt.setLong(1, nodeid.longValue());
275
        pstmt.setString(2, path);
276
        pstmt.executeUpdate();
277
278
        //System.out.println(nodeid + " ==> " + path);
279
      }
280
281
      // Close the database statement
282
      pstmt.close();
283
    } catch (SQLException sqe) {
284
      System.err.println("SQL Exception while inserting path to index.");
285
      System.err.println(sqe.getMessage());
286
      throw new SAXException(sqe.getMessage());
287
    }
288
  }
289
290
  /**
291
   * USED FROM SEPARATE THREAD RUNNED from DBSAXHandler on endDocument()
292
   * Update the node index (xml_index) for this node by generating
293
   * test strings that represent all of the relative and absolute
294
   * paths through the XML tree from document root to this node
295
   */
296
  public void updateNodeIndex(Connection conn, String docid, String doctype)
297
               throws SAXException
298
  {
299
    Hashtable pathlist = new Hashtable();
300
    boolean atStartingNode = true;
301
    boolean atRootDocumentNode = false;
302
    DBSAXNode nodePointer = this;
303
    StringBuffer currentPath = new StringBuffer();
304
    int counter = 0;
305
306
    // Create a Hashtable of all of the paths to reach this node
307
    // including absolute paths and relative paths
308
    while (!atRootDocumentNode) {
309
      if (atStartingNode) {
310
        currentPath.insert(0, nodePointer.getTagName());
311
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
312
        counter++;
313
        atStartingNode = false;
314
      } else {
315
        currentPath.insert(0, "/");
316
        currentPath.insert(0, nodePointer.getTagName());
317
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
318
        counter++;
319
      }
320
321
      // advance to the next parent node
322
      nodePointer = nodePointer.getParentNode();
323
324
      // If we're at the DOCUMENT node (root of DOM tree), add
325
      // the root "/" to make the absolute path
326
      if (nodePointer.getNodeType().equals("DOCUMENT")) {
327
        currentPath.insert(0, "/");
328
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
329
        counter++;
330
        atRootDocumentNode = true;
331
      }
332
    }
333
334
    try {
335
      // Create an insert statement to reuse for all of the path insertions
336
      PreparedStatement pstmt = conn.prepareStatement(
337
              "INSERT INTO xml_index (nodeid, path, docid, doctype, " +
338
               "parentnodeid) " +
339
              "VALUES (?, ?, ?, ?, ?)");
340
      ((OraclePreparedStatement)pstmt).setExecuteBatch(counter);
341
342
      pstmt.setString(3, docid);
343
      pstmt.setString(4, doctype);
344
      pstmt.setLong(5, getParentID());
345
346
      // Step through the hashtable and insert each of the path values
347 176 jones
      Enumeration en = pathlist.keys();
348
      while (en.hasMoreElements()) {
349
        String path = (String)en.nextElement();
350
        Long nodeid = (Long)pathlist.get(path);
351
        pstmt.setLong(1, nodeid.longValue());
352
        pstmt.setString(2, path);
353 457 bojilova
        pstmt.executeUpdate();
354 176 jones
355
        //System.out.println(nodeid + " ==> " + path);
356
      }
357
358
      // Close the database statement
359
      pstmt.close();
360
    } catch (SQLException sqe) {
361
      System.err.println("SQL Exception while inserting path to index.");
362
      System.err.println(sqe.getMessage());
363 461 bojilova
      throw new SAXException(sqe.getMessage());
364 176 jones
    }
365
  }
366
367
  /** get the parent of this node */
368
  public DBSAXNode getParentNode() {
369
    return parentNode;
370
  }
371 15 jones
}