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: berkley $'
10
 *     '$Date: 2002-01-29 10:15:11 -0800 (Tue, 29 Jan 2002) $'
11
 * '$Revision: 915 $'
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 qName, String lName,
71
                    DBSAXNode parentNode, long rootnodeid, 
72
                    String docid, String doctype) 
73
                                               throws SAXException {
74

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

    
107
      // Bind the values to the query
108
      pstmt.setString(1, nodetype);
109
      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
      if (nodetype == "DOCUMENT") {
119
        // moved it to separate method updateRootNodeID
120
        //pstmt.setLong(4, nid);
121
      } else {
122
        if (nodetype == "ELEMENT") {
123
          pstmt.setLong(5, getRootNodeID());
124
          pstmt.setLong(6, getParentID());
125
          pstmt.setString(7, data);
126
          pstmt.setInt(8, getNodeIndex());
127
        } else {
128
          pstmt.setLong(5, getRootNodeID());
129
          pstmt.setLong(6, getNodeID());
130
          pstmt.setString(7, data);
131
          pstmt.setInt(8, incChildNum());
132
        }
133
      }
134
      // Do the insertion
135
      pstmt.execute();
136
      pstmt.close();
137

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

    
146
      if (nodetype.equals("DOCUMENT") || nodetype.equals("ELEMENT")) {
147

    
148
        // Record the node id that was generated from the database
149
        setNodeID(nid);
150

    
151
        // Record the node type that was passed to the method
152
        setNodeType(nodetype);
153

    
154
      }
155

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

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

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

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

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

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

    
233
      return nid;
234
  }
235

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

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

    
251
  /** Add a namespace to this node */
252
  public void setNamespace(String prefix, String uri, String docid)
253
              throws SAXException {
254
    if (prefix != null) {
255
      // Enter the namespace in a hash table
256
      super.setNamespace(prefix, uri);
257
      // And enter the namespace in the database
258
      writeChildNodeToDB("NAMESPACE", prefix, uri, docid);
259
    } else {
260
      System.err.println("Namespace prefix must not be null!");
261
      throw new SAXException("Namespace prefix must not be null!");
262
    }
263
  }
264

    
265
  /** 
266
   * NOT USED
267
   * Update the node index (xml_index) for this node by generating
268
   * test strings that represent all of the relative and absolute
269
   * paths through the XML tree from document root to this node
270
   */
271
  private void updateNodeIndex(String docid, String doctype) 
272
               throws SAXException
273
  {
274
    Hashtable pathlist = new Hashtable();
275
    boolean atStartingNode = true;
276
    boolean atRootDocumentNode = false;
277
    DBSAXNode nodePointer = this;
278
    StringBuffer currentPath = new StringBuffer();
279
    int counter = 0;
280

    
281
    // Create a Hashtable of all of the paths to reach this node
282
    // including absolute paths and relative paths
283
    while (!atRootDocumentNode) {
284
      if (atStartingNode) {
285
        currentPath.insert(0, nodePointer.getTagName());
286
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
287
        counter++;
288
        atStartingNode = false;
289
      } else {
290
        currentPath.insert(0, "/");
291
        currentPath.insert(0, nodePointer.getTagName());
292
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
293
        counter++;
294
      }
295

    
296
      // advance to the next parent node
297
      nodePointer = nodePointer.getParentNode();
298

    
299
      // If we're at the DOCUMENT node (root of DOM tree), add
300
      // the root "/" to make the absolute path
301
      if (nodePointer.getNodeType().equals("DOCUMENT")) {
302
        currentPath.insert(0, "/");
303
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
304
        counter++;
305
        atRootDocumentNode = true;
306
      } 
307
    }
308

    
309
    try {
310
      // Create an insert statement to reuse for all of the path insertions
311
      PreparedStatement pstmt = conn.prepareStatement(
312
              "INSERT INTO xml_index (nodeid, path, docid, doctype, " + 
313
               "parentnodeid) " + 
314
              "VALUES (?, ?, ?, ?, ?)");
315
      //((OraclePreparedStatement)pstmt).setExecuteBatch(counter);
316
  
317
      pstmt.setString(3, docid);
318
      pstmt.setString(4, doctype);
319
      pstmt.setLong(5, getParentID());
320
      
321
      // Step through the hashtable and insert each of the path values
322
      Enumeration en = pathlist.keys();
323
      while (en.hasMoreElements()) {
324
        String path = (String)en.nextElement();
325
        Long nodeid = (Long)pathlist.get(path);
326
        pstmt.setLong(1, nodeid.longValue());
327
        pstmt.setString(2, path);
328
        pstmt.executeUpdate();
329
  
330
        //System.out.println(nodeid + " ==> " + path);
331
      }
332

    
333
      // Close the database statement
334
      pstmt.close();
335
    } catch (SQLException sqe) {
336
      System.err.println("SQL Exception while inserting path to index in " + 
337
                         "DBSAXNode.updateNodeIndex");
338
      System.err.println(sqe.getMessage());
339
      throw new SAXException(sqe.getMessage());
340
    }
341
  }
342

    
343
  /** 
344
   * USED FROM SEPARATE THREAD RUNNED from DBSAXHandler on endDocument()
345
   * Update the node index (xml_index) for this node by generating
346
   * test strings that represent all of the relative and absolute
347
   * paths through the XML tree from document root to this node
348
   */
349
  public void updateNodeIndex(Connection conn, String docid, String doctype) 
350
               throws SAXException
351
  {
352
    Hashtable pathlist = new Hashtable();
353
    boolean atStartingNode = true;
354
    boolean atRootDocumentNode = false;
355
    DBSAXNode nodePointer = this;
356
    StringBuffer currentPath = new StringBuffer();
357
    int counter = 0;
358

    
359
    // Create a Hashtable of all of the paths to reach this node
360
    // including absolute paths and relative paths
361
    while (!atRootDocumentNode) {
362
      if (atStartingNode) {
363
        currentPath.insert(0, nodePointer.getTagName());
364
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
365
        counter++;
366
        atStartingNode = false;
367
      } else {
368
        currentPath.insert(0, "/");
369
        currentPath.insert(0, nodePointer.getTagName());
370
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
371
        counter++;
372
      }
373

    
374
      // advance to the next parent node
375
      nodePointer = nodePointer.getParentNode();
376

    
377
      // If we're at the DOCUMENT node (root of DOM tree), add
378
      // the root "/" to make the absolute path
379
      if (nodePointer.getNodeType().equals("DOCUMENT")) {
380
        currentPath.insert(0, "/");
381
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
382
        counter++;
383
        atRootDocumentNode = true;
384
      } 
385
    }
386

    
387
    try {
388
      // Create an insert statement to reuse for all of the path insertions
389
      PreparedStatement pstmt = conn.prepareStatement(
390
              "INSERT INTO xml_index (nodeid, path, docid, doctype, " + 
391
               "parentnodeid) " + 
392
              "VALUES (?, ?, ?, ?, ?)");
393
  
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
      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
        
406
        pstmt.executeUpdate();
407
      }
408
      // Close the database statement
409
      pstmt.close();
410
    } catch (SQLException sqe) {
411
      System.err.println("SQL Exception while inserting path to index in " +
412
                         "DBSAXNode.updateNodeIndex for document " + docid);
413
      System.err.println(sqe.getMessage());
414
      throw new SAXException(sqe.getMessage());
415
    }
416
  }
417
 
418
  /** get the parent of this node */
419
  public DBSAXNode getParentNode() {
420
    return parentNode;
421
  }
422
}
(16-16/40)