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-06-01 12:12:16 -0700 (Fri, 01 Jun 2001) $'
11
 * '$Revision: 763 $'
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.DBAdapter;
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 DBAdapter 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
          if ( nodetype == "TEXT" && getTagName().equals("meta_file_id") ) {
130
            pstmt.setString(6, getDocID());
131
          } else {
132
            pstmt.setString(6, data);
133
          }  
134
          pstmt.setInt(7, incChildNum());
135
        }
136
      }
137
      // Do the insertion
138
      pstmt.execute();
139
      pstmt.close();
140

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

    
149
      if (nodetype.equals("DOCUMENT") || nodetype.equals("ELEMENT")) {
150

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

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

    
157
      }
158

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

    
169
  /** 
170
   * update rootnodeid=nodeid for 'DOCUMENT' type of nodes only
171
   */
172
  public void updateRootNodeID(long nodeid) throws SAXException {
173
      try {
174
        PreparedStatement pstmt;
175
        pstmt = conn.prepareStatement(
176
              "UPDATE xml_nodes set rootnodeid = ? " +
177
              "WHERE nodeid = ?");
178

    
179
        // Bind the values to the query
180
        pstmt.setLong(1, nodeid);
181
        pstmt.setLong(2, nodeid);
182
        // Do the update
183
        pstmt.execute();
184
        pstmt.close();
185
      } catch (SQLException e) {
186
        System.out.println("Error in DBSaxNode.updateRootNodeID: " + 
187
                           e.getMessage());
188
        throw new SAXException(e.getMessage());
189
      }
190
  }
191

    
192
  /** 
193
   * creates SQL code to put nodename for the document node 
194
   * into DB connection 
195
   */
196
  public void writeNodename(String nodename) throws SAXException {
197
      try {
198
        PreparedStatement pstmt;
199
        pstmt = conn.prepareStatement(
200
              "UPDATE xml_nodes set nodename = ? " +
201
              "WHERE nodeid = ?");
202

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

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

    
235
      return nid;
236
  }
237

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

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

    
253
  /** 
254
   * NOT USED
255
   * Update the node index (xml_index) for this node by generating
256
   * test strings that represent all of the relative and absolute
257
   * paths through the XML tree from document root to this node
258
   */
259
  private void updateNodeIndex(String docid, String doctype) 
260
               throws SAXException
261
  {
262
    Hashtable pathlist = new Hashtable();
263
    boolean atStartingNode = true;
264
    boolean atRootDocumentNode = false;
265
    DBSAXNode nodePointer = this;
266
    StringBuffer currentPath = new StringBuffer();
267
    int counter = 0;
268

    
269
    // Create a Hashtable of all of the paths to reach this node
270
    // including absolute paths and relative paths
271
    while (!atRootDocumentNode) {
272
      if (atStartingNode) {
273
        currentPath.insert(0, nodePointer.getTagName());
274
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
275
        counter++;
276
        atStartingNode = false;
277
      } else {
278
        currentPath.insert(0, "/");
279
        currentPath.insert(0, nodePointer.getTagName());
280
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
281
        counter++;
282
      }
283

    
284
      // advance to the next parent node
285
      nodePointer = nodePointer.getParentNode();
286

    
287
      // If we're at the DOCUMENT node (root of DOM tree), add
288
      // the root "/" to make the absolute path
289
      if (nodePointer.getNodeType().equals("DOCUMENT")) {
290
        currentPath.insert(0, "/");
291
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
292
        counter++;
293
        atRootDocumentNode = true;
294
      } 
295
    }
296

    
297
    try {
298
      // Create an insert statement to reuse for all of the path insertions
299
      PreparedStatement pstmt = conn.prepareStatement(
300
              "INSERT INTO xml_index (nodeid, path, docid, doctype, " + 
301
               "parentnodeid) " + 
302
              "VALUES (?, ?, ?, ?, ?)");
303
      //((OraclePreparedStatement)pstmt).setExecuteBatch(counter);
304
  
305
      pstmt.setString(3, docid);
306
      pstmt.setString(4, doctype);
307
      pstmt.setLong(5, getParentID());
308
      
309
      // Step through the hashtable and insert each of the path values
310
      Enumeration en = pathlist.keys();
311
      while (en.hasMoreElements()) {
312
        String path = (String)en.nextElement();
313
        Long nodeid = (Long)pathlist.get(path);
314
        pstmt.setLong(1, nodeid.longValue());
315
        pstmt.setString(2, path);
316
        pstmt.executeUpdate();
317
  
318
        //System.out.println(nodeid + " ==> " + path);
319
      }
320

    
321
      // Close the database statement
322
      pstmt.close();
323
    } catch (SQLException sqe) {
324
      System.err.println("SQL Exception while inserting path to index in " + 
325
                         "DBSAXNode.updateNodeIndex");
326
      System.err.println(sqe.getMessage());
327
      throw new SAXException(sqe.getMessage());
328
    }
329
  }
330

    
331
  /** 
332
   * USED FROM SEPARATE THREAD RUNNED from DBSAXHandler on endDocument()
333
   * Update the node index (xml_index) for this node by generating
334
   * test strings that represent all of the relative and absolute
335
   * paths through the XML tree from document root to this node
336
   */
337
  public void updateNodeIndex(Connection conn, String docid, String doctype) 
338
               throws SAXException
339
  {
340
    Hashtable pathlist = new Hashtable();
341
    boolean atStartingNode = true;
342
    boolean atRootDocumentNode = false;
343
    DBSAXNode nodePointer = this;
344
    StringBuffer currentPath = new StringBuffer();
345
    int counter = 0;
346

    
347
    // Create a Hashtable of all of the paths to reach this node
348
    // including absolute paths and relative paths
349
    while (!atRootDocumentNode) {
350
      if (atStartingNode) {
351
        currentPath.insert(0, nodePointer.getTagName());
352
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
353
        counter++;
354
        atStartingNode = false;
355
      } else {
356
        currentPath.insert(0, "/");
357
        currentPath.insert(0, nodePointer.getTagName());
358
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
359
        counter++;
360
      }
361

    
362
      // advance to the next parent node
363
      nodePointer = nodePointer.getParentNode();
364

    
365
      // If we're at the DOCUMENT node (root of DOM tree), add
366
      // the root "/" to make the absolute path
367
      if (nodePointer.getNodeType().equals("DOCUMENT")) {
368
        currentPath.insert(0, "/");
369
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
370
        counter++;
371
        atRootDocumentNode = true;
372
      } 
373
    }
374

    
375
    try {
376
      // Create an insert statement to reuse for all of the path insertions
377
      PreparedStatement pstmt = conn.prepareStatement(
378
              "INSERT INTO xml_index (nodeid, path, docid, doctype, " + 
379
               "parentnodeid) " + 
380
              "VALUES (?, ?, ?, ?, ?)");
381
      //((OraclePreparedStatement)pstmt).setExecuteBatch(counter);
382
  
383
      pstmt.setString(3, docid);
384
      pstmt.setString(4, doctype);
385
      pstmt.setLong(5, getParentID());
386
      
387
      // Step through the hashtable and insert each of the path values
388
      Enumeration en = pathlist.keys();
389
      while (en.hasMoreElements()) {
390
        String path = (String)en.nextElement();
391
        Long nodeid = (Long)pathlist.get(path);
392
        pstmt.setLong(1, nodeid.longValue());
393
        pstmt.setString(2, path);
394
        pstmt.executeUpdate();
395
  
396
        //System.out.println(nodeid + " ==> " + path);
397
      }
398

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