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