KickJava   Java API By Example, From Geeks To Geeks.

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


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
26 import java.sql.*;
27 import java.util.*;
28
29 import org.xml.sax.InputSource JavaDoc;
30 import org.xml.sax.SAXException JavaDoc;
31 import org.xquark.mapper.*;
32 import org.xquark.mapper.dbms.*;
33 import org.xquark.mapper.mapping.Loader;
34 import org.xquark.mapper.mapping.MappingFactory;
35 import org.xquark.mapper.mapping.RepositoryMapping;
36 import org.xquark.mapper.storage.PersistentCollectionInfo;
37 import org.xquark.mapper.storage.PersistentRepositoryInfo;
38 import org.xquark.mapper.storage.RepositoryReader;
39 import org.xquark.mapper.util.*;
40 import org.xquark.schema.SchemaManager;
41 import org.xquark.xml.xdbc.XMLDBCException;
42 import org.xquark.xml.xdbc.XMLDBCNotRecognizedException;
43 import org.xquark.xpath.XTree;
44 import org.xquark.xquery.ModuleManager;
45 import org.xquark.xquery.metadata.resolver.SourceMetadata;
46
47
48 /**
49  * Provide functions for manipulating repositories such as creating,
50  * opening, deleting...
51  * Repository manages a list of repositories for each database user. At
52  * the present time a database user can only access his own repositories.
53  * @see org.xquark.mapper.AccessManager
54   */

55 public final class Repository implements RepositoryConstants, _Repository
56 {
57     private static final String JavaDoc RCSRevision = "$Revision: 1.4 $";
58     private static final String JavaDoc RCSName = "$Name: $";
59
60     /** The repsoitory configuration information read from the Repository table */
61     private RepositoryInfo config;
62
63     /** A collection for opened XML Collections */
64     private CacheManager collectionManager = new CacheManager(RepositoryProperties.getIntProperty(CONF_COLLECTION_METADATA_CACHE));
65
66     /** A collection for loaded mappings (in fact {mappingID, MappingFactory} */
67     private CounterMap loadedMappings = new CounterMap();
68
69     /** The class managing loaded schemas */
70     private SchemaManager schemaManager;
71     
72     /** The system repositories used to store mapping files and schemas.
73      * Only opened when a repository is opened or created.
74      */

75     private CollectionMetadata schemaCollection, mappingCollection;
76
77     /** JDBC connection reserved for metadata operation, not submitted
78      * to storage rollback.
79      */

80     private AbstractConnection metadataConnection;
81     private _RepositoryConnection metadataRepConnection;
82
83     /** The name of the user connected to this rdbms */
84     private String JavaDoc user;
85     private String JavaDoc URL;
86
87     /** A map containing TableInfo for repository tables.
88      */

89     private Map repositoryTables;
90     
91     /** Object containing user table Information for user tables.
92      */

93     private UserTableManager userTables;
94     
95     /** XQuery parser interfaces implementation */
96     private Collection sourceCollection;
97     private Map proxyCollections = null;
98     
99     /** SQL Statements. */
100     private String JavaDoc checkSchemaStmt;
101     private String JavaDoc checkMappingStmt;
102     private String JavaDoc deletePathSetStmt;
103     private String JavaDoc updateColDescStmt;
104     
105     /** Create a Repository object using the Connection object passed in parameter.
106      * @param conn a java.sql.Connection object
107      * @throws RepositoryException application exception.
108      */

109     public Repository(AbstractConnection connection) throws XMLDBCException
110     {
111         setConnection(connection);
112         sourceCollection = Collections.singletonList(this);
113         
114         // TO DO : define a user API for Repository conf !!!
115
/* boot */
116         config = new RepositoryInfo(user, DEFAULT_CID_SIZE);
117         init(true); // with the current default configuration (needed for boot)
118

119         try
120         {
121             if (metadataConnection.checkTable(LEGACY_REPOSITORY_CHECKER))
122                 throw new RepositoryException(RepositoryException.DB_CONSISTENCY_ERROR,
123                 "A legacy repository has been detected an no migration tool is available (beta stage).\nPlease remove the old repository before using this version of the runtime. This can be performed with the old runtime (with XMLManager 'del rep' command) or by dropping all dbms tables beginning with the 'XQUARK$' prefix.");
124             
125             if (!metadataConnection.checkTable(getTableInfo(TableSpec.TYPE_REPOSITORY))) // check if initialization was performed
126
initializeRepository();
127             /* loading repository configuration info */
128             PersistentRepositoryInfo configReader = new PersistentRepositoryInfo(
129             getTableInfo(TableSpec.TYPE_REPOSITORY), metadataConnection);
130             try
131             {
132                 configReader.fetchRow();
133             }
134             catch (SQLException e)
135             {
136                 throw new RepositoryException(RepositoryException.DB_ERROR,
137                 "JDBC error while reading repository configuration.", e);
138             }
139             config = configReader.getRepositoryInfo();
140             
141             /* Repository relational schema compatibility check */
142             if (!config.getVersion().equals(TableSpecLoader.REPOSITORY_DATA_VERSION))
143                throw new RepositoryException(RepositoryException.CONSISTENCY_ERROR,
144                 "This existing repository is not compatible with the current software version. A migration must be considered.");
145             
146             init(false); // init schemaManager, read repository config
147
}
148         catch (SQLException e) {
149             throw new RepositoryException(RepositoryException.DB_ERROR,
150             "JDBC error while performing repository initialization.", e);
151         }
152     }
153     
154     ////////////////////////////////////////////////////////////////////
155
// ACCESSORS
156
////////////////////////////////////////////////////////////////////
157
private void setConnection(AbstractConnection connection)
158     throws RepositoryException
159     {
160         try
161         {
162             restoreConnection(connection);
163             DatabaseMetaData dbMeta = metadataConnection.getConnection().getMetaData();
164             user = dbMeta.getUserName().toUpperCase();
165             URL = dbMeta.getURL();
166         }
167         catch (SQLException e)
168         {
169             throw new RepositoryException(RepositoryException.DB_ERROR,
170             "JDBC error while initialization a connection for metadata.", e);
171         }
172         
173     }
174     
175     public boolean standsBy()
176     {
177         return (metadataConnection == null);
178     }
179     
180     public boolean isAlive()
181     {
182         return (schemaManager != null);
183     }
184     
185     public TableInfo getTableInfo(byte type)
186     {
187         return (TableInfo)repositoryTables.get(new Byte JavaDoc(type));
188     }
189     
190     public UserTableManager getTableManager()
191     {
192         return userTables;
193     }
194     
195     public RepositoryInfo getInfo()
196     {
197         return config;
198     }
199     
200     /** Open collection metadata without guarantee it is not released. Consequently,
201      * metadata object collection may be performed at every call.
202      */

203     public synchronized _Collection getCollection(String JavaDoc name) throws XMLDBCException
204     {
205         if (name == null)
206             throw new RepositoryException(RepositoryException.ILLEGAL_EXPRESSION, "All method parameters are mandatory and must not be null.");
207         
208         name=name.toUpperCase();
209         
210         // check if not already opened
211
CollectionMetadata collection = (CollectionMetadata)collectionManager.get(name);
212         if (collection == null)
213         {
214             collection = createCollectionMetadata(name);
215             collectionManager.put(name, collection);
216         }
217         return collection;
218     }
219   
220     public String JavaDoc getName()
221     {
222         return config.getName();
223     }
224     
225     public String JavaDoc getVersion()
226     {
227         return config.getVersion();
228     }
229     
230     /** Returns the dbms user name used by this object.
231      * @return the user name supplied at opening time.
232      */

233     public String JavaDoc getUserName()
234     {
235         return user;
236     }
237     
238     /** Returns the JDBC string used by this object.
239      * @return the JDBC string supplied at opening time.
240      */

241     public String JavaDoc getURL()
242     {
243         return URL;
244     }
245     
246     public String JavaDoc toString()
247     {
248         return RepositoryDriver.REPOSITORY_URL_PREFIX + URL + ", " + user;
249     }
250
251     /**
252      * Return the database repository list.
253      *
254      * @return repository names in a string List.
255      * @throws RepositoryException application exception.
256      */

257     public List getCollectionList() throws XMLDBCException
258     {
259         ArrayList names = new ArrayList();
260         AbstractConnection connection = null;
261         PersistentCollectionInfo wConfig = null;
262         try {
263             connection = metadataConnection;
264             wConfig = new PersistentCollectionInfo(
265                     getTableInfo(TableSpec.TYPE_COLLECTIONS), connection);
266
267             wConfig.retrieveDataSet(CollectionInfo.USER); // system repositories are not fetched
268
while (wConfig.fetchNextRow())
269             {
270                 names.add(wConfig.getCollectionName());
271             }
272         }
273         catch (SQLException e) {
274             throw new RepositoryException(RepositoryException.DB_ERROR, "JDBC error while getting repository list.", e);
275         }
276         finally {
277             if (wConfig != null)
278                 wConfig.close();
279         }
280
281         return names;
282     }
283
284     /**
285      * Get the system Collection object for this database object,
286      * containing schema files. Actually, this repository is
287      * opened the the first time this method is called
288      *
289      * @return a CollectionMetadata object.
290      */

291     public synchronized CollectionMetadata getSchemaCollection()
292     throws XMLDBCException
293     {
294         return schemaCollection;
295     }
296     
297     public SchemaManager getSchemaManager()
298     {
299         return schemaManager;
300     }
301     
302     public ModuleManager getModuleManager()
303     {
304         //TODO to be done!!
305
return null;
306     }
307         
308     public AbstractConnection getMetadataConnection()
309     {
310         return metadataConnection;
311     }
312     
313     /**
314      * Get the system Collection object for this database object,
315      * containing mapping files. Actually, this repository is
316      * opened the the first time this method is called
317      *
318      * @return a CollectionMetadata object.
319      */

320     public synchronized CollectionMetadata getMappingCollection()
321     throws XMLDBCException
322     {
323         return mappingCollection;
324     }
325
326     public MappingFactory getMapping(String JavaDoc MappingID) throws RepositoryException
327     {
328         MappingFactory ret = (MappingFactory)loadedMappings.checkOut(MappingID);
329         if (ret == null) // if not already opened
330
{
331             // Load mapping
332
ret = loadMapping(MappingID, false);
333             // Put the mapping factory in the hastable of loaded mappings
334
loadedMappings.put(MappingID, ret);
335         }
336         return ret;
337     }
338     
339     ////////////////////////////////////////////////////////////////////
340
// PUBLIC
341
////////////////////////////////////////////////////////////////////
342
public synchronized void resetRepository() throws XMLDBCException
343     {
344         deleteRepository();
345         initializeRepository();
346         init(false);
347     }
348     
349     /**
350      * Free all resources. For instance, close JDBC connection and repositories.
351      * <B>Any subsequent call to a function of the object will raise an
352      * exception.</B>
353      * @throws RepositoryException application exception.
354      */

355     public synchronized void close()
356     throws XMLDBCException
357     {
358         // free collection metadata opened for queries is useless since we'return closing (waiting for LRU)
359
withdrawConnection();
360         reset();
361
362         repositoryTables = null;
363         collectionManager = null;
364         loadedMappings = null;
365     }
366
367     public void withdrawConnection() throws XMLDBCException
368     {
369         metadataRepConnection.close();
370         metadataRepConnection = null;
371         metadataConnection = null;
372         // release collection metadata JDBC Ressources
373
schemaCollection.releaseJDBCRessources();
374         mappingCollection.releaseJDBCRessources();
375         
376         Iterator it = collectionManager.iterator();
377         while (it.hasNext())
378             ((CollectionMetadata)it.next()).releaseJDBCRessources();
379     }
380     
381     public void restoreConnection(AbstractConnection connection)
382     throws SQLException, RepositoryException
383     {
384         metadataRepConnection = new RepositoryConnectionImpl(
385         this,
386         connection,
387         new DestructionToken()
388         {
389             public void destruct(Object JavaDoc o)
390             {};
391         });
392         
393         metadataConnection = connection;
394         metadataConnection.getConnection().setAutoCommit(true);
395         // NOTE prepared statements will be automatically recreated from metadata connection
396
}
397     
398     private void reset() throws RepositoryException
399     {
400         if (isAlive())
401         {
402             collectionManager.clear();
403             loadedMappings.clear();
404             schemaManager = null;
405             userTables = null;
406             schemaCollection = null;
407             mappingCollection = null;
408             proxyCollections = null;
409         }
410     }
411     
412     /** Remove <b>XQuark Repository</b> configuration from the underlying database,
413      * but not the repository tables. All repositories must have been previously
414      * removed from the configuration table before this function is able to work.
415      *
416      * @throws RepositoryException application exception.
417      */

418     public synchronized void deleteConfiguration() throws XMLDBCException
419     {
420         PersistentCollectionInfo wConfig = null;
421         try {
422             wConfig = new PersistentCollectionInfo(getTableInfo(TableSpec.TYPE_COLLECTIONS),
423                 metadataConnection);
424
425             wConfig.retrieveDataSet(CollectionInfo.USER);
426             if(wConfig.fetchNextRow())
427                 throw new RepositoryException(RepositoryException.NOT_ALLOWED, "All collections must be deleted before using this function.");
428             deleteRepository();
429         }
430         catch (SQLException e) {
431             throw new RepositoryException(RepositoryException.DB_ERROR, "JDBC error while deleting database.", e);
432         }
433         finally {
434             wConfig.close();
435         }
436     }
437
438     /** Remove <b>XQuark Repository</b> configuration from the underlying database
439      * and all the repositories referenced. This method does not stops if a failure
440      * occurs while deleting a repository.
441      * <B>Don't use this method unless you are sure not to use XQuark Repository
442      * any more in the underlying database, because all data will be lost.</B>
443      * @throws RepositoryException application exception.
444      * @return the number of XML collections deleted.
445      */

446     public synchronized int deleteAllCollections() throws XMLDBCException
447     {
448         List collections = getCollectionList();
449         Iterator it = collections.iterator();
450         
451         while (it.hasNext())
452             deleteCollection((String JavaDoc)it.next());
453         
454         return collections.size();
455     }
456     
457     public synchronized void deleteRepository()
458     throws XMLDBCException
459     {
460         // release system collections
461
releaseCollectionMetadata(RepositoryConnection.MAPPING_COLLECTION);
462         releaseCollectionMetadata(RepositoryConnection.SCHEMA_COLLECTION);
463         
464         // check no collection metadata is currently in use (lightweith
465
// RepositoryConnection object should close them first)
466
if (collectionManager.used())
467             throw new RepositoryException(RepositoryException.NOT_ALLOWED,
468                 "All collections must be closed before repository can be deleted.");
469         
470             // Delete all repository tables (don't remove user data)
471
try
472         {
473             dropRepositoryTables();
474         }
475         catch (SQLException e)
476         {
477             throw new RepositoryException(RepositoryException.DB_ERROR,
478                 "JDBC error while destroying repository tables.", e);
479         }
480         try
481         {
482             metadataConnection.onDeleteRepository(this);
483         }
484         catch (SQLException e)
485         {
486             throw new RepositoryException(RepositoryException.DB_ERROR,
487                 "JDBC error while performing dbms-specific cleaning tasks.", e);
488         }
489         // reinit schema manager and cache
490
reset();
491     }
492     
493     /** Open a repository owned by the connection user, identified by the
494      * <code>name</code> parameter. If the repository has been opened
495      * previously, the same object is returned. A counter is kept on the object
496      * so it won't be destroyed before beeing released.
497      * @param name the name of the repository.
498      * @return the repository opened.
499      * @throws RepositoryException Application exception. For instance if
500      * the specified repository does not exist.
501      */

502     public synchronized CollectionMetadata openCollection(String JavaDoc name)
503     throws XMLDBCException
504     {
505         if (name == null)
506         throw new RepositoryException(RepositoryException.ILLEGAL_EXPRESSION, "All method parameters are mandatory and must not be null.");
507
508         name=name.toUpperCase();
509
510         // check if not already opened
511
CollectionMetadata collection = (CollectionMetadata)collectionManager.checkOut(name);
512         if (collection == null)
513         {
514             collection = createCollectionMetadata(name);
515             // put it in the list
516
collectionManager.use(name, collection);
517         }
518 // else // increment mapping use counter
519
// {
520
// String MappingID = collection.getInfo().getMappingID();
521
// MappingFactory ret = (MappingFactory)loadedMappings.checkOut(MappingID);
522
// if (ret == null) // if not already opened
523
// {
524
// // Load mapping
525
// ret = collection.getMappingFactory();
526
// // Put the mapping factory in the hastable of loaded mappings
527
// loadedMappings.put(MappingID, ret);
528
// }
529
//
530
// }
531
return collection;
532     }
533
534     private CollectionMetadata createCollectionMetadata(String JavaDoc name)
535     throws XMLDBCException
536     {
537         CollectionMetadata collection = null;
538         
539         PersistentCollectionInfo wConfig = new PersistentCollectionInfo(
540             getTableInfo(TableSpec.TYPE_COLLECTIONS), metadataConnection);
541
542         // searching for the collection in config table
543
try {
544             if (wConfig.fetchRow(name))
545             {
546                 // Create a collection object
547
switch(wConfig.getCollectionInfo().getType())
548                 {
549                     case CollectionInfo.SYSTEM:
550                     case CollectionInfo.USER:
551                         collection = new CollectionMetadata(
552                                                 name,
553                                                 wConfig.getCollectionID(),
554                                                 wConfig.getCollectionInfo(),
555                                                 this,
556                                                 getMapping(wConfig.getCollectionInfo().getMappingID())
557                                                 );
558                         break;
559                     default:
560                         throw new RepositoryException(RepositoryException.ILLEGAL_EXPRESSION,
561                                     "This type of collection (" + wConfig.getCollectionInfo().getType() +
562                                     ") stored in the XQUARK$_CONFIG table is unknown.");
563                 }
564             }
565             else
566                 throw new RepositoryException(RepositoryException.NOT_EXISTS, "XMLCollection information not found for " + name + " collection.");
567         }
568         catch (SQLException e) {
569             throw new RepositoryException(RepositoryException.DB_ERROR, "Error while fetching information for " + name + " collection.", e);
570         }
571         
572         return collection;
573     }
574     
575     public MappingFactory loadDefaultMapping()
576     throws RepositoryException
577     {
578         MappingFactory ret = new MappingFactory(this, schemaManager, metadataRepConnection);
579         ret.createTree();
580         return ret;
581     }
582     
583     public MappingFactory loadMapping(String JavaDoc MappingID, boolean generate)
584     throws RepositoryException
585     {
586         RepositoryMapping mapping;
587         MappingFactory ret = new MappingFactory(this, schemaManager, metadataRepConnection);
588         mapping = (RepositoryMapping)ret.createTree();
589         // load the mapping from the system repository (and save it if no saved yet)
590
if (MappingID!= null && MappingID.length() > 0)
591         {
592             RepositoryReader mappingReader = null;
593             try
594             {
595                 mappingReader = metadataRepConnection.getMappingReader();
596                 Loader loader = new Loader
597                 (
598                 mappingReader,
599                 metadataRepConnection.getConnection(),
600                 schemaManager,
601                 generate
602                 );
603                 InputSource JavaDoc source = new InputSource JavaDoc(MappingID);
604                 mapping = loader.load(source, ret, false);
605             }
606             catch (Exception JavaDoc e)
607             {
608                 throw new RepositoryException(RepositoryException.NOT_EXISTS, "Error while loading mapping or schema.", e);
609             }
610             finally
611             {
612                 if (mappingReader != null)
613                     mappingReader.close();
614             }
615             // Verify (only for Repository) that multiple join tables
616
// specification do not exist for a same user table
617
mapping.checkRedundantTables();
618         }
619         return ret;
620     }
621     
622     /**
623      * @return a list of collection names
624      */

625     public synchronized List getCollectionsUsingMapping(String JavaDoc mappingID)
626     throws XMLDBCException
627     {
628         // query execution
629
ArrayList collections = new ArrayList();
630         PreparedStatement pStmt = null;
631         ResultSet rs = null;
632         try
633         {
634             pStmt = metadataConnection.getConnection().prepareStatement(checkMappingStmt);
635             pStmt.setString(1, mappingID);
636             rs = pStmt.executeQuery();
637             
638             while (rs.next())
639                 collections.add(rs.getString(1));
640         }
641         catch (SQLException e)
642         {
643             throw new RepositoryException(RepositoryException.DB_ERROR,
644             "JDBC error while collecting information on namespaces used in the repository.", e);
645         }
646         finally
647         {
648             try
649             {
650                 if (rs != null)
651                     rs.close();
652                 if (pStmt != null)
653                     pStmt.close();
654             }
655             catch (SQLException e)
656             {
657                 // no op
658
}
659         }
660         
661         return collections;
662     }
663
664     /**
665      * @return a list of collection names
666      */

667     public synchronized List getCollectionsUsingNamespace(String JavaDoc targetNamespace)
668     throws XMLDBCException
669     {
670         // query execution
671
ArrayList collections = new ArrayList();
672         PreparedStatement pStmt = null;
673         ResultSet rs = null;
674         try
675         {
676             pStmt = metadataConnection.getConnection().prepareStatement(checkSchemaStmt);
677             pStmt.setString(1, targetNamespace);
678             rs = pStmt.executeQuery();
679             
680             ListIterator it = collections.listIterator();
681             
682             while (rs.next())
683                 collections.add(rs.getString(1));
684         }
685         catch (SQLException e)
686         {
687             throw new RepositoryException(RepositoryException.DB_ERROR,
688             "JDBC error while collecting information on namespaces used in the repository.", e);
689         }
690         finally
691         {
692             try
693             {
694                 if (rs != null)
695                     rs.close();
696                 if (pStmt != null)
697                     pStmt.close();
698             }
699             catch (SQLException e)
700             {
701                 // no op
702
}
703         }
704         
705         return collections;
706     }
707     
708     /** Create a new repository which features are given by the CollectionInfo
709      * object. If a repository with the same ID (name, owner) already exists,
710      * the existing repository is returned without any warning.
711      * Processes database object initialization for the repository.
712      * @param name the name of the repository.
713      * @param config a CollectionInfo object allowing to set the features of
714      * the new repository.
715      * @return the newly created repository
716      * @throws RepositoryException application exception.
717      */

718     public synchronized void createCollection(String JavaDoc name, CollectionInfo config, MappingFactory mappingFactory)
719     throws XMLDBCException
720     {
721         name = name.toUpperCase();
722         
723         // Check if a Collection of same name exists.
724
if (getCollectionList().indexOf(name) >= 0)
725             throw new RepositoryException(RepositoryException.ALREADY_EXISTS, "This collection seems to exist.");
726         
727         if ((name == null) || (config == null))
728             throw new RepositoryException(RepositoryException.ILLEGAL_EXPRESSION, "All method parameters are mandatory and must not be null.");
729         
730         PersistentCollectionInfo configRow = new PersistentCollectionInfo
731                                         (
732                                         getTableInfo(TableSpec.TYPE_COLLECTIONS),
733                                         name,
734                                         config,
735                                         getInfo().getColIDMaxValue(),
736                                         metadataConnection
737                                         );
738         CollectionMetadata.initializeCollection
739                                         (
740                                         (RepositoryMapping)mappingFactory.getTree(),
741                                         configRow,
742                                         this,
743                                         metadataConnection
744                                         );
745     }
746     
747     /** Remove completely a repository from the base.
748      * <B>The repository is supposed not to be in use.</B>
749      * <p>Attempts is made to delete repository tables even if the repository
750      * is not present in the configuration table.</p>
751      * @param name repository name
752      * @throws RepositoryException application exception
753      */

754     public synchronized void deleteCollection(String JavaDoc name)
755     throws XMLDBCException
756     {
757         if (name == null)
758         throw new RepositoryException(RepositoryException.ILLEGAL_EXPRESSION, "All method parameters are mandatory and must not be null.");
759
760         if (collectionManager.used(name))
761             throw new RepositoryException(RepositoryException.NOT_ALLOWED,
762                 "Collection must be closed before it can be deleted.");
763             
764         PersistentCollectionInfo wConfig = null;
765         try {
766             wConfig = new PersistentCollectionInfo(
767                 getTableInfo(TableSpec.TYPE_COLLECTIONS), metadataConnection);
768
769             name=name.toUpperCase();
770
771             // TO DO : CHECK REPOSITORYCONNECTIONS ARE WARNED OR PREVENT REMOVAL WHEN IN USE BY OTHER REPOSITORYCONNECTIONS
772

773             // close collection if opened
774
cleanCollection(name);
775
776             // searching for the repository in config table
777
if (wConfig.fetchRow(name))
778             {
779                 // Create a repository object
780
switch(wConfig.getCollectionInfo().getType())
781                 {
782                     case CollectionInfo.SYSTEM:
783                     case CollectionInfo.USER:
784                         CollectionMetadata.dropCollectionTables(wConfig, config.getColIDSize(), metadataConnection);
785                         break;
786                     default:
787                         throw new RepositoryException(RepositoryException.ILLEGAL_EXPRESSION,
788                                     "This type of repository (" + wConfig.getCollectionInfo().getType() +
789                                     ") stored in the XQUARK$_CONFIG table is unknown.");
790                 }
791                 
792                 // remove the path set
793
metadataConnection.executeUpdate(deletePathSetStmt + wConfig.getCollectionID());
794                 
795                 // remove the entry from the config table
796
try {
797                     wConfig.deleteRow();
798                 }
799                 catch (SQLException e) {
800                     throw new RepositoryException(RepositoryException.DB_ERROR, "Failed to delete repository from the configuration table.", e);
801                 }
802             }
803             else // try to delete generic repository tables because table dropping may have previously failed
804
CollectionMetadata.dropCollectionTables(wConfig, config.getColIDSize(), metadataConnection);
805                 
806         }
807         catch (SQLException e) {
808             // NO ROLLBACK is attempted
809
throw new RepositoryException(RepositoryException.DB_ERROR, "JDBC error while deleting repository.", e);
810         }
811         finally {
812             if (wConfig != null)
813                 wConfig.close();
814         }
815     }
816     /** Rename a repository.
817      * <p>Proceed renaming of all repository-related database objects.</p>
818      * <B>Result is unpredictable if the renaming occurs while repository
819      * access is being done. It is recommended to stop all repository use.</B>
820      * @param oldName current name of the repository
821      * @param newName new name to set for the repository.
822      * @throws RepositoryException application exception.
823      */

824     public synchronized void renameCollection(String JavaDoc oldName, String JavaDoc newName)
825     throws XMLDBCException
826     {
827         if ((oldName == null) || (newName == null))
828         throw new RepositoryException(RepositoryException.ILLEGAL_EXPRESSION, "All method parameters are mandatory and must not be null.");
829
830         AbstractConnection connection = null;
831         PersistentCollectionInfo wConfig = null;
832         try {
833             connection = metadataConnection;
834             wConfig = new PersistentCollectionInfo(getTableInfo(TableSpec.TYPE_COLLECTIONS), connection);
835
836             oldName=oldName.toUpperCase();
837             newName=newName.toUpperCase();
838
839             // searching for the repository in config table in order to change it
840
if (wConfig.fetchRow(oldName))
841             {
842                 // rename a repository object
843
switch(wConfig.getCollectionInfo().getType())
844                 {
845                     case CollectionInfo.SYSTEM:
846                         throw new RepositoryException(RepositoryException.NOT_ALLOWED,
847                                     "Cannot rename a system XML collection.");
848                     case CollectionInfo.USER:
849                         wConfig.rename(oldName, newName);
850                         break;
851                     default:
852                         throw new RepositoryException(RepositoryException.ILLEGAL_EXPRESSION,
853                                     "This type of repository (" + wConfig.getCollectionInfo().getType() +
854                                     ") stored in the XQUARK$_CONFIG table is unknown.");
855                 }
856             }
857             else
858                 throw new RepositoryException(RepositoryException.NOT_EXISTS, "XMLCollection information not found.");
859             
860             // change name in memory if already opened
861
CollectionMetadata colMeta = (CollectionMetadata)collectionManager.get(oldName);
862             if (colMeta != null)
863             {
864                 colMeta.setName(newName);
865                 collectionManager.setKey(oldName, newName);
866             }
867
868         }
869         catch (SQLException e) {
870             throw new RepositoryException(RepositoryException.DB_ERROR, "JDBC error while renaming repository.", e);
871         }
872         finally {
873             if (wConfig != null)
874                 wConfig.close();
875         }
876     }
877
878     public synchronized void releaseCollectionMetadata(String JavaDoc collectionName)
879     throws RepositoryException
880     {
881         // remove from the list
882
CollectionMetadata collection = (CollectionMetadata)collectionManager.release(collectionName.toUpperCase());
883         
884         // TO IMPROVE: this close should be performed when LRU discards it (using object should be warned it can be closed())
885
// release mapping if any and if the collection is really removed (last use)
886
if (collection != null)
887         {
888             try
889             {
890                 if (collection.getMapping() != null) // TO CHECK (un mapping quand même ?)
891
loadedMappings.remove(collection.getInfo().getProperty(RepositoryConnection.MAPPING_ID_PROPERTY));
892             }
893             catch (XMLDBCNotRecognizedException e)
894             {
895                 // no op : internal use
896
throw new RuntimeException JavaDoc("Internal error: unknown feature or property.");
897             }
898 // collection.close();
899

900             if (collectionName.equals(RepositoryConnection.MAPPING_COLLECTION))
901                 mappingCollection = null;
902             else if (collectionName.equals(RepositoryConnection.SCHEMA_COLLECTION))
903                 schemaCollection = null;
904         }
905     }
906     
907     ///////////////////////////////////////////////////////////////////////////
908
// MetadataAccess implementation
909
///////////////////////////////////////////////////////////////////////////
910

911     /**
912      * @return a Map object {sourceName, Map {collectionName, CollectionMetadata}}
913      */

914     public Collection getSources()
915     {
916         if (proxyCollections == null)
917             refreshCollectionList();
918         return sourceCollection;
919     }
920     
921     /** Provide access to a particular data source.
922      * <B>Warning:</B> implementation may be case unsensitive.
923      * @param sourceName the ID of the source
924      * @return a SourceMetadata object
925      */

926     public SourceMetadata getSourceMetadata(String JavaDoc sourceName)
927     {
928         if (proxyCollections == null)
929             refreshCollectionList();
930
931         if (sourceName.equals(getSourceName()))
932             return this;
933         else
934             return null;
935     }
936     
937     private void refreshCollectionList()
938     {
939         String JavaDoc name;
940         Iterator it;
941         try
942         {
943             it = getCollectionList().iterator();
944         }
945         catch (XMLDBCException e)
946         { // TO SEE: How to process it ?
947
throw new RuntimeException JavaDoc("Error while getting collection list: " + e.getMessage());
948         }
949         
950         // refresh list at every call
951
if (proxyCollections == null)
952             proxyCollections = new HashMap();
953         else
954             proxyCollections.clear();
955         while (it.hasNext())
956         {
957             name = (String JavaDoc)it.next();
958             proxyCollections.put(name, new ProxyCollection(name));
959         }
960         
961     }
962     
963 // public List getCachedCollectionList()
964
// {
965
// return new ArrayList(proxyCollections.keySet());
966
// }
967
//
968
///////////////////////////////////////////////////////////////////////////
969
// SourceMetadata implementation
970
///////////////////////////////////////////////////////////////////////////
971

972     public boolean isCaseSensitive()
973     {
974         return false;
975     }
976     
977     public boolean isStrict()
978     {
979         return false;
980     }
981
982     public String JavaDoc getSourceName()
983     {
984         return RepositoryConstants.REPOSITORY_SOURCE_NAME;
985     }
986     
987     public Collection getCollectionsMetadata()
988     {
989         return proxyCollections.values();
990     }
991     
992     public org.xquark.xquery.metadata.resolver.CollectionMetadata getCollectionMetadata(String JavaDoc collectionName)
993     {
994         return (org.xquark.xquery.metadata.resolver.CollectionMetadata)proxyCollections.get(collectionName.toUpperCase());
995     }
996     
997     
998     ///////////////////////////////////////////////////////////////////////////
999
// XPathResolver implementation
1000
///////////////////////////////////////////////////////////////////////////
1001
// public ArrayList resolveXPath(ArrayList xnodes, StepExpr step) {
1002
// return null;
1003
// }
1004
//
1005
// public ArrayList resolveXPath(ArrayList xnodes, ArrayList steps) {
1006
// return null;
1007
// }
1008
//
1009
// public QType resolveQType(byte context, QType qtype, StepExpr step) {
1010
// return null;
1011
// }
1012
//
1013
// public ArrayList getCollectionRootNodes(String collectionName) {
1014
// return null;
1015
// }
1016
//
1017
// public XNode getDocumentRootNode(URI documentURI) {
1018
// return null;
1019
// }
1020
//
1021
// public ArrayList getInputRootNodes() {
1022
// return null;
1023
// }
1024

1025    ////////////////////////////////////////////////////////////////////
1026
// PACKAGE-PRIVATE
1027
////////////////////////////////////////////////////////////////////
1028
void updateCollectionDescription(short cid, String JavaDoc desc)
1029    throws SQLException
1030    {
1031        PreparedStatement pStmt = null;
1032        try
1033        {
1034            pStmt = metadataConnection.getConnection().prepareStatement(updateColDescStmt);
1035            pStmt.setString(1, desc);
1036            pStmt.setShort(2, cid);
1037            pStmt.executeUpdate();
1038        }
1039        finally
1040        {
1041            if (pStmt != null)
1042                pStmt.close();
1043        }
1044    }
1045    
1046    ////////////////////////////////////////////////////////////////////
1047
// PRIVATE
1048
////////////////////////////////////////////////////////////////////
1049
/** Initialize and configure the underlying database for managing XML
1050     * documents and other semi-structured data. This method needs to be
1051     * called only once per database. Subsequence raise an exception.
1052     * Config table, dictionary and system repositories are created.
1053     * @throws RepositoryException Application exception.
1054     */

1055    private void initializeRepository()
1056    throws XMLDBCException
1057    {
1058        try {
1059            /* create repository level tables and indexes */
1060            Iterator it = metadataConnection.createTables(repositoryTables.values()).iterator();
1061            
1062            /* sequence creation (step must be specified) */
1063            while (it.hasNext())
1064                new Sequence((TableInfo)it.next(), (short)1).create(metadataConnection);
1065           
1066            /* store repository config */
1067            PersistentRepositoryInfo infoSaver = new PersistentRepositoryInfo(
1068                config,
1069                getTableInfo(TableSpec.TYPE_REPOSITORY),
1070                metadataConnection
1071                );
1072            infoSaver.save();
1073            
1074            /* perform dbms-specific tasks */
1075            metadataConnection.onInitRepository(this);
1076        }
1077        catch (RepositoryException e) {
1078            try {
1079                dropRepositoryTables();
1080            }
1081            catch (SQLException ex) {
1082                // no op
1083
}
1084            throw e;
1085        }
1086        catch (SQLException e) {
1087            try {
1088                dropRepositoryTables();
1089            }
1090            catch (SQLException ex) {
1091                throw new RepositoryException(RepositoryException.DB_ERROR,
1092                "JDBC error while repository initialization. Could not remove tables.", e);
1093            }
1094            throw new RepositoryException(RepositoryException.DB_ERROR, "JDBC error while repository initialization.", e);
1095        }
1096        
1097        /* Create "system" repository for storing mapping files and schemas */
1098        CollectionInfo config = new CollectionInfo(CollectionInfo.SYSTEM,
1099                            metadataConnection.getSystemCollectionDataLength());
1100        
1101        createCollection(RepositoryConnection.SCHEMA_COLLECTION, config, getMapping(config.getMappingID()));
1102        createCollection(RepositoryConnection.MAPPING_COLLECTION, config, getMapping(config.getMappingID()));
1103    }
1104
1105    private void init(boolean boot) throws XMLDBCException
1106    {
1107        /* reloading tableInfo with configuration read and not boot one.*/
1108        repositoryTables = loadTableInfo(config);
1109        
1110        /* creating a new schema manager */
1111        schemaManager = new SchemaManager();
1112        String JavaDoc resource = RepositoryDataSource.class.getResource(
1113            MAPPING_PACKAGE + RESOURCES_FOLDER + MAPPING_SCHEMA_FILE).toString();
1114        try {
1115            schemaManager.loadSchema(new InputSource JavaDoc(resource));
1116        }
1117        catch (SAXException JavaDoc e) {
1118            throw new RepositoryException(RepositoryException.PARSER_ERROR,
1119            "Error while loading mapping language schema.", e);
1120        }
1121        
1122        /* initialize statements */
1123        initStatements();
1124        
1125        if (!boot)
1126        {
1127            /* loading UserTableManager */
1128            userTables = new UserTableManager(this);
1129            
1130            /* opening system collections */
1131            schemaCollection = openCollection(RepositoryConnection.SCHEMA_COLLECTION); // Open the system repository (ignore exception
1132
mappingCollection = openCollection(RepositoryConnection.MAPPING_COLLECTION); // Open the system repository (ignore exception
1133
}
1134   }
1135
1136    private void initStatements()
1137    {
1138        StringBuffer JavaDoc sql = new StringBuffer JavaDoc();
1139        sql.append("select distinct c.NAME from ");
1140        sql.append(getTableInfo(TableSpec.TYPE_PATHS).getName());
1141        sql.append(" p,");
1142        sql.append(getTableInfo(TableSpec.TYPE_COLLECTIONS).getName());
1143        sql.append(" c where p.NS=? and p.CID=c.CID");
1144        checkSchemaStmt = sql.toString();
1145        
1146        sql.setLength(0);
1147        sql.append("delete from ");
1148        sql.append(getTableInfo(TableSpec.TYPE_PATHS).getName());
1149        sql.append(" where CID=");
1150        deletePathSetStmt = sql.toString();
1151        
1152        sql.setLength(0);
1153        sql.append("select NAME from ");
1154        sql.append(getTableInfo(TableSpec.TYPE_COLLECTIONS).getName());
1155        sql.append(" where MAPPING_ID=?");
1156        checkMappingStmt = sql.toString();
1157        
1158        sql.setLength(0);
1159        sql.append("update ");
1160        sql.append(getTableInfo(TableSpec.TYPE_COLLECTIONS).getName());
1161        sql.append(" set DESCRIPTION=? WHERE CID=?");
1162        updateColDescStmt = sql.toString();
1163    }
1164    
1165    private Map loadTableInfo(RepositoryInfo info) throws RepositoryException
1166    {
1167        HashMap map = new HashMap();
1168        
1169        /* loading tableInfo */
1170        List tables = TableSpecLoader.getInstance().getTableSpecs(TableSpec.CAT_REPOSITORY, metadataConnection.getDBMSType());
1171        Iterator it = tables.iterator();
1172        TableSpec wSpec = null;
1173        
1174        long[] params = new long[TableInfo.PARAM_NUMBER];
1175        params[TableInfo.PARAM_CID_SIZE] = info.getColIDSize();
1176        
1177        while (it.hasNext())
1178        {
1179            wSpec = (TableSpec)it.next();
1180            map.put(new Byte JavaDoc(wSpec.getType()), new TableInfo(wSpec, params, metadataConnection));
1181        }
1182        return map;
1183    }
1184
1185    /** Close a collection identified by the <code>name</code> parameter
1186     * @param name the name of the collection.
1187     */

1188    private synchronized void cleanCollection(String JavaDoc name)
1189    throws RepositoryException
1190    {
1191        CollectionMetadata collection = (CollectionMetadata)collectionManager.remove(name.toUpperCase());
1192        if (collection != null)
1193        {
1194            try {
1195                if (collection.getMapping() != null) // TO CHECK (un mapping quand même ?)
1196
loadedMappings.remove(collection.getInfo().getProperty(RepositoryConnection.MAPPING_ID_PROPERTY));
1197            }
1198            catch (XMLDBCNotRecognizedException e) {
1199                // no op : internal use
1200
throw new RuntimeException JavaDoc("Internal error: unknown feature or property.");
1201            }
1202            collection.close();
1203        }
1204    }
1205    
1206    private void dropRepositoryTables() throws SQLException, XMLDBCException
1207    {
1208        // delete all tables with XQuark prefixes
1209
String JavaDoc pattern = TABLE_PREFIX + "%";
1210        Iterator it = metadataConnection.getUserTableNames(pattern).iterator();
1211        while (it.hasNext())
1212        {
1213            try
1214            {
1215                metadataConnection.dropTable((String JavaDoc)it.next());
1216            }
1217            catch (SQLException e)
1218            {
1219                // ignore
1220
}
1221        }
1222
1223        // delete all sequences with XQuark prefixes
1224
it = metadataConnection.getUserSequenceNames(pattern).iterator();
1225        while (it.hasNext())
1226        {
1227            try
1228            {
1229                metadataConnection.dropSequence((String JavaDoc)it.next());
1230            }
1231            catch (SQLException e)
1232            {
1233                // ignore
1234
}
1235        }
1236    }
1237
1238    public synchronized void refresh() throws XMLDBCException
1239    {
1240        Iterator it = collectionManager.iterator();
1241        
1242        while(it.hasNext())
1243            ((_Collection)it.next()).refresh();
1244    }
1245    
1246    ///////////////////////////////////////////////////////////////////////////
1247
// INNER CLASSES
1248
///////////////////////////////////////////////////////////////////////////
1249
private class ProxyCollection implements org.xquark.xquery.metadata.resolver.CollectionMetadata
1250    {
1251        String JavaDoc collectionName;
1252        XTree tree = null;
1253        
1254        public ProxyCollection(String JavaDoc collectionName)
1255        {
1256            this.collectionName = collectionName;
1257        }
1258        
1259        public XTree getXTree()
1260        {
1261            try
1262            {
1263                if (tree == null)
1264                    tree = getCollection(collectionName).getPathSet(); // won't be freed till LRU
1265
else
1266                    ((PathSet)tree).refresh();
1267            }
1268            catch (XMLDBCException e)
1269            { // TO SEE: How to process it ?
1270
throw new RuntimeException JavaDoc("Error while opening collection: " + e.getMessage());
1271            }
1272            return tree;
1273        }
1274        
1275        public String JavaDoc getCollectionName()
1276        {
1277            return collectionName;
1278        }
1279        
1280        public boolean isXTreeLoaded()
1281        {
1282            return tree != null;
1283        }
1284
1285        public Collection getRootNodes() {
1286            return null;
1287        }
1288
1289    }
1290    
1291}
1292
Popular Tags