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: 2001-01-18 15:15:21 -0800 (Thu, 18 Jan 2001) $'
11
 * '$Revision: 675 $'
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
/** 
38
 * A Class that represents an XML node and its contents and
39
 * can write its own representation to a database connection
40
 */
41
public class DBSAXNode extends BasicNode {
42

    
43
  private Connection	conn;
44
  private DBSAXNode	parentNode;
45

    
46
  /** 
47
   * Construct a new node instance for DOCUMENT nodes
48
   *
49
   * @param conn the JDBC Connection to which all information is written
50
   */
51
  public DBSAXNode (Connection conn, String docid) throws SAXException {
52
    super();
53
    this.conn = conn;
54
    this.parentNode = null;
55
    writeChildNodeToDB("DOCUMENT", null, null, docid);
56
  }
57

    
58
  /** 
59
   * Construct a new node instance for ELEMENT nodes
60
   *
61
   * @param conn the JDBC Connection to which all information is written
62
   * @param tagname the name of the node
63
   * @param parentNode the parent node for this node being created
64
   */
65
  public DBSAXNode (Connection conn, String tagname, DBSAXNode parentNode, 
66
                    long rootnodeid, String docid, String doctype) 
67
                    throws SAXException {
68

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

    
101
      // Bind the values to the query
102
      long nid = generateNodeID();
103
      pstmt.setLong(1, nid);
104
      pstmt.setString(2, nodetype);
105
      pstmt.setString(3, nodename);
106
      pstmt.setString(4, docid);
107
      if (nodetype == "DOCUMENT") {
108
        pstmt.setLong(5, nid);
109
      } else {
110
        if (nodetype == "ELEMENT") {
111
          pstmt.setLong(5, getRootNodeID());
112
          pstmt.setLong(6, getParentID());
113
          pstmt.setString(7, data);
114
          pstmt.setInt(8, getNodeIndex());
115
        } else {
116
          pstmt.setLong(5, getRootNodeID());
117
          pstmt.setLong(6, getNodeID());
118
          if ( nodetype == "TEXT" && getTagName().equals("meta_file_id") ) {
119
            pstmt.setString(7, getDocID());
120
          } else {
121
            pstmt.setString(7, data);
122
          }  
123
          pstmt.setInt(8, incChildNum());
124
        }
125
      }
126
      // Do the insertion
127
      pstmt.execute();
128
      pstmt.close();
129
      
130
      if (nodetype.equals("DOCUMENT")) {
131
        // Record the root node id that was generated from the database
132
        setRootNodeID(nid);
133
      }
134

    
135
      if (nodetype.equals("DOCUMENT") || nodetype.equals("ELEMENT")) {
136

    
137
        // Record the node id that was generated from the database
138
        setNodeID(nid);
139

    
140
        // Record the node type that was passed to the method
141
        setNodeType(nodetype);
142

    
143
      }
144

    
145
    } catch (SQLException e) {
146
      System.out.println("Error in DBSaxNode.writeChildNodeToDB");
147
      System.err.println("Error inserting node: (" + nodetype + ", " +
148
                                                     nodename + ", " + 
149
                                                     data + ")" );
150
      System.err.println(e.getMessage());
151
      throw new SAXException(e.getMessage());
152
    }
153
  }
154

    
155
  /** 
156
   * creates SQL code to put nodename for the document node 
157
   * into DB connection 
158
   */
159
  public void writeNodename(String nodename) throws SAXException {
160
      try {
161
        PreparedStatement pstmt;
162
        pstmt = conn.prepareStatement(
163
              "UPDATE xml_nodes set nodename = ? " +
164
              "WHERE nodeid = ?");
165

    
166
        // Bind the values to the query
167
        pstmt.setString(1, nodename);
168
        pstmt.setLong(2, getNodeID());
169
        // Do the insertion
170
        pstmt.execute();
171
        pstmt.close();
172
      } catch (SQLException e) {
173
        System.out.println("Error in DBSaxNode.writeNodeName: " + 
174
                           e.getMessage());
175
        throw new SAXException(e.getMessage());
176
      }
177
  }
178

    
179
  /** get next node id from DB connection */
180
  private long generateNodeID() throws SAXException {
181
      long nid=0;
182
      Statement stmt;
183
      try {
184
        stmt = conn.createStatement();
185
        stmt.execute("SELECT xml_nodes_id_seq.nextval FROM dual");
186
        ResultSet rs = stmt.getResultSet();
187
        boolean tableHasRows = rs.next();
188
        if (tableHasRows) {
189
          nid = rs.getLong(1);
190
        }
191
        stmt.close();
192
      } catch (SQLException e) {
193
        System.out.println("Error in DBSaxNode.generateNodeID: " + 
194
                            e.getMessage());
195
        throw new SAXException(e.getMessage());
196
      }
197

    
198
      return nid;
199
  }
200

    
201
  /** Add a new attribute to this node, or set its value */
202
  public void setAttribute(String attName, String attValue, String docid)
203
              throws SAXException {
204
    if (attName != null) {
205
      // Enter the attribute in the hash table
206
      super.setAttribute(attName, attValue);
207

    
208
      // And enter the attribute in the database
209
      writeChildNodeToDB("ATTRIBUTE", attName, attValue, docid);
210
    } else {
211
      System.err.println("Attribute name must not be null!");
212
      throw new SAXException("Attribute name must not be null!");
213
    }
214
  }
215

    
216
  /** 
217
   * NOT USED
218
   * Update the node index (xml_index) for this node by generating
219
   * test strings that represent all of the relative and absolute
220
   * paths through the XML tree from document root to this node
221
   */
222
  private void updateNodeIndex(String docid, String doctype) 
223
               throws SAXException
224
  {
225
    Hashtable pathlist = new Hashtable();
226
    boolean atStartingNode = true;
227
    boolean atRootDocumentNode = false;
228
    DBSAXNode nodePointer = this;
229
    StringBuffer currentPath = new StringBuffer();
230
    int counter = 0;
231

    
232
    // Create a Hashtable of all of the paths to reach this node
233
    // including absolute paths and relative paths
234
    while (!atRootDocumentNode) {
235
      if (atStartingNode) {
236
        currentPath.insert(0, nodePointer.getTagName());
237
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
238
        counter++;
239
        atStartingNode = false;
240
      } else {
241
        currentPath.insert(0, "/");
242
        currentPath.insert(0, nodePointer.getTagName());
243
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
244
        counter++;
245
      }
246

    
247
      // advance to the next parent node
248
      nodePointer = nodePointer.getParentNode();
249

    
250
      // If we're at the DOCUMENT node (root of DOM tree), add
251
      // the root "/" to make the absolute path
252
      if (nodePointer.getNodeType().equals("DOCUMENT")) {
253
        currentPath.insert(0, "/");
254
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
255
        counter++;
256
        atRootDocumentNode = true;
257
      } 
258
    }
259

    
260
    try {
261
      // Create an insert statement to reuse for all of the path insertions
262
      PreparedStatement pstmt = conn.prepareStatement(
263
              "INSERT INTO xml_index (nodeid, path, docid, doctype, " + 
264
               "parentnodeid) " + 
265
              "VALUES (?, ?, ?, ?, ?)");
266
      ((OraclePreparedStatement)pstmt).setExecuteBatch(counter);
267
  
268
      pstmt.setString(3, docid);
269
      pstmt.setString(4, doctype);
270
      pstmt.setLong(5, getParentID());
271
      
272
      // Step through the hashtable and insert each of the path values
273
      Enumeration en = pathlist.keys();
274
      while (en.hasMoreElements()) {
275
        String path = (String)en.nextElement();
276
        Long nodeid = (Long)pathlist.get(path);
277
        pstmt.setLong(1, nodeid.longValue());
278
        pstmt.setString(2, path);
279
        pstmt.executeUpdate();
280
  
281
        //System.out.println(nodeid + " ==> " + path);
282
      }
283

    
284
      // Close the database statement
285
      pstmt.close();
286
    } catch (SQLException sqe) {
287
      System.err.println("SQL Exception while inserting path to index in " + 
288
                         "DBSAXNode.updateNodeIndex");
289
      System.err.println(sqe.getMessage());
290
      throw new SAXException(sqe.getMessage());
291
    }
292
  }
293

    
294
  /** 
295
   * USED FROM SEPARATE THREAD RUNNED from DBSAXHandler on endDocument()
296
   * Update the node index (xml_index) for this node by generating
297
   * test strings that represent all of the relative and absolute
298
   * paths through the XML tree from document root to this node
299
   */
300
  public void updateNodeIndex(Connection conn, String docid, String doctype) 
301
               throws SAXException
302
  {
303
    Hashtable pathlist = new Hashtable();
304
    boolean atStartingNode = true;
305
    boolean atRootDocumentNode = false;
306
    DBSAXNode nodePointer = this;
307
    StringBuffer currentPath = new StringBuffer();
308
    int counter = 0;
309

    
310
    // Create a Hashtable of all of the paths to reach this node
311
    // including absolute paths and relative paths
312
    while (!atRootDocumentNode) {
313
      if (atStartingNode) {
314
        currentPath.insert(0, nodePointer.getTagName());
315
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
316
        counter++;
317
        atStartingNode = false;
318
      } else {
319
        currentPath.insert(0, "/");
320
        currentPath.insert(0, nodePointer.getTagName());
321
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
322
        counter++;
323
      }
324

    
325
      // advance to the next parent node
326
      nodePointer = nodePointer.getParentNode();
327

    
328
      // If we're at the DOCUMENT node (root of DOM tree), add
329
      // the root "/" to make the absolute path
330
      if (nodePointer.getNodeType().equals("DOCUMENT")) {
331
        currentPath.insert(0, "/");
332
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
333
        counter++;
334
        atRootDocumentNode = true;
335
      } 
336
    }
337

    
338
    try {
339
      // Create an insert statement to reuse for all of the path insertions
340
      PreparedStatement pstmt = conn.prepareStatement(
341
              "INSERT INTO xml_index (nodeid, path, docid, doctype, " + 
342
               "parentnodeid) " + 
343
              "VALUES (?, ?, ?, ?, ?)");
344
      ((OraclePreparedStatement)pstmt).setExecuteBatch(counter);
345
  
346
      pstmt.setString(3, docid);
347
      pstmt.setString(4, doctype);
348
      pstmt.setLong(5, getParentID());
349
      
350
      // Step through the hashtable and insert each of the path values
351
      Enumeration en = pathlist.keys();
352
      while (en.hasMoreElements()) {
353
        String path = (String)en.nextElement();
354
        Long nodeid = (Long)pathlist.get(path);
355
        pstmt.setLong(1, nodeid.longValue());
356
        pstmt.setString(2, path);
357
        pstmt.executeUpdate();
358
  
359
        //System.out.println(nodeid + " ==> " + path);
360
      }
361

    
362
      // Close the database statement
363
      pstmt.close();
364
    } catch (SQLException sqe) {
365
      System.err.println("SQL Exception while inserting path to index in " +
366
                         "DBSAXNode.updateNodeIndex");
367
      System.err.println(sqe.getMessage());
368
      throw new SAXException(sqe.getMessage());
369
    }
370
  }
371
 
372
  /** get the parent of this node */
373
  public DBSAXNode getParentNode() {
374
    return parentNode;
375
  }
376
}
(16-16/43)