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: sgarg $'
10
 *     '$Date: 2005-01-13 16:27:45 -0800 (Thu, 13 Jan 2005) $'
11
 * '$Revision: 2364 $'
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

    
139
      if (nodetype == "DOCUMENT") {
140
        pstmt = connection.prepareStatement(
141
            "INSERT INTO xml_nodes " +
142
            "(nodetype, nodename, nodeprefix, docid) " +
143
            "VALUES (?, ?, ?, ?)");
144

    
145
        // Increase DBConnection usage count
146
        connection.increaseUsageCount(1);
147
        MetaCatUtil.debugMessage("INSERTING DOCNAME: " + nodename, 35);
148
      } else {
149
          if(data != null && !data.trim().equals("")
150
             && !data.trim().equals("NaN")){
151
              try{
152
                  double numberData = Double.parseDouble(data);
153
                  pstmt = connection.prepareStatement(
154
                      "INSERT INTO xml_nodes " +
155
                      "(nodetype, nodename, nodeprefix, docid, " +
156
                      "rootnodeid, parentnodeid, nodedata, nodeindex, nodedatanumerical) " +
157
                      "VALUES (?, ?, ?, ?, ?, ?, ?, ?, "+ numberData +")");
158
              } catch (NumberFormatException nfe) {
159
                  pstmt = connection.prepareStatement(
160
                      "INSERT INTO xml_nodes " +
161
                      "(nodetype, nodename, nodeprefix, docid, " +
162
                      "rootnodeid, parentnodeid, nodedata, nodeindex) " +
163
                      "VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
164
              }
165
          } else {
166
              pstmt = connection.prepareStatement(
167
                  "INSERT INTO xml_nodes " +
168
                  "(nodetype, nodename, nodeprefix, docid, " +
169
                  "rootnodeid, parentnodeid, nodedata, nodeindex) " +
170
                  "VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
171
          }
172
        // Increase DBConnection usage count
173
        connection.increaseUsageCount(1);
174
      }
175

    
176
      // Bind the values to the query
177
      pstmt.setString(1, nodetype);
178
      int idx;
179
      if ( nodename != null && (idx = nodename.indexOf(":")) != -1 ) {
180
        pstmt.setString(2, nodename.substring(idx+1));
181
        pstmt.setString(3, nodename.substring(0,idx));
182
      } else {
183
        pstmt.setString(2, nodename);
184
        pstmt.setString(3, null);
185
      }
186
      pstmt.setString(4, docid);
187
      if (nodetype == "DOCUMENT") {
188
        // moved it to separate method updateRootNodeID
189
        //pstmt.setLong(4, nid);
190
      } else {
191
        if (nodetype == "ELEMENT") {
192
          pstmt.setLong(5, getRootNodeID());
193
          pstmt.setLong(6, getParentID());
194
          pstmt.setString(7, data);
195
          pstmt.setInt(8, getNodeIndex());
196
        } else {
197
          pstmt.setLong(5, getRootNodeID());
198
          pstmt.setLong(6, getNodeID());
199
          pstmt.setString(7, data);
200
          pstmt.setInt(8, incChildNum());
201
        }
202
      }
203
      // Do the insertion
204
      pstmt.execute();
205
      pstmt.close();
206

    
207
      // get the generated unique id afterward
208
      nid = dbAdapter.getUniqueID(connection.getConnections(), "xml_nodes");
209
      //should incease connection usage!!!!!!
210

    
211

    
212
      if (nodetype.equals("DOCUMENT")) {
213
        // Record the root node id that was generated from the database
214
        setRootNodeID(nid);
215
      }
216

    
217
      if (nodetype.equals("DOCUMENT") || nodetype.equals("ELEMENT")) {
218

    
219
        // Record the node id that was generated from the database
220
        setNodeID(nid);
221

    
222
        // Record the node type that was passed to the method
223
        setNodeType(nodetype);
224

    
225
      }
226

    
227
    } catch (SQLException e) {
228
      System.out.println("Error in DBSaxNode.writeChildNodeToDB");
229
      System.err.println("Error inserting node: (" + nodetype + ", " +
230
                                                     nodename + ", " +
231
                                                     data + ")" );
232
      System.err.println(e.getMessage());
233
      e.printStackTrace(System.err);
234
      throw new SAXException(e.getMessage());
235
    }
236
    return nid;
237
  }
238

    
239
  /**
240
   * update rootnodeid=nodeid for 'DOCUMENT' type of nodes only
241
   */
242
  public void updateRootNodeID(long nodeid) throws SAXException {
243
      try {
244
        PreparedStatement pstmt;
245
        pstmt = connection.prepareStatement(
246
              "UPDATE xml_nodes set rootnodeid = ? " +
247
              "WHERE nodeid = ?");
248
        // Increase DBConnection usage count
249
        connection.increaseUsageCount(1);
250

    
251
        // Bind the values to the query
252
        pstmt.setLong(1, nodeid);
253
        pstmt.setLong(2, nodeid);
254
        // Do the update
255
        pstmt.execute();
256
        pstmt.close();
257
      } catch (SQLException e) {
258
        System.out.println("Error in DBSaxNode.updateRootNodeID: " +
259
                           e.getMessage());
260
        throw new SAXException(e.getMessage());
261
      }
262
  }
263

    
264
  /**
265
   * creates SQL code to put nodename for the document node
266
   * into DB connection
267
   */
268
  public void writeNodename(String nodename) throws SAXException {
269
      try {
270
        PreparedStatement pstmt;
271
        pstmt = connection.prepareStatement(
272
              "UPDATE xml_nodes set nodename = ? " +
273
              "WHERE nodeid = ?");
274
        // Increase DBConnection usage count
275
        connection.increaseUsageCount(1);
276

    
277
        // Bind the values to the query
278
        pstmt.setString(1, nodename);
279
        pstmt.setLong(2, getNodeID());
280
        // Do the insertion
281
        pstmt.execute();
282
        pstmt.close();
283
      } catch (SQLException e) {
284
        System.out.println("Error in DBSaxNode.writeNodeName: " +
285
                           e.getMessage());
286
        throw new SAXException(e.getMessage());
287
      }
288
  }
289

    
290
 /** creates SQL code and inserts new node into DB connection */
291
  public long writeDTDNodeToDB(String nodename, String data, String docid)
292
                                 throws SAXException
293
  {
294
    long nid = -1;
295
    try
296
    {
297

    
298
      PreparedStatement pstmt;
299
      MetaCatUtil.debugMessage("Insert dtd into db: "+nodename +" "+data, 45);
300
      if(data != null && !data.trim().equals("")){
301
            try{
302
                double numberData = Double.parseDouble(data);
303
                pstmt = connection.prepareStatement(
304
                    "INSERT INTO xml_nodes " +
305
                    "(nodetype, nodename, docid, " +
306
                    "rootnodeid, parentnodeid, nodedata, nodeindex, nodedatanumerical) " +
307
                    "VALUES (?, ?, ?, ?, ?, ?, ?, "+ numberData +")");
308
            } catch (NumberFormatException nfe) {
309
                pstmt = connection.prepareStatement(
310
                    "INSERT INTO xml_nodes " +
311
                    "(nodetype, nodename,  docid, " +
312
                    "rootnodeid, parentnodeid, nodedata, nodeindex) " +
313
                    "VALUES (?, ?, ?, ?, ?, ?, ?)");
314
            }
315
        } else {
316
            pstmt = connection.prepareStatement(
317
                  "INSERT INTO xml_nodes " +
318
                  "(nodetype, nodename, docid, " +
319
                  "rootnodeid, parentnodeid, nodedata, nodeindex) " +
320
                  "VALUES (?, ?, ?, ?, ?, ?, ?)");
321
        }
322

    
323
       // Increase DBConnection usage count
324
      connection.increaseUsageCount(1);
325

    
326
      // Bind the values to the query
327
      pstmt.setString(1, DocumentImpl.DTD);
328
      pstmt.setString(2, nodename);
329
      pstmt.setString(3, docid);
330
      pstmt.setLong(4, getRootNodeID());
331
      pstmt.setLong(5, getParentID());
332
      pstmt.setString(6, data);
333
      pstmt.setInt(7, getNodeIndex());
334

    
335
      // Do the insertion
336
      pstmt.execute();
337
      pstmt.close();
338

    
339
      // get the generated unique id afterward
340
      nid = dbAdapter.getUniqueID(connection.getConnections(), "xml_nodes");
341
      //should incease connection usage!!!!!!
342

    
343
    } catch (SQLException e) {
344
      System.out.println("Error in DBSaxNode.writeDTDNodeToDB");
345
      System.err.println("Error inserting node: (" + DocumentImpl.DTD + ", " +
346
                                                     nodename + ", " +
347
                                                     data + ")" );
348
      System.err.println(e.getMessage());
349
      e.printStackTrace(System.err);
350
      throw new SAXException(e.getMessage());
351
    }
352
    return nid;
353
  }
354

    
355

    
356
  /** get next node id from DB connection */
357
  private long generateNodeID() throws SAXException {
358
      long nid=0;
359
      Statement stmt;
360
      DBConnection dbConn = null;
361
      int serialNumber = -1;
362
      try {
363
        // Get DBConnection
364
        dbConn=DBConnectionPool.getDBConnection("DBSAXNode.generateNodeID");
365
        serialNumber=dbConn.getCheckOutSerialNumber();
366
        stmt = dbConn.createStatement();
367
        stmt.execute("SELECT xml_nodes_id_seq.nextval FROM dual");
368
        ResultSet rs = stmt.getResultSet();
369
        boolean tableHasRows = rs.next();
370
        if (tableHasRows) {
371
          nid = rs.getLong(1);
372
        }
373
        stmt.close();
374
      } catch (SQLException e) {
375
        System.out.println("Error in DBSaxNode.generateNodeID: " +
376
                            e.getMessage());
377
        throw new SAXException(e.getMessage());
378
      }
379
      finally
380
      {
381
        // Return DBconnection
382
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
383
      }//finally
384

    
385
      return nid;
386
  }
387

    
388
  /** Add a new attribute to this node, or set its value */
389
  public long setAttribute(String attName, String attValue, String docid)
390
              throws SAXException
391
  {
392
    long nodeId = -1;
393
    if (attName != null)
394
    {
395
      // Enter the attribute in the hash table
396
      super.setAttribute(attName, attValue);
397

    
398
      // And enter the attribute in the database
399
      nodeId = writeChildNodeToDB("ATTRIBUTE", attName, attValue, docid);
400
    }
401
    else
402
    {
403
      System.err.println("Attribute name must not be null!");
404
      throw new SAXException("Attribute name must not be null!");
405
    }
406
    return nodeId;
407
  }
408

    
409
  /** Add a namespace to this node */
410
  public long setNamespace(String prefix, String uri, String docid)
411
              throws SAXException
412
  {
413
    long nodeId = -1;
414
    if (prefix != null)
415
    {
416
      // Enter the namespace in a hash table
417
      super.setNamespace(prefix, uri);
418
      // And enter the namespace in the database
419
      nodeId = writeChildNodeToDB("NAMESPACE", prefix, uri, docid);
420
    }
421
    else
422
    {
423
      System.err.println("Namespace prefix must not be null!");
424
      throw new SAXException("Namespace prefix must not be null!");
425
    }
426
    return nodeId;
427
  }
428

    
429

    
430

    
431
  /**
432
   * USED FROM SEPARATE THREAD RUNNED from DBSAXHandler on endDocument()
433
   * Update the node index (xml_index) for this node by generating
434
   * test strings that represent all of the relative and absolute
435
   * paths through the XML tree from document root to this node
436
   */
437
  public void updateNodeIndex(DBConnection conn, String docid, String doctype)
438
               throws SAXException
439
  {
440
    Hashtable pathlist = new Hashtable();
441
    boolean atStartingNode = true;
442
    boolean atRootDocumentNode = false;
443
    DBSAXNode nodePointer = this;
444
    StringBuffer currentPath = new StringBuffer();
445
    int counter = 0;
446

    
447
    // Create a Hashtable of all of the paths to reach this node
448
    // including absolute paths and relative paths
449
    while (!atRootDocumentNode) {
450
      if (atStartingNode) {
451
        currentPath.insert(0, nodePointer.getTagName());
452
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
453
        counter++;
454
        atStartingNode = false;
455
      } else {
456
        currentPath.insert(0, "/");
457
        currentPath.insert(0, nodePointer.getTagName());
458
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
459
        counter++;
460
      }
461

    
462
      // advance to the next parent node
463
      nodePointer = nodePointer.getParentNode();
464

    
465
      // If we're at the DOCUMENT node (root of DOM tree), add
466
      // the root "/" to make the absolute path
467
      if (nodePointer.getNodeType().equals("DOCUMENT")) {
468
        currentPath.insert(0, "/");
469
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
470
        counter++;
471
        atRootDocumentNode = true;
472
      }
473
    }
474

    
475
    try {
476
      // Create an insert statement to reuse for all of the path insertions
477
      PreparedStatement pstmt = conn.prepareStatement(
478
              "INSERT INTO xml_index (nodeid, path, docid, doctype, " +
479
               "parentnodeid) " +
480
              "VALUES (?, ?, ?, ?, ?)");
481
      // Increase usage count
482
      conn.increaseUsageCount(1);
483

    
484
      pstmt.setString(3, docid);
485
      pstmt.setString(4, doctype);
486
      pstmt.setLong(5, getParentID());
487

    
488
      // Step through the hashtable and insert each of the path values
489
      Enumeration en = pathlist.keys();
490
      while (en.hasMoreElements()) {
491
        String path = (String)en.nextElement();
492
        Long nodeid = (Long)pathlist.get(path);
493
        pstmt.setLong(1, nodeid.longValue());
494
        pstmt.setString(2, path);
495

    
496
        pstmt.executeUpdate();
497
      }
498
      // Close the database statement
499
      pstmt.close();
500
    } catch (SQLException sqe) {
501
      System.err.println("SQL Exception while inserting path to index in " +
502
                         "DBSAXNode.updateNodeIndex for document " + docid);
503
      System.err.println(sqe.getMessage());
504
      throw new SAXException(sqe.getMessage());
505
    }
506
  }
507

    
508
  /** get the parent of this node */
509
  public DBSAXNode getParentNode() {
510
    return parentNode;
511
  }
512
}
(24-24/63)