Project

General

Profile

1
/**
2
 *  '$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
 *    Release: @release@
8
 *
9
 *   '$Author: bojilova $'
10
 *     '$Date: 2001-07-13 12:17:23 -0700 (Fri, 13 Jul 2001) $'
11
 * '$Revision: 792 $'
12
 *
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
 */
27

    
28
package edu.ucsb.nceas.metacat;
29

    
30
import java.sql.*;
31
import java.io.IOException;
32
import java.util.Hashtable;
33
import java.util.Enumeration;
34
//import oracle.jdbc.driver.*;
35
import org.xml.sax.SAXException;
36

    
37
import edu.ucsb.nceas.dbadapter.AbstractDatabase;
38

    
39
/** 
40
 * A Class that represents an XML node and its contents and
41
 * can write its own representation to a database connection
42
 */
43
public class DBSAXNode extends BasicNode {
44

    
45
  private Connection	conn;
46
  private DBSAXNode	parentNode;
47
  private static final AbstractDatabase dbAdapter = MetaCatUtil.dbAdapter;
48

    
49
  /** 
50
   * Construct a new node instance for DOCUMENT nodes
51
   *
52
   * @param conn the JDBC Connection to which all information is written
53
   */
54
  public DBSAXNode (Connection conn, String docid) throws SAXException {
55

    
56
    super();
57
    this.conn = conn;
58
    this.parentNode = null;
59
    writeChildNodeToDB("DOCUMENT", null, null, docid);
60
    updateRootNodeID(getNodeID());
61
  }
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
  public DBSAXNode (Connection conn, String tagname, DBSAXNode parentNode, 
71
                    long rootnodeid, String docid, String doctype) 
72
                    throws SAXException {
73

    
74
    super(tagname);
75
    this.conn = conn;
76
    this.parentNode = parentNode;
77
    setParentID(parentNode.getNodeID());
78
    setRootNodeID(rootnodeid);
79
    setDocID(docid);
80
    setNodeIndex(parentNode.incChildNum());
81
    writeChildNodeToDB("ELEMENT", getTagName(), null, docid);
82
    //No writing XML Index from here. New Thread used instead.
83
    //updateNodeIndex(docid, doctype);
84
  }
85
    
86
  /** creates SQL code and inserts new node into DB connection */
87
  public void writeChildNodeToDB(String nodetype, String nodename,
88
                                 String data, String docid) 
89
                                 throws SAXException {
90
    try {
91
      PreparedStatement pstmt;
92
      if (nodetype == "DOCUMENT") {
93
        pstmt = conn.prepareStatement(
94
            "INSERT INTO xml_nodes " +
95
            "(nodetype, nodename, docid) " +
96
            "VALUES (?, ?, ?)");
97
        MetaCatUtil.debugMessage("INSERTING DOCNAME: " + nodename);
98
      } else {
99
        pstmt = conn.prepareStatement(
100
            "INSERT INTO xml_nodes " +
101
            "(nodetype, nodename, docid, " +
102
            "rootnodeid, parentnodeid, nodedata, nodeindex) " +
103
            "VALUES (?, ?, ?, ?, ?, ?, ?)");
104
      }
105

    
106
      // Bind the values to the query
107
      // NOT USED; USED DBAdapter.getUniqueID() instead
108
      //long nid = generateNodeID();
109
      // 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
      if (nodetype == "DOCUMENT") {
118
        // moved it to separate method updateRootNodeID
119
        //pstmt.setLong(4, nid);
120
      } else {
121
        if (nodetype == "ELEMENT") {
122
          pstmt.setLong(4, getRootNodeID());
123
          pstmt.setLong(5, getParentID());
124
          pstmt.setString(6, data);
125
          pstmt.setInt(7, getNodeIndex());
126
        } else {
127
          pstmt.setLong(4, getRootNodeID());
128
          pstmt.setLong(5, getNodeID());
129
          // 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
            pstmt.setString(6, data);
135
          //}  
136
          pstmt.setInt(7, incChildNum());
137
        }
138
      }
139
      // Do the insertion
140
      pstmt.execute();
141
      pstmt.close();
142

    
143
      // get the generated unique id afterward
144
      long nid = dbAdapter.getUniqueID(conn, "xml_nodes");
145
      
146
      if (nodetype.equals("DOCUMENT")) {
147
        // Record the root node id that was generated from the database
148
        setRootNodeID(nid);
149
      }
150

    
151
      if (nodetype.equals("DOCUMENT") || nodetype.equals("ELEMENT")) {
152

    
153
        // Record the node id that was generated from the database
154
        setNodeID(nid);
155

    
156
        // Record the node type that was passed to the method
157
        setNodeType(nodetype);
158

    
159
      }
160

    
161
    } catch (SQLException e) {
162
      System.out.println("Error in DBSaxNode.writeChildNodeToDB");
163
      System.err.println("Error inserting node: (" + nodetype + ", " +
164
                                                     nodename + ", " + 
165
                                                     data + ")" );
166
      System.err.println(e.getMessage());
167
      throw new SAXException(e.getMessage());
168
    }
169
  }
170

    
171
  /** 
172
   * 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
   * creates SQL code to put nodename for the document node 
196
   * into DB connection 
197
   */
198
  public void writeNodename(String nodename) throws SAXException {
199
      try {
200
        PreparedStatement pstmt;
201
        pstmt = conn.prepareStatement(
202
              "UPDATE xml_nodes set nodename = ? " +
203
              "WHERE nodeid = ?");
204

    
205
        // Bind the values to the query
206
        pstmt.setString(1, nodename);
207
        pstmt.setLong(2, getNodeID());
208
        // Do the insertion
209
        pstmt.execute();
210
        pstmt.close();
211
      } catch (SQLException e) {
212
        System.out.println("Error in DBSaxNode.writeNodeName: " + 
213
                           e.getMessage());
214
        throw new SAXException(e.getMessage());
215
      }
216
  }
217

    
218
  /** get next node id from DB connection */
219
  private long generateNodeID() throws SAXException {
220
      long nid=0;
221
      Statement stmt;
222
      try {
223
        stmt = conn.createStatement();
224
        stmt.execute("SELECT xml_nodes_id_seq.nextval FROM dual");
225
        ResultSet rs = stmt.getResultSet();
226
        boolean tableHasRows = rs.next();
227
        if (tableHasRows) {
228
          nid = rs.getLong(1);
229
        }
230
        stmt.close();
231
      } catch (SQLException e) {
232
        System.out.println("Error in DBSaxNode.generateNodeID: " + 
233
                            e.getMessage());
234
        throw new SAXException(e.getMessage());
235
      }
236

    
237
      return nid;
238
  }
239

    
240
  /** Add a new attribute to this node, or set its value */
241
  public void setAttribute(String attName, String attValue, String docid)
242
              throws SAXException {
243
    if (attName != null) {
244
      // Enter the attribute in the hash table
245
      super.setAttribute(attName, attValue);
246

    
247
      // And enter the attribute in the database
248
      writeChildNodeToDB("ATTRIBUTE", attName, attValue, docid);
249
    } else {
250
      System.err.println("Attribute name must not be null!");
251
      throw new SAXException("Attribute name must not be null!");
252
    }
253
  }
254

    
255
  /** 
256
   * NOT USED
257
   * 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
  private void updateNodeIndex(String docid, String doctype) 
262
               throws SAXException
263
  {
264
    Hashtable pathlist = new Hashtable();
265
    boolean atStartingNode = true;
266
    boolean atRootDocumentNode = false;
267
    DBSAXNode nodePointer = this;
268
    StringBuffer currentPath = new StringBuffer();
269
    int counter = 0;
270

    
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
        counter++;
278
        atStartingNode = false;
279
      } else {
280
        currentPath.insert(0, "/");
281
        currentPath.insert(0, nodePointer.getTagName());
282
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
283
        counter++;
284
      }
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
        counter++;
295
        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
              "INSERT INTO xml_index (nodeid, path, docid, doctype, " + 
303
               "parentnodeid) " + 
304
              "VALUES (?, ?, ?, ?, ?)");
305
      //((OraclePreparedStatement)pstmt).setExecuteBatch(counter);
306
  
307
      pstmt.setString(3, docid);
308
      pstmt.setString(4, doctype);
309
      pstmt.setLong(5, getParentID());
310
      
311
      // Step through the hashtable and insert each of the path values
312
      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
      System.err.println("SQL Exception while inserting path to index in " + 
327
                         "DBSAXNode.updateNodeIndex");
328
      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
      //((OraclePreparedStatement)pstmt).setExecuteBatch(counter);
384
  
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
      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
        pstmt.executeUpdate();
397
  
398
        //System.out.println(nodeid + " ==> " + path);
399
      }
400

    
401
      // Close the database statement
402
      pstmt.close();
403
    } catch (SQLException sqe) {
404
      System.err.println("SQL Exception while inserting path to index in " +
405
                         "DBSAXNode.updateNodeIndex");
406
      System.err.println(sqe.getMessage());
407
      throw new SAXException(sqe.getMessage());
408
    }
409
  }
410
 
411
  /** get the parent of this node */
412
  public DBSAXNode getParentNode() {
413
    return parentNode;
414
  }
415
}
(16-16/40)