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: tao $'
10
 *     '$Date: 2003-08-14 16:41:05 -0700 (Thu, 14 Aug 2003) $'
11
 * '$Revision: 1803 $'
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 DBConnection	connection;
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 (DBConnection conn, String docid) throws SAXException {
55

    
56
    super();
57
    this.connection = 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 (DBConnection conn, String qName, String lName,
71
                    DBSAXNode parentNode, long rootnodeid, 
72
                    String docid, String doctype) 
73
                                               throws SAXException {
74

    
75
    super(lName);
76
    this.connection = 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
  /** 
88
   * Construct a new node instance for DTD nodes
89
   * This Node will write docname, publicId and systemId into db. Only
90
   * handle systemid  existed.(external dtd)
91
   *
92
   * @param conn the JDBC Connection to which all information is written
93
   * @param tagname the name of the node
94
   * @param parentNode the parent node for this node being created
95
   */
96
  public DBSAXNode (DBConnection conn, String docName, String publicId, 
97
                    String systemId, DBSAXNode parentNode, long rootnodeid, 
98
                    String docid) throws SAXException 
99
  {
100

    
101
    super();
102
    this.connection = conn;
103
    this.parentNode = parentNode;
104
    setParentID(parentNode.getNodeID());
105
    setRootNodeID(rootnodeid);
106
    setDocID(docid);
107
    // insert dtd node only for external dtd definiation
108
    if (systemId != null)
109
    {
110
      //write docname to DB
111
      if (docName != null)
112
      {
113
        setNodeIndex(parentNode.incChildNum());
114
        writeDTDNodeToDB(DocumentImpl.DOCNAME, docName, docid);
115
      }
116
      //write publicId to DB
117
      if (publicId != null)
118
      {
119
        setNodeIndex(parentNode.incChildNum());
120
        writeDTDNodeToDB(DocumentImpl.PUBLICID, publicId, docid);
121
      }
122
      //write systemId to DB
123
      setNodeIndex(parentNode.incChildNum());
124
      writeDTDNodeToDB(DocumentImpl.SYSTEMID, systemId, docid);
125
    }
126
  }
127
    
128
  /** creates SQL code and inserts new node into DB connection */
129
  public long writeChildNodeToDB(String nodetype, String nodename,
130
                                 String data, String docid) 
131
                                 throws SAXException 
132
  {
133
    long nid = -1;
134
    try 
135
    {
136
 
137
      PreparedStatement pstmt;
138
      if (nodetype == "DOCUMENT") {
139
        pstmt = connection.prepareStatement(
140
            "INSERT INTO xml_nodes " +
141
            "(nodetype, nodename, nodeprefix, docid) " +
142
            "VALUES (?, ?, ?, ?)");
143
        
144
        // Increase DBConnection usage count
145
        connection.increaseUsageCount(1);
146
        MetaCatUtil.debugMessage("INSERTING DOCNAME: " + nodename, 35);
147
      } else {
148
        pstmt = connection.prepareStatement(
149
            "INSERT INTO xml_nodes " +
150
            "(nodetype, nodename, nodeprefix, docid, " +
151
            "rootnodeid, parentnodeid, nodedata, nodeindex) " +
152
            "VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
153
        // Increase DBConnection usage count
154
        connection.increaseUsageCount(1);
155
      }
156

    
157
      // Bind the values to the query
158
      pstmt.setString(1, nodetype);
159
      int idx;
160
      if ( nodename != null && (idx = nodename.indexOf(":")) != -1 ) {
161
        pstmt.setString(2, nodename.substring(idx+1));
162
        pstmt.setString(3, nodename.substring(0,idx));
163
      } else {
164
        pstmt.setString(2, nodename);
165
        pstmt.setString(3, null);
166
      }
167
      pstmt.setString(4, docid);
168
      if (nodetype == "DOCUMENT") {
169
        // moved it to separate method updateRootNodeID
170
        //pstmt.setLong(4, nid);
171
      } else {
172
        if (nodetype == "ELEMENT") {
173
          pstmt.setLong(5, getRootNodeID());
174
          pstmt.setLong(6, getParentID());
175
          pstmt.setString(7, data);
176
          pstmt.setInt(8, getNodeIndex());
177
        } else {
178
          pstmt.setLong(5, getRootNodeID());
179
          pstmt.setLong(6, getNodeID());
180
          pstmt.setString(7, data);
181
          pstmt.setInt(8, incChildNum());
182
        }
183
      }
184
      // Do the insertion
185
      pstmt.execute();
186
      pstmt.close();
187

    
188
      // get the generated unique id afterward
189
      nid = dbAdapter.getUniqueID(connection.getConnections(), "xml_nodes");
190
      //should incease connection usage!!!!!!
191
     
192
      
193
      if (nodetype.equals("DOCUMENT")) {
194
        // Record the root node id that was generated from the database
195
        setRootNodeID(nid);
196
      }
197

    
198
      if (nodetype.equals("DOCUMENT") || nodetype.equals("ELEMENT")) {
199

    
200
        // Record the node id that was generated from the database
201
        setNodeID(nid);
202

    
203
        // Record the node type that was passed to the method
204
        setNodeType(nodetype);
205

    
206
      }
207

    
208
    } catch (SQLException e) {
209
      System.out.println("Error in DBSaxNode.writeChildNodeToDB");
210
      System.err.println("Error inserting node: (" + nodetype + ", " +
211
                                                     nodename + ", " + 
212
                                                     data + ")" );
213
      System.err.println(e.getMessage());
214
      e.printStackTrace(System.err);
215
      throw new SAXException(e.getMessage());
216
    }
217
    return nid;
218
  }
219

    
220
  /** 
221
   * update rootnodeid=nodeid for 'DOCUMENT' type of nodes only
222
   */
223
  public void updateRootNodeID(long nodeid) throws SAXException {
224
      try {
225
        PreparedStatement pstmt;
226
        pstmt = connection.prepareStatement(
227
              "UPDATE xml_nodes set rootnodeid = ? " +
228
              "WHERE nodeid = ?");
229
        // Increase DBConnection usage count
230
        connection.increaseUsageCount(1);
231

    
232
        // Bind the values to the query
233
        pstmt.setLong(1, nodeid);
234
        pstmt.setLong(2, nodeid);
235
        // Do the update
236
        pstmt.execute();
237
        pstmt.close();
238
      } catch (SQLException e) {
239
        System.out.println("Error in DBSaxNode.updateRootNodeID: " + 
240
                           e.getMessage());
241
        throw new SAXException(e.getMessage());
242
      }
243
  }
244

    
245
  /** 
246
   * creates SQL code to put nodename for the document node 
247
   * into DB connection 
248
   */
249
  public void writeNodename(String nodename) throws SAXException {
250
      try {
251
        PreparedStatement pstmt;
252
        pstmt = connection.prepareStatement(
253
              "UPDATE xml_nodes set nodename = ? " +
254
              "WHERE nodeid = ?");
255
        // Increase DBConnection usage count
256
        connection.increaseUsageCount(1);
257

    
258
        // Bind the values to the query
259
        pstmt.setString(1, nodename);
260
        pstmt.setLong(2, getNodeID());
261
        // Do the insertion
262
        pstmt.execute();
263
        pstmt.close();
264
      } catch (SQLException e) {
265
        System.out.println("Error in DBSaxNode.writeNodeName: " + 
266
                           e.getMessage());
267
        throw new SAXException(e.getMessage());
268
      }
269
  }
270

    
271
 /** creates SQL code and inserts new node into DB connection */
272
  public long writeDTDNodeToDB(String nodename, String data, String docid) 
273
                                 throws SAXException 
274
  {
275
    long nid = -1;
276
    try 
277
    {
278
 
279
      PreparedStatement pstmt;
280
      MetaCatUtil.debugMessage("Insert dtd into db: "+nodename +" "+data, 45);
281
      pstmt = connection.prepareStatement(
282
            "INSERT INTO xml_nodes " +
283
            "(nodetype, nodename, docid, " +
284
            "rootnodeid, parentnodeid, nodedata, nodeindex) " +
285
            "VALUES (?, ?, ?, ?, ?, ?, ?)");
286
       // Increase DBConnection usage count
287
      connection.increaseUsageCount(1);
288
      
289
      // Bind the values to the query
290
      pstmt.setString(1, DocumentImpl.DTD);
291
      pstmt.setString(2, nodename);
292
      pstmt.setString(3, docid);
293
      pstmt.setLong(4, getRootNodeID());
294
      pstmt.setLong(5, getParentID());
295
      pstmt.setString(6, data);
296
      pstmt.setInt(7, getNodeIndex());
297
    
298
      // Do the insertion
299
      pstmt.execute();
300
      pstmt.close();
301

    
302
      // get the generated unique id afterward
303
      nid = dbAdapter.getUniqueID(connection.getConnections(), "xml_nodes");
304
      //should incease connection usage!!!!!!
305
     
306
    } catch (SQLException e) {
307
      System.out.println("Error in DBSaxNode.writeDTDNodeToDB");
308
      System.err.println("Error inserting node: (" + DocumentImpl.DTD + ", " +
309
                                                     nodename + ", " + 
310
                                                     data + ")" );
311
      System.err.println(e.getMessage());
312
      e.printStackTrace(System.err);
313
      throw new SAXException(e.getMessage());
314
    }
315
    return nid;
316
  }
317
 
318
  
319
  /** get next node id from DB connection */
320
  private long generateNodeID() throws SAXException {
321
      long nid=0;
322
      Statement stmt;
323
      DBConnection dbConn = null;
324
      int serialNumber = -1;
325
      try {
326
        // Get DBConnection
327
        dbConn=DBConnectionPool.getDBConnection("DBSAXNode.generateNodeID");
328
        serialNumber=dbConn.getCheckOutSerialNumber();
329
        stmt = dbConn.createStatement();
330
        stmt.execute("SELECT xml_nodes_id_seq.nextval FROM dual");
331
        ResultSet rs = stmt.getResultSet();
332
        boolean tableHasRows = rs.next();
333
        if (tableHasRows) {
334
          nid = rs.getLong(1);
335
        }
336
        stmt.close();
337
      } catch (SQLException e) {
338
        System.out.println("Error in DBSaxNode.generateNodeID: " + 
339
                            e.getMessage());
340
        throw new SAXException(e.getMessage());
341
      }
342
      finally
343
      {
344
        // Return DBconnection
345
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
346
      }//finally
347

    
348
      return nid;
349
  }
350

    
351
  /** Add a new attribute to this node, or set its value */
352
  public long setAttribute(String attName, String attValue, String docid)
353
              throws SAXException 
354
  {
355
    long nodeId = -1;
356
    if (attName != null) 
357
    {
358
      // Enter the attribute in the hash table
359
      super.setAttribute(attName, attValue);
360

    
361
      // And enter the attribute in the database
362
      nodeId = writeChildNodeToDB("ATTRIBUTE", attName, attValue, docid);
363
    } 
364
    else 
365
    {
366
      System.err.println("Attribute name must not be null!");
367
      throw new SAXException("Attribute name must not be null!");
368
    }
369
    return nodeId;
370
  }
371

    
372
  /** Add a namespace to this node */
373
  public long setNamespace(String prefix, String uri, String docid)
374
              throws SAXException 
375
  {
376
    long nodeId = -1;
377
    if (prefix != null) 
378
    {
379
      // Enter the namespace in a hash table
380
      super.setNamespace(prefix, uri);
381
      // And enter the namespace in the database
382
      nodeId = writeChildNodeToDB("NAMESPACE", prefix, uri, docid);
383
    } 
384
    else 
385
    {
386
      System.err.println("Namespace prefix must not be null!");
387
      throw new SAXException("Namespace prefix must not be null!");
388
    }
389
    return nodeId;
390
  }
391

    
392
 
393

    
394
  /** 
395
   * USED FROM SEPARATE THREAD RUNNED from DBSAXHandler on endDocument()
396
   * Update the node index (xml_index) for this node by generating
397
   * test strings that represent all of the relative and absolute
398
   * paths through the XML tree from document root to this node
399
   */
400
  public void updateNodeIndex(DBConnection conn, String docid, String doctype) 
401
               throws SAXException
402
  {
403
    Hashtable pathlist = new Hashtable();
404
    boolean atStartingNode = true;
405
    boolean atRootDocumentNode = false;
406
    DBSAXNode nodePointer = this;
407
    StringBuffer currentPath = new StringBuffer();
408
    int counter = 0;
409

    
410
    // Create a Hashtable of all of the paths to reach this node
411
    // including absolute paths and relative paths
412
    while (!atRootDocumentNode) {
413
      if (atStartingNode) {
414
        currentPath.insert(0, nodePointer.getTagName());
415
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
416
        counter++;
417
        atStartingNode = false;
418
      } else {
419
        currentPath.insert(0, "/");
420
        currentPath.insert(0, nodePointer.getTagName());
421
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
422
        counter++;
423
      }
424

    
425
      // advance to the next parent node
426
      nodePointer = nodePointer.getParentNode();
427

    
428
      // If we're at the DOCUMENT node (root of DOM tree), add
429
      // the root "/" to make the absolute path
430
      if (nodePointer.getNodeType().equals("DOCUMENT")) {
431
        currentPath.insert(0, "/");
432
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
433
        counter++;
434
        atRootDocumentNode = true;
435
      } 
436
    }
437

    
438
    try {
439
      // Create an insert statement to reuse for all of the path insertions
440
      PreparedStatement pstmt = conn.prepareStatement(
441
              "INSERT INTO xml_index (nodeid, path, docid, doctype, " + 
442
               "parentnodeid) " + 
443
              "VALUES (?, ?, ?, ?, ?)");
444
      // Increase usage count
445
      conn.increaseUsageCount(1);
446
  
447
      pstmt.setString(3, docid);
448
      pstmt.setString(4, doctype);
449
      pstmt.setLong(5, getParentID());
450
      
451
      // Step through the hashtable and insert each of the path values
452
      Enumeration en = pathlist.keys();
453
      while (en.hasMoreElements()) {
454
        String path = (String)en.nextElement();
455
        Long nodeid = (Long)pathlist.get(path);
456
        pstmt.setLong(1, nodeid.longValue());
457
        pstmt.setString(2, path);
458
        
459
        pstmt.executeUpdate();
460
      }
461
      // Close the database statement
462
      pstmt.close();
463
    } catch (SQLException sqe) {
464
      System.err.println("SQL Exception while inserting path to index in " +
465
                         "DBSAXNode.updateNodeIndex for document " + docid);
466
      System.err.println(sqe.getMessage());
467
      throw new SAXException(sqe.getMessage());
468
    }
469
  }
470
 
471
  /** get the parent of this node */
472
  public DBSAXNode getParentNode() {
473
    return parentNode;
474
  }
475
}
(24-24/58)