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