KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > xquark > mapper > storage > XMLCollectionImpl


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.storage;
24
25 import java.io.StringWriter JavaDoc;
26 import java.sql.*;
27 import java.util.*;
28
29 import org.xquark.mapper.RepositoryConnection;
30 import org.xquark.mapper.RepositoryDocument;
31 import org.xquark.mapper.RepositoryException;
32 import org.xquark.mapper.dbms.*;
33 import org.xquark.mapper.mapping.MappingConstants;
34 import org.xquark.mapper.mapping.MappingFactory;
35 import org.xquark.mapper.mapping.MappingSetIterator;
36 import org.xquark.mapper.metadata.*;
37 import org.xquark.mapper.util.*;
38 import org.xquark.schema.validation.SchemaValidationContext;
39 import org.xquark.util.SAXConstants;
40 import org.xquark.xml.xdbc.*;
41
42
43 /** Common part ot the {@link org.xquark.mapper.XMLCollection XMLCollection}
44  * implementations.
45  *
46  * @see org.xquark.mapper.XMLCollection
47  */

48
49 public class XMLCollectionImpl
50 implements _RepositoryCollection, RepositoryConstants, SAXConstants
51 {
52     private static final String JavaDoc RCSRevision = "$Revision: 1.1 $";
53     private static final String JavaDoc RCSName = "$Name: $";
54     //
55
// Data
56
//
57
protected _RepositoryConnection repConnection;
58     protected AbstractConnection connection;
59     private DestructionToken destructor;
60     private CollectionMetadata metadata;
61     
62     /* data for removal and renaming */
63     protected JDBCBatcher batcher;
64     protected PreparedStatement removeStmt;
65     protected PreparedStatement removeStructStmt;
66     protected PreparedStatement removeExtraStmt;
67     protected ArrayList removeValuesStmts;
68     protected PreparedStatement renameStmt;
69     
70     protected HashSet filers = new HashSet(); // to close filers when closing & set modes
71
// contains SAXHandlers & not XMLDocumentFilers !!!
72
protected RepositoryReader cachedReader; // TO DO : instead of caching reader : put pstmt here !
73
private ArrayList removedDocDIDs;
74     
75     private boolean readOnly = false;
76     
77     /** Constructor.
78      * @param name The name of the repository.
79      * @param config A CollectionConfig object.
80      * and shared with other repositories of the same database.
81      * @exception java.sql.SQLException Relational database exception.
82      */

83     
84     public XMLCollectionImpl(CollectionMetadata metadata,
85     _RepositoryConnection connection, DestructionToken destructor)
86     {
87         repConnection = connection;
88         this.connection = connection.getConnection();
89         this.destructor = destructor;
90         this.metadata = metadata;
91         MappingFactory factory = new MappingFactory(
92             metadata.getMapping(),
93             connection.getSchemaManager(),
94             connection
95             );
96     }
97     
98     public CollectionMetadata getMetadata()
99     {
100         return metadata;
101     }
102     
103     /** Get an XMLReader object in order to perform SAX2 parsing which is the
104      * most performant method.
105      * @return an XMLReader object.
106      */

107     public RepositoryReader getReader() throws XMLDBCException
108     {
109         RepositoryReader ret;
110         if (cachedReader == null)
111             ret = new NSPrefixRepositoryFilter(new DocumentProducer(this));
112         else
113         {
114             ret = cachedReader;
115             cachedReader = null;
116         }
117         return ret;
118     }
119     
120     
121     /** Get an XMLReader object in order to perform SAX2 parsing which is the
122      * most performant method.
123      */

124     public void releaseReader(RepositoryReader reader)
125     throws RepositoryException
126     {
127         if (cachedReader == null)
128         {
129             reader.unPlug();
130             cachedReader = reader;
131         }
132         else
133             reader.close();
134     }
135     
136     /** Free all resources. Repository is warned that repository is closed.
137      * <B>Any subsequent call to a function of the object will raise an
138      * exception.</B>
139      */

140     public void close() throws XMLDBCException
141     {
142         // Must be done first because destruct call getCollectionName()
143
if (destructor != null)
144         {
145             try
146             {
147                 destructor.destruct(this);
148             }
149             catch (RepositoryRuntimeException e)
150             {
151                 throw e.getRepositoryException();
152             }
153             destructor = null;
154             
155             repConnection = null;
156             connection = null;
157             
158             metadata = null;
159             
160             closeFilers();
161             filers = null;
162             
163             if (cachedReader != null)
164                 cachedReader.close();
165
166             if (batcher != null) // does not close statements
167
try
168                 {
169                     batcher.close();
170                 }
171                 catch (SQLException e)
172                 {
173                     throw new RepositoryException(RepositoryException.DB_ERROR,
174                     "Could not close the JDBC Batcher");
175                 }
176             try
177             {
178                 if (removeStmt != null)
179                 {
180                     removeStmt.close();
181                     removeStmt = null;
182                 }
183                 if (removeStructStmt != null)
184                 {
185                     removeStructStmt.close();
186                     removeStructStmt = null;
187                 }
188                 if (removeExtraStmt != null)
189                 {
190                     removeExtraStmt.close();
191                     removeExtraStmt = null;
192                 }
193                 if (renameStmt != null)
194                 {
195                     renameStmt.close();
196                     renameStmt = null;
197                 }
198                 if (removeValuesStmts != null)
199                 {
200                     int len = removeValuesStmts.size();
201                     for (int i = 0; i < len; i++)
202                         ((PreparedStatement)removeValuesStmts.get(i)).close();
203                     removeValuesStmts = null;
204                 }
205             }
206             catch (SQLException e)
207             {
208                 // no op
209
}
210         }
211     }
212     
213     public _RepositoryConnection getRepositoryConnection()
214     {
215         return repConnection;
216     }
217     
218     public class HandlerDestructor implements DestructionToken
219     {
220         public void destruct(Object JavaDoc o)
221         {
222             filers.remove(o);
223         }
224     }
225     
226     public long getDocumentID(String JavaDoc ID)
227     throws SQLException, RepositoryException
228     {
229         Statement statement = null;
230         long docOID = -1;
231         try
232         {
233             statement = connection.getConnection().createStatement();
234             ResultSet rs = statement.executeQuery(
235             metadata.getSelectDocIDStmt() + ID + "'");
236             if(rs.next())
237                 docOID = rs.getLong(1);
238             rs.close();
239         }
240         finally
241         {
242             if (statement != null)
243                 statement.close();
244         }
245         return docOID;
246     }
247     
248     public CollectionInfo getInfo()
249     {
250         return metadata.getInfo();
251     }
252     
253     public String JavaDoc getCollectionName()
254     {
255         return metadata.getCollectionName();
256     }
257     
258     public String JavaDoc toString()
259     {
260         StringWriter JavaDoc out = new StringWriter JavaDoc();
261         Tabulator tabulator = new Tabulator
262                                     (
263                                     out,
264                                     79,
265                                     new int[] {0, 40}
266                                     );
267                                     
268                                     
269         tabulator.addItem("name");
270         tabulator.addItem(getCollectionName());
271         
272         String JavaDoc[] properties = getPropertyList();
273         for (int i = 0; i < properties.length; i++)
274         {
275             tabulator.addItem(properties[i].substring(properties[i].lastIndexOf('/') + 1));
276             try
277             {
278                 tabulator.addItem(getProperty(properties[i]));
279             }
280             catch (XMLDBCNotRecognizedException e)
281             {
282                 // no op
283
}
284         }
285         
286         String JavaDoc[] features = getFeatureList();
287         for (int i = 0; i < features.length; i++)
288         {
289             tabulator.addItem(features[i].substring(features[i].lastIndexOf('/') + 1));
290             try
291             {
292                 tabulator.addItem(String.valueOf(getFeature(features[i])));
293             }
294             catch (XMLDBCNotRecognizedException e)
295             {
296                 // no op
297
}
298         }
299         return out.toString();
300     }
301     
302     ///////////////////////////////////////////////////////////////////////////
303
// XMLCollection implementation
304
///////////////////////////////////////////////////////////////////////////
305

306     /**
307      * Creates a "filer" object that can be used to insert a new XML document
308      * into the XML collection. A single filer can store several
309      * documents sequentially, however it is an error to try to use a filer
310      * before the current storage is finished.<BR>
311      * @return an XMLDocumentFiler object.
312      * @throws XMLDBCException if a database access error occurs.
313      */

314     public XMLDocumentFiler getDocumentFiler() throws XMLDBCException
315     {
316         protectReadOnlyMethod();
317         SchemaValidationContext validationContext =
318         new SchemaValidationContext(repConnection.getSchemaManager());
319         ValidatingFilerAdapter validator = new ValidatingFilerAdapter(validationContext, repConnection);
320         validator.setDocumentBase("http://www.fake.com/");
321         CollectionFiler handler = new CollectionFiler
322         (
323         this,
324         validationContext,
325         !getFeature(RepositoryConnection.USE_SCHEMA_PREFIXES_FEATURE),
326         new XMLCollectionImpl.HandlerDestructor()
327         );
328         validator.setSAXHandler(handler);
329         filers.add(handler);
330         return new XDBCFilerAdapter(validator, handler, handler, handler);
331     }
332     
333     
334     public XMLConnection getConnection() throws XMLDBCException
335     {
336         return getRepositoryConnection();
337     }
338     
339     public XMLDocument getDocument(String JavaDoc documentID) throws XMLDBCException
340     {
341         return getRepositoryDocument(documentID);
342     }
343     
344     public boolean renameDocument(String JavaDoc oldID, String JavaDoc newID) throws XMLDBCException
345     {
346         return renameDocument(oldID, newID, true);
347     }
348     
349     /** @param useTransaction used during schema storage */
350     boolean renameDocument(String JavaDoc oldID, String JavaDoc newID, boolean useTransaction) throws XMLDBCException
351     {
352         protectReadOnlyMethod();
353         boolean ret = false;
354         // flush potential pending storages...
355
flushFilers();
356         // performs an update of the document list
357
if (useTransaction)
358             connection.start();
359         PreparedStatement statement = null;
360         try
361         {
362             statement = connection.getConnection().prepareStatement(metadata.getRenameDocStmt());
363             statement.setString(1, newID);
364             statement.setString(2, oldID);
365             statement.executeUpdate();
366         }
367         catch(SQLException e)
368         {
369             throw new RepositoryException(RepositoryException.DB_ERROR, "Relational database error while renaming a document in the document table.", e);
370         }
371         finally
372         {
373             try
374             {
375                 if (statement != null)
376                     statement.close();
377             }
378             catch (SQLException e)
379             {
380                 // no op
381
}
382         }
383         if (useTransaction && getConnection().getAutoCommit())
384         {
385              connection.commit();
386              commitPerformed();
387         }
388         return ret;
389     }
390     
391     public boolean removeDocument(String JavaDoc documentID) throws XMLDBCException
392     {
393         protectReadOnlyMethod();
394         boolean ret = false;
395         // flush potential pending storages...
396
flushFilers();
397         ret = removeDocumentUsingBatch(documentID);
398         batcher.flush();
399         if (getConnection().getAutoCommit())
400         {
401              connection.commit();
402              commitPerformed();
403         }
404         return ret;
405     }
406     
407     public boolean containsDocument(String JavaDoc documentID) throws XMLDBCException
408     {
409         boolean contains = false;
410         // check whether this document ID is present in the document table
411
Statement statement = null;
412         try
413         {
414             statement = connection.getConnection().createStatement();
415             ResultSet rs = statement.executeQuery(metadata.getContainsDocStmt() + documentID + "'");
416             
417             if (rs.next()&& (rs.getInt(1) > 0))
418                 contains = true;
419             
420             rs.close();
421         }
422         catch(SQLException e)
423         {
424             throw new RepositoryException(RepositoryException.DB_ERROR, "Relational database error while checking for document existence.", e);
425         }
426         finally
427         {
428             try
429             {
430                 if (statement != null)
431                     statement.close();
432             }
433             catch (SQLException e)
434             {
435                 // no op
436
}
437         }
438         return contains;
439     }
440     
441     
442     public String JavaDoc getName() throws XMLDBCException
443     {
444         return metadata.getCollectionName();
445     }
446     
447     public void setDescription(String JavaDoc description) throws XMLDBCException
448     {
449         metadata.updateDescription(description);
450     }
451     
452     public String JavaDoc getDescription() throws XMLDBCException
453     {
454         return getInfo().getDescription();
455     }
456     
457     public long getDocumentCount() throws XMLDBCException
458     {
459         // get the whole repository document table
460
long numDocs = 0;
461         Statement statement = null;
462         
463         try
464         {
465             statement = connection.getConnection().createStatement();
466             ResultSet rs = statement.executeQuery(metadata.getCountDocStmt());
467             
468             if (rs.next())
469                 numDocs = rs.getLong(1);
470             rs.close();
471         }
472         catch(SQLException e)
473         {
474             throw new RepositoryException(RepositoryException.DB_ERROR, "Relational database error while retrieving document list.", e);
475         }
476         finally
477         {
478             try
479             {
480                 if (statement != null)
481                     statement.close();
482             }
483             catch (SQLException e)
484             {
485                 // no op
486
}
487         }
488         return numDocs;
489     }
490     
491     public List getIdentifierList() throws XMLDBCException
492     {
493         ArrayList list = new ArrayList();
494         
495         // get the whole repository document table
496
Statement statement = null;
497         try
498         {
499             statement = connection.getConnection().createStatement();
500             ResultSet rs = statement.executeQuery(metadata.getDocListStmt());
501             
502             while (rs.next())
503             {
504                 list.add(rs.getString(1));
505             }
506             rs.close();
507         }
508         catch(SQLException e)
509         {
510             throw new RepositoryException(RepositoryException.DB_ERROR, "Relational database error while retrieving document list.", e);
511         }
512         finally
513         {
514             try
515             {
516                 if (statement != null)
517                     statement.close();
518             }
519             catch (SQLException e)
520             {
521                 // no op
522
}
523         }
524         return list;
525     }
526     
527     public int removeAllDocuments() throws XMLDBCException
528     {
529         protectReadOnlyMethod();
530         // flush potential pending storages...
531
flushFilers();
532         Iterator it = getIdentifierList().iterator();
533         int docCount = 0;
534         
535         while (it.hasNext())
536         {
537             removeDocumentUsingBatch((String JavaDoc)it.next());
538             docCount++;
539             if (getConnection().getAutoCommit())
540             {
541                 batcher.flush();
542                 connection.commit();
543                  commitPerformed();
544             }
545         }
546         if (batcher != null)
547             batcher.flush();
548         return docCount;
549     }
550     
551     public void setReadOnly(boolean readOnly) throws XMLDBCException
552     {
553         if (readOnly)
554             closeFilers();
555         this.readOnly = readOnly;
556     }
557     
558     public boolean isReadOnly() throws XMLDBCException
559     {
560         return readOnly;
561     }
562     
563     ///////////////////////////////////////////////////////////////////////////
564
// RepositoryCollection implementation
565
///////////////////////////////////////////////////////////////////////////
566
public List getRepositoryDocumentList() throws XMLDBCException
567     {
568         return metadata.getDocumentInfoList(this);
569     }
570     
571     public RepositoryDocument getRepositoryDocument(String JavaDoc documentID) throws XMLDBCException
572     {
573         return new RepositoryDocumentImpl(documentID, this);
574     }
575     
576     public void createIndexes() throws RepositoryException
577     {
578         protectReadOnlyMethod();
579         metadata.createIndexes();
580     }
581     
582     public void dropIndexes() throws RepositoryException
583     {
584         protectReadOnlyMethod();
585         metadata.dropIndexes();
586     }
587     
588     public void updateStatistics() throws XMLDBCException
589     {
590         protectReadOnlyMethod();
591         metadata.updateStatistics();
592     }
593     
594     ///////////////////////////////////////////////////////////////////////////
595
// _RepositoryCollection implementation
596
///////////////////////////////////////////////////////////////////////////
597
public void flushFilers() throws XMLDBCException
598     {
599         Iterator it = filers.iterator();
600         while (it.hasNext())
601         {
602             ((SAXHandler)it.next()).flushBuffer();
603         }
604     }
605     
606     public void commitPerformed() throws XMLDBCException
607     {
608         if (removedDocDIDs != null)
609             metadata.getUOIDManager().freeDocOIDs(removedDocDIDs);
610     }
611     
612     public void rollbackPerformed() throws XMLDBCException
613     {
614         if (removedDocDIDs != null)
615             removedDocDIDs.clear();
616     }
617     
618     public void restoreDID(long did)
619     {
620         if (removedDocDIDs == null)
621             removedDocDIDs = new ArrayList();
622         removedDocDIDs.add(new Long JavaDoc(did));
623     }
624     
625     ///////////////////////////////////////////////////////////////////////////
626
// Configurable implementation
627
///////////////////////////////////////////////////////////////////////////
628

629     public void setProperty(String JavaDoc propertyId, Object JavaDoc value) throws XMLDBCNotRecognizedException, XMLDBCNotSupportedException
630     {
631         getInfo().setProperty(propertyId, value);
632     }
633     
634     public Object JavaDoc getProperty(String JavaDoc propertyId) throws XMLDBCNotRecognizedException
635     {
636         return getInfo().getProperty(propertyId);
637     }
638     
639     public String JavaDoc[] getPropertyList()
640     {
641         return getInfo().getPropertyList();
642     }
643     
644     public void setFeature(String JavaDoc featureId, boolean state) throws XMLDBCNotRecognizedException, XMLDBCNotSupportedException
645     {
646         getInfo().setFeature(featureId, state);
647     }
648     
649     public boolean getFeature(String JavaDoc featureId) throws XMLDBCNotRecognizedException
650     {
651         return getInfo().getFeature(featureId);
652     }
653     
654     public String JavaDoc[] getFeatureList()
655     {
656         return getInfo().getFeatureList();
657     }
658     
659     ///////////////////////////////////////////////////////////////////////////
660
// PRIVATE UTILITIES
661
///////////////////////////////////////////////////////////////////////////
662
private boolean removeDocumentUsingBatch(String JavaDoc documentID) throws XMLDBCException
663     {
664         if (batcher == null)
665             batcher = new JDBCBatcher(connection, true);
666         
667         long UDID;
668         if (documentID == null)
669             throw new RepositoryException(RepositoryException.ILLEGAL_EXPRESSION, "The ID is mandatory to remove document.");
670         // remove useless spaces
671
documentID = documentID.trim();
672         
673         try
674         {
675             UDID = getDocumentID(documentID);
676         }
677         catch(SQLException e)
678         {
679             throw new RepositoryException(RepositoryException.DB_ERROR, "Relational database error while retrieving the internal numeric ID.", e);
680         }
681         if (UDID < 0)
682             return false;
683         
684         long first = metadata.getUOIDManager().getDocMinUOID(UDID);
685         long last = metadata.getUOIDManager().getDocMaxUOID(UDID);
686         
687         // Delete first the document ID
688
connection.start();
689         try
690         {
691             if (removeStmt == null)
692             {
693                 String JavaDoc tableName = metadata.getTableInfo(TableSpec.TYPE_DOCS).getName();
694                 removeStmt = connection.getConnection().prepareStatement(metadata.getDeleteDocIDStmt());
695                 batcher.addStatement(removeStmt, tableName, RepositoryProperties.getIntProperty(CONF_REMOVE_BATCHSIZE));
696             }
697             removeStmt.setString(1, documentID);
698             batcher.addBatch(removeStmt);
699             
700             // Delete then document struct rows
701
if (removeStructStmt == null)
702             {
703                 TableInfo table = metadata.getTableInfo(TableSpec.TYPE_STRUCT);
704                 removeStructStmt = StructSaver.getDeleteStatement(connection, table);
705                 batcher.addStatement(removeStructStmt, table.getName(), RepositoryProperties.getIntProperty(CONF_REMOVE_BATCHSIZE));
706             }
707             removeStructStmt.setLong(1, first);
708             removeStructStmt.setLong(2, last);
709             batcher.addBatch(removeStructStmt);
710             
711             // Delete then document extra-data rows
712
if (removeExtraStmt == null)
713             {
714                 TableInfo table = metadata.getTableInfo(TableSpec.TYPE_EXTRA);
715                 removeExtraStmt = ExtraDataSaver.getDeleteStatement(connection, table);
716                 batcher.addStatement(removeExtraStmt, table.getName(), RepositoryProperties.getIntProperty(CONF_REMOVE_BATCHSIZE));
717             }
718             
719             removeExtraStmt.setLong(1, first);
720             removeExtraStmt.setLong(2, last);
721             batcher.addBatch(removeExtraStmt);
722             
723             // Delete then document value rows
724
removeValues(first, last);
725             
726             // recycle doc OID but only when committed because other instances
727
// must not use it before it is effective in the database
728
restoreDID(metadata.getUOIDManager().getDID(UDID));
729             
730         }
731         catch(Exception JavaDoc e)
732         {
733             try
734             {
735                 if (getConnection().getAutoCommit())
736                     connection.rollback();
737                 rollbackPerformed(); // automatic
738
}
739             catch(SQLException sqle)
740             {
741                 // no op : rdbms is supposed to have performed rollback
742
}
743             if (e instanceof RepositoryException)
744                 throw (RepositoryException)e;
745             else
746                 throw new RepositoryException(RepositoryException.DB_ERROR, "Relational database error while deleting document rows.", e);
747         }
748         return true;
749     }
750     
751     private void removeValues(long first, long last)
752     throws SQLException, RepositoryException
753     {
754         PreparedStatement stmt = null;
755         
756         /* Put statements in batcher if not initialized */
757         if (removeValuesStmts == null)
758         {
759             removeValuesStmts = new ArrayList();
760         /* Delete the values in user tables for table of 'INSERT' type. That means
761          * tables where tuples are not supposed to exist before document storage.
762          * The collection given by the mapping is supposed to be ordered so there
763          * is no reference constraint broken.
764          */

765             MappingSetIterator it = getMetadata().getSortedTableMappingSetIterator(true);
766             CollectionMappingInfo table;
767             
768             while (it.hasNext())
769             {
770                 table = (CollectionMappingInfo)it.next();
771                 String JavaDoc SQLString = null;
772                 
773                 if (it.isTableFirstOccurence())
774                 {
775                     // user table : only if storage mode is INSERT else data is supposed to pre-exist
776
if (table.getTableMapping().getAction() == MappingConstants.INSERT)
777                     {
778                         if (table.getTableMapping().isClustered())
779                             SQLString = table.getDeleteStatement();
780                         else
781                             SQLString = connection.getDeleteUserTableRowsStatement(
782                             table.getTableMapping().getTableName(),
783                             table.getDocumentRowsStatement()
784                             );
785                         stmt = connection.getConnection().prepareStatement(SQLString);
786                         removeValuesStmts.add(stmt);
787                         batcher.addStatement(stmt,table.getTableMapping().getTableName(),
788                         RepositoryProperties.getIntProperty(CONF_REMOVE_BATCHSIZE));
789                     }
790                     
791                     // OID table (in fact user table if clustering...)
792
SQLString = table.getOIDDeleteStatement();
793                     if (!table.getTableMapping().isClustered())
794                     {
795                         stmt = connection.getConnection().prepareStatement(table.getOIDDeleteStatement());
796                         removeValuesStmts.add(stmt);
797                         batcher.addStatement(stmt,table.getTableMapping().getTableName(),
798                         RepositoryProperties.getIntProperty(CONF_REMOVE_BATCHSIZE));
799                     }
800                 }
801             }
802         }
803         /* Put statements in the batcher */
804         int len = removeValuesStmts.size();
805         
806         for(int i = 0; i < len; i++)
807         {
808             stmt = (PreparedStatement)removeValuesStmts.get(i);
809             stmt.setLong(1, first);
810             stmt.setLong(2, last);
811             batcher.addBatch(stmt);
812         }
813     }
814     
815     protected void protectReadOnlyMethod() throws RepositoryException
816     {
817         if (readOnly)
818             throw new RepositoryException(RepositoryException.NOT_ALLOWED,
819             "Such operation is forbidden because collection is read-only.");
820     }
821     
822     private void closeFilers() throws XMLDBCException
823     {
824         Iterator it = ((HashSet)filers.clone()).iterator();
825         while(it.hasNext())
826         {
827             ((SAXHandler)it.next()).close();
828             it.remove();
829         }
830     }
831 } // class
832
Popular Tags