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: 2002-06-13 11:54:51 -0700 (Thu, 13 Jun 2002) $'
11
 * '$Revision: 1217 $'
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
  /** 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 = connection.prepareStatement(
109
            "INSERT INTO xml_nodes " +
110
            "(nodetype, nodename, nodeprefix, docid) " +
111
            "VALUES (?, ?, ?, ?)");
112
        
113
        // Increase DBConnection usage count
114
        connection.increaseUsageCount(1);
115
        MetaCatUtil.debugMessage("INSERTING DOCNAME: " + nodename);
116
      } else {
117
        pstmt = connection.prepareStatement(
118
            "INSERT INTO xml_nodes " +
119
            "(nodetype, nodename, nodeprefix, docid, " +
120
            "rootnodeid, parentnodeid, nodedata, nodeindex) " +
121
            "VALUES (?, ?, ?, ?, ?, ?, ?, ?)");
122
        // Increase DBConnection usage count
123
        connection.increaseUsageCount(1);
124
      }
125

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

    
157
      // get the generated unique id afterward
158
      long nid = dbAdapter.
159
                         getUniqueID(connection.getConnections(), "xml_nodes");
160
      //should incease connection usage!!!!!!
161
     
162
      
163
      if (nodetype.equals("DOCUMENT")) {
164
        // Record the root node id that was generated from the database
165
        setRootNodeID(nid);
166
      }
167

    
168
      if (nodetype.equals("DOCUMENT") || nodetype.equals("ELEMENT")) {
169

    
170
        // Record the node id that was generated from the database
171
        setNodeID(nid);
172

    
173
        // Record the node type that was passed to the method
174
        setNodeType(nodetype);
175

    
176
      }
177

    
178
    } catch (SQLException e) {
179
      System.out.println("Error in DBSaxNode.writeChildNodeToDB");
180
      System.err.println("Error inserting node: (" + nodetype + ", " +
181
                                                     nodename + ", " + 
182
                                                     data + ")" );
183
      System.err.println(e.getMessage());
184
      e.printStackTrace(System.err);
185
      throw new SAXException(e.getMessage());
186
    }
187
  }
188

    
189
  /** 
190
   * update rootnodeid=nodeid for 'DOCUMENT' type of nodes only
191
   */
192
  public void updateRootNodeID(long nodeid) throws SAXException {
193
      try {
194
        PreparedStatement pstmt;
195
        pstmt = connection.prepareStatement(
196
              "UPDATE xml_nodes set rootnodeid = ? " +
197
              "WHERE nodeid = ?");
198
        // Increase DBConnection usage count
199
        connection.increaseUsageCount(1);
200

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

    
214
  /** 
215
   * creates SQL code to put nodename for the document node 
216
   * into DB connection 
217
   */
218
  public void writeNodename(String nodename) throws SAXException {
219
      try {
220
        PreparedStatement pstmt;
221
        pstmt = connection.prepareStatement(
222
              "UPDATE xml_nodes set nodename = ? " +
223
              "WHERE nodeid = ?");
224
        // Increase DBConnection usage count
225
        connection.increaseUsageCount(1);
226

    
227
        // Bind the values to the query
228
        pstmt.setString(1, nodename);
229
        pstmt.setLong(2, getNodeID());
230
        // Do the insertion
231
        pstmt.execute();
232
        pstmt.close();
233
      } catch (SQLException e) {
234
        System.out.println("Error in DBSaxNode.writeNodeName: " + 
235
                           e.getMessage());
236
        throw new SAXException(e.getMessage());
237
      }
238
  }
239

    
240
  /** get next node id from DB connection */
241
  private long generateNodeID() throws SAXException {
242
      long nid=0;
243
      Statement stmt;
244
      DBConnection dbConn = null;
245
      int serialNumber = -1;
246
      try {
247
        // Get DBConnection
248
        dbConn=DBConnectionPool.getDBConnection("DBSAXNode.generateNodeID");
249
        serialNumber=dbConn.getCheckOutSerialNumber();
250
        stmt = dbConn.createStatement();
251
        stmt.execute("SELECT xml_nodes_id_seq.nextval FROM dual");
252
        ResultSet rs = stmt.getResultSet();
253
        boolean tableHasRows = rs.next();
254
        if (tableHasRows) {
255
          nid = rs.getLong(1);
256
        }
257
        stmt.close();
258
      } catch (SQLException e) {
259
        System.out.println("Error in DBSaxNode.generateNodeID: " + 
260
                            e.getMessage());
261
        throw new SAXException(e.getMessage());
262
      }
263
      finally
264
      {
265
        // Return DBconnection
266
        DBConnectionPool.returnDBConnection(dbConn, serialNumber);
267
      }//finally
268

    
269
      return nid;
270
  }
271

    
272
  /** Add a new attribute to this node, or set its value */
273
  public void setAttribute(String attName, String attValue, String docid)
274
              throws SAXException {
275
    if (attName != null) {
276
      // Enter the attribute in the hash table
277
      super.setAttribute(attName, attValue);
278

    
279
      // And enter the attribute in the database
280
      writeChildNodeToDB("ATTRIBUTE", attName, attValue, docid);
281
    } else {
282
      System.err.println("Attribute name must not be null!");
283
      throw new SAXException("Attribute name must not be null!");
284
    }
285
  }
286

    
287
  /** Add a namespace to this node */
288
  public void setNamespace(String prefix, String uri, String docid)
289
              throws SAXException {
290
    if (prefix != null) {
291
      // Enter the namespace in a hash table
292
      super.setNamespace(prefix, uri);
293
      // And enter the namespace in the database
294
      writeChildNodeToDB("NAMESPACE", prefix, uri, docid);
295
    } else {
296
      System.err.println("Namespace prefix must not be null!");
297
      throw new SAXException("Namespace prefix must not be null!");
298
    }
299
  }
300

    
301
 
302

    
303
  /** 
304
   * USED FROM SEPARATE THREAD RUNNED from DBSAXHandler on endDocument()
305
   * Update the node index (xml_index) for this node by generating
306
   * test strings that represent all of the relative and absolute
307
   * paths through the XML tree from document root to this node
308
   */
309
  public void updateNodeIndex(DBConnection conn, String docid, String doctype) 
310
               throws SAXException
311
  {
312
    Hashtable pathlist = new Hashtable();
313
    boolean atStartingNode = true;
314
    boolean atRootDocumentNode = false;
315
    DBSAXNode nodePointer = this;
316
    StringBuffer currentPath = new StringBuffer();
317
    int counter = 0;
318

    
319
    // Create a Hashtable of all of the paths to reach this node
320
    // including absolute paths and relative paths
321
    while (!atRootDocumentNode) {
322
      if (atStartingNode) {
323
        currentPath.insert(0, nodePointer.getTagName());
324
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
325
        counter++;
326
        atStartingNode = false;
327
      } else {
328
        currentPath.insert(0, "/");
329
        currentPath.insert(0, nodePointer.getTagName());
330
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
331
        counter++;
332
      }
333

    
334
      // advance to the next parent node
335
      nodePointer = nodePointer.getParentNode();
336

    
337
      // If we're at the DOCUMENT node (root of DOM tree), add
338
      // the root "/" to make the absolute path
339
      if (nodePointer.getNodeType().equals("DOCUMENT")) {
340
        currentPath.insert(0, "/");
341
        pathlist.put(currentPath.toString(), new Long(getNodeID()));
342
        counter++;
343
        atRootDocumentNode = true;
344
      } 
345
    }
346

    
347
    try {
348
      // Create an insert statement to reuse for all of the path insertions
349
      PreparedStatement pstmt = conn.prepareStatement(
350
              "INSERT INTO xml_index (nodeid, path, docid, doctype, " + 
351
               "parentnodeid) " + 
352
              "VALUES (?, ?, ?, ?, ?)");
353
      // Increase usage count
354
      conn.increaseUsageCount(1);
355
  
356
      pstmt.setString(3, docid);
357
      pstmt.setString(4, doctype);
358
      pstmt.setLong(5, getParentID());
359
      
360
      // Step through the hashtable and insert each of the path values
361
      Enumeration en = pathlist.keys();
362
      while (en.hasMoreElements()) {
363
        String path = (String)en.nextElement();
364
        Long nodeid = (Long)pathlist.get(path);
365
        pstmt.setLong(1, nodeid.longValue());
366
        pstmt.setString(2, path);
367
        
368
        pstmt.executeUpdate();
369
      }
370
      // Close the database statement
371
      pstmt.close();
372
    } catch (SQLException sqe) {
373
      System.err.println("SQL Exception while inserting path to index in " +
374
                         "DBSAXNode.updateNodeIndex for document " + docid);
375
      System.err.println(sqe.getMessage());
376
      throw new SAXException(sqe.getMessage());
377
    }
378
  }
379
 
380
  /** get the parent of this node */
381
  public DBSAXNode getParentNode() {
382
    return parentNode;
383
  }
384
}
(22-22/52)