KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > mapper > metadata > PathSet


1 /*
2  * This file belongs to the XQuark distribution.
3  * Copyright (C) 2003 Universite de Versailles Saint-Quentin.
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307.
18  * You can also get it at http://www.gnu.org/licenses/lgpl.html
19  *
20  * For more information on this software, see http://www.xquark.org.
21  */

22
23 package org.xquark.mapper.metadata;
24
25 import java.sql.*;
26 import java.util.ArrayList JavaDoc;
27
28 import org.xquark.mapper.RepositoryException;
29 import org.xquark.mapper.dbms.*;
30 import org.xquark.mapper.mapping.TableMapping;
31 import org.xquark.xpath.*;
32
33 /** Shared memory data structure used to store paths of an XML collection
34  * and provide a direct access to mapping information.
35  *
36  * <p><B>WARNING !</B> Path are never removed till a reconstruction is made
37  * from the documents stored in the collection. Thus, some paths in the path set
38  * may not correspond to stored documents.</p>
39  * <p><B>WARNING !</B> This object keeps a collection.getMetadataConnection() till it is closed.</p>
40  * <p>It uses PathNode object for storing a path ID for every node of the
41  * collection metadata.</p>
42  */

43 public class PathSet extends XTree implements RepositoryConstants
44 {
45     private static final String JavaDoc RCSRevision = "$Revision: 1.1 $";
46     private static final String JavaDoc RCSName = "$Name: $";
47     // TO DO : CHECK OVERFLOW
48

49     /** The collection metadata ewning this pathset
50      */

51     private CollectionMetadata collection;
52     
53     private Sequence pathSeq;
54     
55     private String JavaDoc selectDiffStmt;
56     private String JavaDoc insertStmt;
57     private String JavaDoc checkCountStmt;
58     private boolean seqInitialized = false;
59     
60     /* synchonization flag */
61     private short mawLoadedPID = 0; // initialized to 0 in order to load all at the beginning
62

63     /** Hashtable used to provide rapid access from ID to a path
64      */

65     protected ArrayList JavaDoc pathIndex = new ArrayList JavaDoc(); // path ID is index (0 is reserved for ROOT)
66
// missing paths will be represented as nulls
67

68     /** JDBC data used for storing rows in the database with batch style.
69      * IMPORTANT : when storing only one batch is used for all threads.
70      */

71     private PreparedStatement pInsertStmt = null;
72     private PreparedStatement pSelectStmt = null;
73     
74     private String JavaDoc tableName;
75     private boolean isNew = false;
76     private boolean loading = false;
77     
78     /** Constructor.
79      * <p>Path set is loaded from the underlying database.</p>
80      * @param collection the repository using the dictionary and providing database access.
81      * @exception java.sql.SQLException if a database-access error occurs.
82      */

83     public PathSet(CollectionMetadata collection)
84     {
85         // Nota : pathIndex is instantiated by super() that calls AllocateNode
86
this.collection = collection;
87         pathSeq = new Sequence(
88                                 collection.getTableInfo(TableSpec.TYPE_PATH_SEQ),
89                                 (short)1
90                                 );
91         initStatements();
92         
93         try
94         {
95             if (isEmpty()) // in order to know if flags must be calculated or read from the database
96
isNew = true;
97         }
98         catch (Exception JavaDoc e)
99         {
100             throw new RuntimeException JavaDoc("Error while loading the path set" + e.getMessage());
101         }
102     }
103     
104     public synchronized boolean isNew()
105     {
106         return isNew;
107     }
108     
109     public void registerMapping(TableMapping tm, PathNode node)
110     {
111         collection.registerMapping(tm, node);
112     }
113     ////////////////////////////////////////////////////////////////////
114
// ACCESSORS
115
////////////////////////////////////////////////////////////////////
116

117     public CollectionMetadata getCollection()
118     {
119         return collection;
120     }
121     
122     public synchronized PathNode get(short id)
123     throws RepositoryException
124     {
125         if ((id > mawLoadedPID) && !loading) // refresh for document reconstruction using paths created by other instances
126
refresh();
127             
128         return (PathNode)pathIndex.get(id);
129     }
130     
131     /**
132      * Returns the <code>PathNode</code> object accessible by the specified
133      * <code>LocationExpression</code>.
134      *
135      * @param e the access path
136      * @return the correspoding PathNode
137      *
138      */

139     public synchronized PathMetadata getPathNode(PathExpr e)
140     {
141         return (PathNode) super.getNode(e);
142     }
143     
144     ////////////////////////////////////////////////////////////////////
145
// PUBLIC
146
////////////////////////////////////////////////////////////////////
147

148     /* Rebuild the actual collection path set from documents stored in the
149      * database. Path that are not found are removed.
150      */

151     public synchronized void refresh()
152     throws RepositoryException
153     {
154         ResultSet rs = null;
155         try
156         {
157             if (!loading)
158             {
159                 loading = true;
160                 if (standsBy())
161                     initPreparedStatements(collection.getMetadataConnection());
162                 pSelectStmt.setShort(1, mawLoadedPID);
163                 rs = pSelectStmt.executeQuery();
164                 while(rs.next())
165                     loadNode(
166                             get(rs.getShort(2)),
167                             rs.getShort(1),
168                             rs.getString(3),
169                             rs.getString(4),
170                             rs.getByte(5),
171                             rs.getByte(6)
172                             );
173                 mawLoadedPID = (short)(pathIndex.size() - 1);
174             }
175         }
176         catch (SQLException e)
177         {
178             throw new RepositoryException(RepositoryException.DB_ERROR,
179             "JDBC error while refreshing path set metadata cache.", e);
180         }
181         finally
182         {
183             loading = false;
184             try
185             {
186                 if (rs != null)
187                     rs.close();
188             }
189             catch (SQLException e)
190             {
191                 throw new RepositoryException(RepositoryException.DB_ERROR,
192                 "JDBC error while refreshing path set metadata cache.", e);
193             }
194         }
195     }
196     
197     public MetadataIterator createIterator()
198     {
199         return new MetadataIterator(collection.getPathSetFactory());
200     }
201     
202     public MetadataIterator createIterator(PathNode path)
203     {
204         return new MetadataIterator(collection.getPathSetFactory(), path);
205     }
206     
207     public MetadataIterator createIterator(short pid)
208     throws RepositoryException
209     {
210         return new MetadataIterator(collection.getPathSetFactory(), (PathNode)get(pid));
211     }
212     
213     ////////////////////////////////////////////////////////////////////
214
// PACKAGE PRIVATE
215
////////////////////////////////////////////////////////////////////
216
void releaseJDBCRessources()
217     {
218         try
219         {
220             if (pInsertStmt != null)
221                 pInsertStmt.close();
222             if (pSelectStmt != null)
223                 pSelectStmt.close();
224         }
225         catch (SQLException e)
226         {
227             // no op : to see...
228
}
229         finally
230         {
231             pInsertStmt = null;
232             pSelectStmt = null;
233         }
234     }
235
236     void initRoot()
237     {
238         pathIndex.add(ROOT_PATH_ID, getRoot());
239     }
240     
241     /** free resources used by this object.
242      */

243     void close()
244     {
245         if (collection != null)
246         {
247             clear();
248             releaseJDBCRessources();
249             pathIndex = null;
250             collection = null;
251         }
252     }
253     
254     /** Empty the path set (in memory).
255      */

256     void clear()
257     {
258         pathIndex.clear();
259     }
260     
261     /**
262      * Called by PathSetFactory when new paths added. Synchronized because of "get" methods.
263      * @return if no collision (if false: do not create node but refresh)
264      */

265     synchronized void allocateID(PathNode node)
266     throws RepositoryException
267     {
268         if (!loading && (node.getType() != NodeKind.NONE)) // allocate one and try to store // already set by default
269
registerPath((short)pathSeq.nextValue(collection.getMetadataConnection()), node);
270     }
271     
272     synchronized void freeID(PathNode node)
273     {
274         pathIndex.remove(node.getPathID());
275     }
276     
277     boolean isLoading()
278     {
279         return loading;
280     }
281
282     void store(PathNode p)
283     throws java.sql.SQLException JavaDoc
284     {
285         // preparation of PreparedStatement for insertion
286
try
287         {
288             AbstractConnection metaConn = collection.getMetadataConnection();
289             synchronized(metaConn) // SHOULD add it to any use of metadata performing commit (reading?)
290
{
291                 if (standsBy())
292                     initPreparedStatements(metaConn);
293                 pInsertStmt.setShort(1, collection.getCollectionID());
294                 pInsertStmt.setShort(2, p.getPathID());
295                 if (p.getParent() == null)
296                     pInsertStmt.setShort(3, ROOT_PATH_ID);
297                 else
298                     pInsertStmt.setShort(3, ((PathNode)p.getParent()).getPathID());
299                 pInsertStmt.setString(4, p.getNamespace());
300                 pInsertStmt.setString(5, p.getLocalName());
301                 pInsertStmt.setByte(6, p.getType());
302                 pInsertStmt.setByte(7, p.getStorageMode());
303                 pInsertStmt.executeUpdate();
304             }
305         }
306         catch (SQLException e)
307         {
308             if (pInsertStmt != null)
309                 pInsertStmt.close();
310             pInsertStmt = null;
311             throw e;
312         }
313     }
314     
315     ////////////////////////////////////////////////////////////////////
316
// PRIVATE
317
////////////////////////////////////////////////////////////////////
318
private void initStatements()
319     {
320         // Documents table statements
321
TableInfo table = collection.getRepository().getTableInfo(TableSpec.TYPE_PATHS);
322         ColumnInfo[] columns = table.getColumns();
323         
324         StringBuffer JavaDoc sql = new StringBuffer JavaDoc();
325         sql.append("SELECT COUNT(*) FROM ");
326         sql.append(table.getName());
327         sql.append(" WHERE CID=");
328         sql.append(collection.getCollectionID());
329         checkCountStmt = sql.toString();
330         
331         sql.setLength(0);
332         sql.append("SELECT PID,PPID,NS,NAME,TYPE,SMF FROM ");
333         sql.append(table.getName());
334         sql.append(" WHERE CID=");
335         sql.append(collection.getCollectionID());
336         sql.append(" AND PID>? ORDER BY PID");
337         selectDiffStmt = sql.toString();
338         
339         insertStmt = table.getInsertStatement();
340     }
341     
342     private boolean standsBy()
343     {
344         return pInsertStmt == null;
345     }
346
347     private void initPreparedStatements(AbstractConnection metaConn) throws SQLException
348     {
349         pInsertStmt = metaConn.getConnection().prepareStatement(insertStmt);
350         pSelectStmt = metaConn.getConnection().prepareStatement(selectDiffStmt);
351     }
352
353     private boolean isEmpty()
354     throws java.sql.SQLException JavaDoc
355     {
356         Statement stmt = null;
357         ResultSet rs = null;
358         boolean isEmpty;
359         try
360         {
361             stmt = collection.getMetadataConnection().getConnection().createStatement();
362             rs = stmt.executeQuery(checkCountStmt);
363             rs.next();
364             isEmpty = (rs.getInt(1) == 0);
365         }
366         finally
367         {
368             if (rs != null)
369                 rs.close();
370             if (stmt != null)
371                 stmt.close();
372         }
373         return isEmpty;
374     }
375     
376     /** Used by loader */
377     /** called by load(). Set the pathID for node created by the mapping
378      * duplication.
379      */

380     private XTreeNode loadNode(PathNode parent, short pid,
381     String JavaDoc namespace, String JavaDoc localName, byte type, byte storageMode)
382     {
383         // calls allocate node if the node was nos part of the mapping
384
PathNode node = (PathNode)collection.getPathSetFactory().createNamedNodeIfNotExist(
385                         parent,
386                         namespace,
387                         localName,
388                         type
389                         );
390         node.setStorageModeFlag(storageMode);
391         registerPath(pid, node);
392         return node;
393     }
394     
395     private void registerPath(short pid, PathNode node)
396     {
397         node.setPathID(pid);
398         while (node.getPathID() > pathIndex.size())
399             pathIndex.add(null); // lost pids
400

401         pathIndex.add(node.getPathID(), node);
402     }
403     
404
405 }
406
Popular Tags