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-04-10 15:18:30 -0700 (Wed, 10 Apr 2002) $'
11
 * '$Revision: 1001 $'
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
      if(conn == null)
93
      {
94
        try
95
        {
96
          MetaCatUtil util = new MetaCatUtil();
97
          conn = util.getConnection();
98
        }
99
        catch(Exception e)
100
        {
101
          MetaCatUtil.debug("Error while getting db connection in " +
102
                            "DBSAXNode: " + e.getMessage());
103
        }
104
      }
105
        
106
      PreparedStatement pstmt;
107
      if (nodetype == "DOCUMENT") {
108
        pstmt = conn.prepareStatement(
109
            "INSERT INTO xml_nodes " +
110
            "(nodetype, nodename, nodeprefix, docid) " +
111
            "VALUES (?, ?, ?, ?)");
112
        MetaCatUtil.debugMessage("INSERTING DOCNAME: " + nodename);
113
      } else {
114
        pstmt = conn.prepareStatement(
115
            "INSERT INTO xml_nodes " +
116
            "(nodetype, nodename, nodeprefix, docid, " +
117
            "rootnodeid, parentnodeid, nodedata, nodeindex) " +
118
            "VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
119
      }
120

    
121
      // Bind the values to the query
122
      pstmt.setString(1, nodetype);
123
      int idx;
124
      if ( nodename != null && (idx = nodename.indexOf(":")) != -1 ) {
125
        pstmt.setString(2, nodename.substring(idx+1));
126
        pstmt.setString(3, nodename.substring(0,idx));
127
      } else {
128
        pstmt.setString(2, nodename);
129
        pstmt.setString(3, null);
130
      }
131
      pstmt.setString(4, docid);
132
      if (nodetype == "DOCUMENT") {
133
        // moved it to separate method updateRootNodeID
134
        //pstmt.setLong(4, nid);
135
      } else {
136
        if (nodetype == "ELEMENT") {
137
          pstmt.setLong(5, getRootNodeID());
138
          pstmt.setLong(6, getParentID());
139
          pstmt.setString(7, data);
140
          pstmt.setInt(8, getNodeIndex());
141
        } else {
142
          pstmt.setLong(5, getRootNodeID());
143
          pstmt.setLong(6, getNodeID());
144
          pstmt.setString(7, data);
145
          pstmt.setInt(8, incChildNum());
146
        }
147
      }
148
      // Do the insertion
149
      pstmt.execute();
150
      pstmt.close();
151

    
152
      // get the generated unique id afterward
153
      long nid = dbAdapter.getUniqueID(conn, "xml_nodes");
154
      
155
      if (nodetype.equals("DOCUMENT")) {
156
        // Record the root node id that was generated from the database
157
        setRootNodeID(nid);
158
      }
159

    
160
      if (nodetype.equals("DOCUMENT") || nodetype.equals("ELEMENT")) {
161

    
162
        // Record the node id that was generated from the database
163
        setNodeID(nid);
164

    
165
        // Record the node type that was passed to the method
166
        setNodeType(nodetype);
167

    
168
      }
169

    
170
    } catch (SQLException e) {
171
      System.out.println("Error in DBSaxNode.writeChildNodeToDB");
172
      System.err.println("Error inserting node: (" + nodetype + ", " +
173
                                                     nodename + ", " + 
174
                                                     data + ")" );
175
      System.err.println(e.getMessage());
176
      e.printStackTrace(System.err);
177
      throw new SAXException(e.getMessage());
178
    }
179
  }
180

    
181
  /** 
182
   * update rootnodeid=nodeid for 'DOCUMENT' type of nodes only
183
   */
184
  public void updateRootNodeID(long nodeid) throws SAXException {
185
      try {
186
        PreparedStatement pstmt;
187
        pstmt = conn.prepareStatement(
188
              "UPDATE xml_nodes set rootnodeid = ? " +
189
              "WHERE nodeid = ?");
190

    
191
        // Bind the values to the query
192
        pstmt.setLong(1, nodeid);
193
        pstmt.setLong(2, nodeid);
194
        // Do the update
195
        pstmt.execute();
196
        pstmt.close();
197
      } catch (SQLException e) {
198
        System.out.println("Error in DBSaxNode.updateRootNodeID: " + 
199
                           e.getMessage());
200
        throw new SAXException(e.getMessage());
201
      }
202
  }
203

    
204
  /** 
205
   * creates SQL code to put nodename for the document node 
206
   * into DB connection 
207
   */
208
  public void writeNodename(String nodename) throws SAXException {
209
      try {
210
        PreparedStatement pstmt;
211
        pstmt = conn.prepareStatement(
212
              "UPDATE xml_nodes set nodename = ? " +
213
              "WHERE nodeid = ?");
214

    
215
        // Bind the values to the query
216
        pstmt.setString(1, nodename);
217
        pstmt.setLong(2, getNodeID());
218
        // Do the insertion
219
        pstmt.execute();
220
        pstmt.close();
221
      } catch (SQLException e) {
222
        System.out.println("Error in DBSaxNode.writeNodeName: " + 
223
                           e.getMessage());
224
        throw new SAXException(e.getMessage());
225
      }
226
  }
227

    
228
  /** get next node id from DB connection */
229
  private long generateNodeID() throws SAXException {
230
      long nid=0;
231
      Statement stmt;
232
      try {
233
        stmt = conn.createStatement();
234
        stmt.execute("SELECT xml_nodes_id_seq.nextval FROM dual");
235
        ResultSet rs = stmt.getResultSet();
236
        boolean tableHasRows = rs.next();
237
        if (tableHasRows) {
238
          nid = rs.getLong(1);
239
        }
240
        stmt.close();
241
      } catch (SQLException e) {
242
        System.out.println("Error in DBSaxNode.generateNodeID: " + 
243
                            e.getMessage());
244
        throw new SAXException(e.getMessage());
245
      }
246

    
247
      return nid;
248
  }
249

    
250
  /** Add a new attribute to this node, or set its value */
251
  public void setAttribute(String attName, String attValue, String docid)
252
              throws SAXException {
253
    if (attName != null) {
254
      // Enter the attribute in the hash table
255
      super.setAttribute(attName, attValue);
256

    
257
      // And enter the attribute in the database
258
      writeChildNodeToDB("ATTRIBUTE", attName, attValue, docid);
259
    } else {
260
      System.err.println("Attribute name must not be null!");
261
      throw new SAXException("Attribute name must not be null!");
262
    }
263
  }
264

    
265
  /** Add a namespace to this node */
266
  public void setNamespace(String prefix, String uri, String docid)
267
              throws SAXException {
268
    if (prefix != null) {
269
      // Enter the namespace in a hash table
270
      super.setNamespace(prefix, uri);
271
      // And enter the namespace in the database
272
      writeChildNodeToDB("NAMESPACE", prefix, uri, docid);
273
    } else {
274
      System.err.println("Namespace prefix must not be null!");
275
      throw new SAXException("Namespace prefix must not be null!");
276
    }
277
  }
278

    
279
  /** 
280
   * NOT USED
281
   * Update the node index (xml_index) for this node by generating
282
   * test strings that represent all of the relative and absolute
283
   * paths through the XML tree from document root to this node
284
   */
285
  private void updateNodeIndex(String docid, String doctype) 
286
               throws SAXException
287
  {
288
    Hashtable pathlist = new Hashtable();
289
    boolean atStartingNode = true;
290
    boolean atRootDocumentNode = false;
291
    DBSAXNode nodePointer = this;
292
    StringBuffer currentPath = new StringBuffer();
293
    int counter = 0;
294

    
295
    // Create a Hashtable of all of the paths to reach this node
296
    // including absolute paths and relative paths
297
    while (!atRootDocumentNode) {
298
      if (atStartingNode) {
299
        currentPath.insert(0, nodePointer.getTagName());
300
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
301
        counter++;
302
        atStartingNode = false;
303
      } else {
304
        currentPath.insert(0, "/");
305
        currentPath.insert(0, nodePointer.getTagName());
306
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
307
        counter++;
308
      }
309

    
310
      // advance to the next parent node
311
      nodePointer = nodePointer.getParentNode();
312

    
313
      // If we're at the DOCUMENT node (root of DOM tree), add
314
      // the root "/" to make the absolute path
315
      if (nodePointer.getNodeType().equals("DOCUMENT")) {
316
        currentPath.insert(0, "/");
317
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
318
        counter++;
319
        atRootDocumentNode = true;
320
      } 
321
    }
322

    
323
    try {
324
      // Create an insert statement to reuse for all of the path insertions
325
      PreparedStatement pstmt = conn.prepareStatement(
326
              "INSERT INTO xml_index (nodeid, path, docid, doctype, " + 
327
               "parentnodeid) " + 
328
              "VALUES (?, ?, ?, ?, ?)");
329
      //((OraclePreparedStatement)pstmt).setExecuteBatch(counter);
330
  
331
      pstmt.setString(3, docid);
332
      pstmt.setString(4, doctype);
333
      pstmt.setLong(5, getParentID());
334
      
335
      // Step through the hashtable and insert each of the path values
336
      Enumeration en = pathlist.keys();
337
      while (en.hasMoreElements()) {
338
        String path = (String)en.nextElement();
339
        Long nodeid = (Long)pathlist.get(path);
340
        pstmt.setLong(1, nodeid.longValue());
341
        pstmt.setString(2, path);
342
        pstmt.executeUpdate();
343
  
344
        //System.out.println(nodeid + " ==> " + path);
345
      }
346

    
347
      // Close the database statement
348
      pstmt.close();
349
    } catch (SQLException sqe) {
350
      System.err.println("SQL Exception while inserting path to index in " + 
351
                         "DBSAXNode.updateNodeIndex");
352
      System.err.println(sqe.getMessage());
353
      throw new SAXException(sqe.getMessage());
354
    }
355
  }
356

    
357
  /** 
358
   * USED FROM SEPARATE THREAD RUNNED from DBSAXHandler on endDocument()
359
   * Update the node index (xml_index) for this node by generating
360
   * test strings that represent all of the relative and absolute
361
   * paths through the XML tree from document root to this node
362
   */
363
  public void updateNodeIndex(Connection conn, String docid, String doctype) 
364
               throws SAXException
365
  {
366
    Hashtable pathlist = new Hashtable();
367
    boolean atStartingNode = true;
368
    boolean atRootDocumentNode = false;
369
    DBSAXNode nodePointer = this;
370
    StringBuffer currentPath = new StringBuffer();
371
    int counter = 0;
372

    
373
    // Create a Hashtable of all of the paths to reach this node
374
    // including absolute paths and relative paths
375
    while (!atRootDocumentNode) {
376
      if (atStartingNode) {
377
        currentPath.insert(0, nodePointer.getTagName());
378
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
379
        counter++;
380
        atStartingNode = false;
381
      } else {
382
        currentPath.insert(0, "/");
383
        currentPath.insert(0, nodePointer.getTagName());
384
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
385
        counter++;
386
      }
387

    
388
      // advance to the next parent node
389
      nodePointer = nodePointer.getParentNode();
390

    
391
      // If we're at the DOCUMENT node (root of DOM tree), add
392
      // the root "/" to make the absolute path
393
      if (nodePointer.getNodeType().equals("DOCUMENT")) {
394
        currentPath.insert(0, "/");
395
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
396
        counter++;
397
        atRootDocumentNode = true;
398
      } 
399
    }
400

    
401
    try {
402
      // Create an insert statement to reuse for all of the path insertions
403
      PreparedStatement pstmt = conn.prepareStatement(
404
              "INSERT INTO xml_index (nodeid, path, docid, doctype, " + 
405
               "parentnodeid) " + 
406
              "VALUES (?, ?, ?, ?, ?)");
407
  
408
      pstmt.setString(3, docid);
409
      pstmt.setString(4, doctype);
410
      pstmt.setLong(5, getParentID());
411
      
412
      // Step through the hashtable and insert each of the path values
413
      Enumeration en = pathlist.keys();
414
      while (en.hasMoreElements()) {
415
        String path = (String)en.nextElement();
416
        Long nodeid = (Long)pathlist.get(path);
417
        pstmt.setLong(1, nodeid.longValue());
418
        pstmt.setString(2, path);
419
        
420
        pstmt.executeUpdate();
421
      }
422
      // Close the database statement
423
      pstmt.close();
424
    } catch (SQLException sqe) {
425
      System.err.println("SQL Exception while inserting path to index in " +
426
                         "DBSAXNode.updateNodeIndex for document " + docid);
427
      System.err.println(sqe.getMessage());
428
      throw new SAXException(sqe.getMessage());
429
    }
430
  }
431
 
432
  /** get the parent of this node */
433
  public DBSAXNode getParentNode() {
434
    return parentNode;
435
  }
436
}
(17-17/41)