kevinross 2003/07/14 12:07:16
Modified: java/src/org/apache/xindice/util Configurable.java XindiceRuntimeException.java XindiceException.java ConfigurationException.java java/src/org/apache/xindice/core DBObject.java MetaSystemCollection.java DBObserver.java FaultCodes.java DocumentCache.java DBException.java Container.java Database.java Collection.java SystemCollection.java CollectionManager.java java/src/org/apache/xindice/client/xmldb/embed DatabaseImpl.java Log: refactoring for javabeans coding conventions including: -naming -accessibility of members. -javadoc comments Revision Changes Path 1.3 +15 -17 xml-xindice/java/src/org/apache/xindice/util/Configurable.java Index: Configurable.java =================================================================== RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/util/Configurable.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- Configurable.java 31 Oct 2002 07:01:45 -0000 1.2 +++ Configurable.java 14 Jul 2003 19:07:14 -0000 1.3 @@ -59,8 +59,6 @@ * $Id$ */ - - /** * Configurable is a simple interface used to pass configuration information * to an object. The implementing object is ultimately responsible for @@ -77,19 +75,19 @@ */ public interface Configurable { - /** - * setConfig sets the configuration information for the Configurable - * object instance. - * - * @param config The configuration Node - */ - void setConfig(Configuration config) throws XindiceException; + /** + * setConfig sets the configuration information for the Configurable + * object instance. + * + * @param config The configuration Node + */ + void setConfig(Configuration config) throws XindiceException; - /** - * getConfig retrieves the configuration information for the - * Configurable object instance. - * - * @return The configuration Node - */ - Configuration getConfig(); + /** + * getConfig retrieves the configuration information for the + * Configurable object instance. + * + * @return The configuration Node + */ + Configuration getConfig(); } 1.2 +6 -1 xml-xindice/java/src/org/apache/xindice/util/XindiceRuntimeException.java Index: XindiceRuntimeException.java =================================================================== RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/util/XindiceRuntimeException.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- XindiceRuntimeException.java 14 Jul 2003 18:28:45 -0000 1.1 +++ XindiceRuntimeException.java 14 Jul 2003 19:07:14 -0000 1.2 @@ -74,6 +74,11 @@ super(message); } + public XindiceRuntimeException(Throwable cause) { + super(); + this.cause = cause; + } + public XindiceRuntimeException(String message, Throwable cause) { super(message); this.cause = cause; 1.6 +7 -2 xml-xindice/java/src/org/apache/xindice/util/XindiceException.java Index: XindiceException.java =================================================================== RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/util/XindiceException.java,v retrieving revision 1.5 retrieving revision 1.6 diff -u -r1.5 -r1.6 --- XindiceException.java 14 Jul 2003 18:28:45 -0000 1.5 +++ XindiceException.java 14 Jul 2003 19:07:14 -0000 1.6 @@ -74,7 +74,12 @@ public XindiceException(String message) { super(message); } - + + public XindiceException(Throwable cause) { + super(); + this.cause = cause; + } + public XindiceException(String message, Throwable cause) { super(message); this.cause = cause; 1.2 +4 -0 xml-xindice/java/src/org/apache/xindice/util/ConfigurationException.java Index: ConfigurationException.java =================================================================== RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/util/ConfigurationException.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- ConfigurationException.java 14 Jul 2003 18:28:45 -0000 1.1 +++ ConfigurationException.java 14 Jul 2003 19:07:14 -0000 1.2 @@ -26,4 +26,8 @@ public ConfigurationException(String message, Throwable cause) { super(message, cause); } + + public ConfigurationException(Throwable cause) { + super(cause); + } } 1.3 +48 -50 xml-xindice/java/src/org/apache/xindice/core/DBObject.java Index: DBObject.java =================================================================== RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/core/DBObject.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- DBObject.java 31 Oct 2002 06:59:56 -0000 1.2 +++ DBObject.java 14 Jul 2003 19:07:14 -0000 1.3 @@ -59,8 +59,6 @@ * $Id$ */ - - /** * DBObject is the interface implemented by all Xindice database objects. * DBObjects are typically objects that can be managed using XML @@ -71,51 +69,51 @@ */ public interface DBObject { - /** - * create creates a new DBObject and any associated resources for the new - * DBObject, such as disk files, etc. - * - * @return Whether or not the DBObject was created - */ - boolean create() throws DBException; - - /** - * open opens the DBObject - * - * @return Whether or not the DBObject was opened - */ - boolean open() throws DBException; - - /** - * isOpened returns whether or not the DBObject is opened for business. - * - * @return The open status of the DBObject - */ - boolean isOpened() throws DBException; - - /** - * exists returns whether or not a physical representation of this - * DBObject actually exists. In the case of a HashFiler, this would - * check for the file, and in the case of an FTPFiler, it might - * perform a connection check. - * - * @return Whether or not the physical resource exists - */ - boolean exists() throws DBException; - - /** - * drop instructs the DBObjectimplementation to remove itself from - * existence. The DBObject's parent is responsible for removing any - * references to the DBObject in its own context. - * - * @return Whether or not the DBObject was dropped - */ - boolean drop() throws DBException; - - /** - * close closes the DBObject - * - * @return Whether or not the DBObject was closed - */ - boolean close() throws DBException; + /** + * create creates a new DBObject and any associated resources for the new + * DBObject, such as disk files, etc. + * + * @return Whether or not the DBObject was created + */ + boolean create() throws DBException; + + /** + * open opens the DBObject + * + * @return Whether or not the DBObject was opened + */ + boolean open() throws DBException; + + /** + * isOpened returns whether or not the DBObject is opened for business. + * + * @return The open status of the DBObject + */ + boolean isOpened() throws DBException; + + /** + * exists returns whether or not a physical representation of this + * DBObject actually exists. In the case of a HashFiler, this would + * check for the file, and in the case of an FTPFiler, it might + * perform a connection check. + * + * @return Whether or not the physical resource exists + */ + boolean exists() throws DBException; + + /** + * drop instructs the DBObjectimplementation to remove itself from + * existence. The DBObject's parent is responsible for removing any + * references to the DBObject in its own context. + * + * @return Whether or not the DBObject was dropped + */ + boolean drop() throws DBException; + + /** + * close closes the DBObject + * + * @return Whether or not the DBObject was closed + */ + boolean close() throws DBException; } 1.3 +61 -96 xml-xindice/java/src/org/apache/xindice/core/MetaSystemCollection.java Index: MetaSystemCollection.java =================================================================== RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/core/MetaSystemCollection.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- MetaSystemCollection.java 27 Mar 2003 07:05:32 -0000 1.2 +++ MetaSystemCollection.java 14 Jul 2003 19:07:14 -0000 1.3 @@ -59,7 +59,6 @@ * $Id$ */ - import java.util.StringTokenizer; import org.apache.commons.logging.Log; @@ -69,52 +68,48 @@ import org.apache.xindice.xml.dom.DOMParser; import org.w3c.dom.Document; - - /** * MetaSystemCollection represents the Meta System Collection. Beyond * standard Collection operations, this class will provide facilities * for Meta data management. */ -public final class MetaSystemCollection extends Collection -{ - public static final String METACOL = "meta"; - public static final String METAS = "Metas"; +public final class MetaSystemCollection extends Collection { + public static final String METACOL = "meta"; + public static final String METAS = "Metas"; public static final String COLLECTION_META_DATA = "_META_DATA_"; private String dbCanonicalName; private String metaCanonicalName; - private static Log log = LogFactory.getLog("org.apache.xindice.core"); + private static Log log = LogFactory.getLog("org.apache.xindice.core"); - public MetaSystemCollection(Database db) - { + public MetaSystemCollection(Database db) { super(db); } - public void init() throws DBException - { + public void init() throws DBException { // Bootstrap the System Collection - String MetaCol = - "<collection name=\""+METACOL+"\">" - // Meta System Collections - + " <collections>" - // Meta Collections - + " <collection name=\""+METAS+"\" compressed=\"true\">" - + " <filer class=\"org.apache.xindice.core.filer.BTreeFiler\" />" - + " </collection>" - - + " </collections>" - + "</collection>"; + String MetaCol = + "<collection name=\"" + METACOL + "\">" + // Meta System Collections + +" <collections>" + // Meta Collections + +" <collection name=\"" + + METAS + + "\" compressed=\"true\">" + + " <filer class=\"org.apache.xindice.core.filer.BTreeFiler\" />" + + " </collection>" + + " </collections>" + + "</collection>"; try { Document metaDoc = DOMParser.toDocument(MetaCol); Configuration metaCfg = new Configuration(metaDoc, false); setConfig(metaCfg); } - catch ( Exception e ) { - if (log.isFatalEnabled()) { - log.fatal("FATAL ERROR: Generating System Collection '"+METACOL+"'", e); + catch (Exception e) { + if (log.isFatalEnabled()) { + log.fatal("FATAL ERROR: Generating System Collection '" + METACOL + "'", e); } System.exit(1); } @@ -127,58 +122,47 @@ /** * Returns the corresponding Meta Collection for the given * collection, optionally creating the hierarchy - * - * @param collection the collection whose meta you want - * @param create whether or not to create the meta if its missing - * @return collection the meta collection for the requested collection + * + * @param collection the collection whose meta you want + * @param create whether or not to create the meta if its missing + * @return collection the meta collection for the requested collection */ - public Collection getMetaCollection(Collection collection, - boolean create) - throws DBException - { + public Collection getMetaCollection(Collection collection, boolean create) throws DBException { String path = collection.getCanonicalName(); // different database - if( !path.startsWith(dbCanonicalName) ) + if (!path.startsWith(dbCanonicalName)) return null; // this is a meta collection - if( path.startsWith(metaCanonicalName) ) + if (path.startsWith(metaCanonicalName)) return null; Collection current = getCollection(METAS); - StringTokenizer st = new StringTokenizer( - path.substring(dbCanonicalName.length()), "/"); + StringTokenizer st = new StringTokenizer(path.substring(dbCanonicalName.length()), "/"); - while( current != null && st.hasMoreTokens() ) - { + while (current != null && st.hasMoreTokens()) { String segment = st.nextToken().trim(); - if ( segment.length() == 0 ) - continue; + if (segment.length() == 0) + continue; Collection childcol = current.getCollection(segment); - if( null == childcol ) - { - if( !create ) + if (null == childcol) { + if (!create) return null; String cfgText = - "<collection name=\""+segment+"\" compressed=\"true\">" + - " <filer class=\"org.apache.xindice.core.filer.BTreeFiler\" />" + - "</collection>"; + "<collection name=\"" + segment + "\" compressed=\"true\">" + " <filer class=\"org.apache.xindice.core.filer.BTreeFiler\" />" + "</collection>"; - try - { + try { Document cfgDoc = DOMParser.toDocument(cfgText); Configuration cfg = new Configuration(cfgDoc, false); childcol = current.createCollection(segment, cfg); } - catch( DBException de ) - { + catch (DBException de) { throw de; } - catch( Exception e ) - { + catch (Exception e) { throw new DBException(FaultCodes.getFaultCode(e)); } } @@ -194,16 +178,13 @@ * * @param collection The Collection whose meta is required */ - public void dropCollectionMeta(Collection collection) - throws DBException - { + public void dropCollectionMeta(Collection collection) throws DBException { Collection mcol = getMetaCollection(collection, false); - if( null != mcol ) - { + if (null != mcol) { try { mcol.drop(); } - catch( DBException e ) { + catch (DBException e) { // fail silently } } @@ -217,18 +198,15 @@ * @param collection The Collection whose meta is required * @return The requested MetaData */ - public MetaData getCollectionMeta(Collection collection) - throws DBException - { + public MetaData getCollectionMeta(Collection collection) throws DBException { Collection mcol = getMetaCollection(collection, true); - if( null != mcol ) - { - MetaData meta = (MetaData)mcol.getObject(COLLECTION_META_DATA); - if ( meta == null ) + if (null != mcol) { + MetaData meta = (MetaData) mcol.getObject(COLLECTION_META_DATA); + if (meta == null) meta = new MetaData(); - if( meta.getType() == MetaData.UNKNOWN ) + if (meta.getType() == MetaData.UNKNOWN) meta.setType(MetaData.COLLECTION); meta.setOwner(collection.getCanonicalName()); meta.setDirty(false); @@ -243,15 +221,12 @@ * @param collection The Collection that owns the MetaData * @param meta The MetaData */ - public void setCollectionMeta(Collection collection, MetaData meta) - throws DBException - { - if( null == meta ) + public void setCollectionMeta(Collection collection, MetaData meta) throws DBException { + if (null == meta) return; Collection mcol = getMetaCollection(collection, true); - if( null != mcol ) - { + if (null != mcol) { mcol.setObject(COLLECTION_META_DATA, meta); meta.setDirty(false); } @@ -264,16 +239,13 @@ * @param collection The Collection whose meta is required * @param id the Document id */ - public void dropDocumentMeta(Collection collection, String id) - throws DBException - { + public void dropDocumentMeta(Collection collection, String id) throws DBException { Collection mcol = getMetaCollection(collection, false); - if( null != mcol ) - { + if (null != mcol) { try { mcol.remove(id); } - catch( DBException e ) { + catch (DBException e) { // fail silently } } @@ -287,17 +259,14 @@ * @param id the ID * @return The requested MetaData */ - public MetaData getDocumentMeta(Collection collection, String id) - throws DBException - { + public MetaData getDocumentMeta(Collection collection, String id) throws DBException { Collection mcol = getMetaCollection(collection, true); - if( null != mcol ) - { - MetaData meta = (MetaData)mcol.getObject(id); - if ( meta == null ) + if (null != mcol) { + MetaData meta = (MetaData) mcol.getObject(id); + if (meta == null) meta = new MetaData(); - if( meta.getType() == MetaData.UNKNOWN ) + if (meta.getType() == MetaData.UNKNOWN) meta.setType(MetaData.DOCUMENT); meta.setOwner(collection.getCanonicalName() + "/" + id); meta.setDirty(false); @@ -313,18 +282,14 @@ * @param id * @param meta The MetaData */ - public void setDocumentMeta(Collection collection, String id, MetaData meta) - throws DBException - { - if( null == meta ) + public void setDocumentMeta(Collection collection, String id, MetaData meta) throws DBException { + if (null == meta) return; Collection mcol = getMetaCollection(collection, true); - if( null != mcol ) - { + if (null != mcol) { mcol.setObject(id, meta); meta.setDirty(false); } } } - 1.4 +38 -63 xml-xindice/java/src/org/apache/xindice/core/DBObserver.java Index: DBObserver.java =================================================================== RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/core/DBObserver.java,v retrieving revision 1.3 retrieving revision 1.4 diff -u -r1.3 -r1.4 --- DBObserver.java 14 Jul 2003 17:23:56 -0000 1.3 +++ DBObserver.java 14 Jul 2003 19:07:14 -0000 1.4 @@ -1,114 +1,89 @@ package org.apache.xindice.core; +import java.util.Map; + import org.apache.xindice.core.data.Key; import org.apache.xindice.core.data.Record; import org.apache.xindice.util.Configuration; - -import org.w3c.dom.*; - -import java.util.Map; +import org.w3c.dom.Document; /** * Observer for Xindice DB activities */ -public abstract class DBObserver -{ - private static final DBObserver NOOP = new DBObserver() - { - public void setDatabaseConfig( - Database db, Map collections, Configuration cfg ) {} +public abstract class DBObserver { + + private static final DBObserver NOOP = new DBObserver() { + public void setDatabaseConfig(Database db, Map collections, Configuration cfg) {} - public void setCollectionConfig( - Collection col, Configuration cfg ) {} + public void setCollectionConfig(Collection col, Configuration cfg) {} - public void flushDatabaseConfig( - Database db, Configuration cfg ) {} - - public void dropCollection( Collection col ) - throws DBException {} + public void flushDatabaseConfig(Database db, Configuration cfg) {} + + public void dropCollection(Collection col) throws DBException {} + + public void createCollection(Collection col) throws DBException {} - public void createCollection( Collection col ) - throws DBException {} + public void putDocument(Collection col, Key key, Document document, boolean create) throws DBException {} - public void putDocument( - Collection col, Key key, Document document, boolean create ) - throws DBException {} - - public void loadDocument( - Collection col, Record record, Document document ) - throws DBException {} - - public void dropDocument( Collection col, Key key ) - throws DBException {} + public void loadDocument(Collection col, Record record, Document document) throws DBException {} + + public void dropDocument(Collection col, Key key) throws DBException {} }; private static DBObserver instance = NOOP; /** * Sets the default observer instance - */ - public static void setInstance( DBObserver obs ) - { - instance = (null == obs) ? NOOP : obs; + */ + public static void setInstance(DBObserver obs) { + instance = (null == obs) ? NOOP : obs; } /** * Returns the observer instance, must be non-null - */ - public static DBObserver getInstance() - { - return instance; + */ + public static DBObserver getInstance() { + return instance; } - + /** * Called after Database.setConfig() - */ - public abstract void setDatabaseConfig( - Database db, Map collections, Configuration cfg ); + */ + public abstract void setDatabaseConfig(Database db, Map collections, Configuration cfg); /** * Called after Collection.setConfig() - */ - public abstract void setCollectionConfig( - Collection col, Configuration cfg ); + */ + public abstract void setCollectionConfig(Collection col, Configuration cfg); /** * Called after Database.flushConfig() */ - public abstract void flushDatabaseConfig( - Database db, Configuration cfg ); - + public abstract void flushDatabaseConfig(Database db, Configuration cfg); + /** * Called before Collection.drop() */ - public abstract void dropCollection( Collection col ) - throws DBException; + public abstract void dropCollection(Collection col) throws DBException; /** * Called after Collection.create() */ - public abstract void createCollection( Collection col ) - throws DBException; + public abstract void createCollection(Collection col) throws DBException; /** * Called after Collection.putDocument() - */ - public abstract void putDocument( - Collection col, Key key, Document document, boolean create ) - throws DBException; + */ + public abstract void putDocument(Collection col, Key key, Document document, boolean create) throws DBException; /** * Called after Collection.getDocument() - */ - public abstract void loadDocument( - Collection col, Record record, Document document ) - throws DBException; + */ + public abstract void loadDocument(Collection col, Record record, Document document) throws DBException; /** * Called before Collection.remove(key) */ - public abstract void dropDocument( Collection col, Key key ) - throws DBException; - -} + public abstract void dropDocument(Collection col, Key key) throws DBException; +} 1.11 +253 -253 xml-xindice/java/src/org/apache/xindice/core/FaultCodes.java Index: FaultCodes.java =================================================================== RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/core/FaultCodes.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- FaultCodes.java 11 Jun 2003 03:56:47 -0000 1.10 +++ FaultCodes.java 14 Jul 2003 19:07:14 -0000 1.11 @@ -71,256 +71,256 @@ */ public abstract class FaultCodes { - private static final Map faultMessages = new HashMap(); - public static final int GEN = (int) (0l); - public static final int OBJ = (int) (100l); - public static final int COL = (int) (200l); - public static final int IDX = (int) (300l); - public static final int TRX = (int) (400l); - public static final int DBE = (int) (500l); - public static final int QRY = (int) (600l); - public static final int SEC = (int) (700l); - public static final int URI = (int) (800l); - public static final int JAVA = (int) (2000l); - public static final int GEN_UNKNOWN = (int) (0l); - public static final int GEN_GENERAL_ERROR = (int) (40l); - public static final int GEN_CRITICAL_ERROR = (int) (70l); - public static final int GEN_FATAL_ERROR = (int) (90l); - public static final int COL_COLLECTION_NOT_FOUND = (int) (200l); - public static final int COL_DOCUMENT_NOT_FOUND = (int) (201l); - public static final int COL_DUPLICATE_COLLECTION = (int) (240l); - public static final int COL_NULL_RESULT = (int) (241l); - public static final int COL_NO_FILER = (int) (242l); - public static final int COL_NO_INDEXMANAGER = (int) (242l); - public static final int COL_DOCUMENT_MALFORMED = (int) (243l); - public static final int COL_CANNOT_STORE = (int) (244l); - public static final int COL_CANNOT_RETRIEVE = (int) (245l); - public static final int COL_COLLECTION_READ_ONLY = (int) (246l); - public static final int COL_COLLECTION_CLOSED = (int) (247l); - public static final int COL_CANNOT_CREATE = (int) (270l); - public static final int COL_CANNOT_DROP = (int) (271l); - public static final int COL_INVALID_RESULT = (int) (277l); - public static final int IDX_VALUE_NOT_FOUND = (int) (300l); - public static final int IDX_INDEX_NOT_FOUND = (int) (301l); - public static final int IDX_MATCHES_NOT_FOUND = (int) (340l); - public static final int IDX_DUPLICATE_INDEX = (int) (341l); - public static final int IDX_NOT_SUPPORTED = (int) (370l); - public static final int IDX_STYLE_NOT_FOUND = (int) (371l); - public static final int IDX_CORRUPTED = (int) (372l); - public static final int IDX_CANNOT_CREATE = (int) (373l); - public static final int TRX_DOC_LOCKED = (int) (400l); - public static final int TRX_NO_CONTEXT = (int) (440l); - public static final int TRX_NOT_ACTIVE = (int) (441l); - public static final int TRX_NOT_SUPPORTED = (int) (470l); - public static final int DBE_NO_PARENT = (int) (500l); - public static final int DBE_CANNOT_DROP = (int) (570l); - public static final int DBE_CANNOT_CREATE = (int) (571l); - public static final int QRY_NULL_RESULT = (int) (600l); - public static final int QRY_COMPILATION_ERROR = (int) (640l); - public static final int QRY_PROCESSING_ERROR = (int) (641l); - public static final int QRY_NOT_SUPPORTED = (int) (670l); - public static final int QRY_STYLE_NOT_FOUND = (int) (671l); - public static final int SEC_INVALID_USER = (int) (770l); - public static final int SEC_INVALID_GROUP = (int) (771l); - public static final int SEC_INVALID_ACCESS = (int) (772l); - public static final int SEC_INVALID_CREDENTIALS = (int) (773l); - public static final int URI_EMPTY = (int) (800l); - public static final int URI_NULL = (int) (801l); - public static final int URI_PARSE_ERROR = (int) (820l); - public static final int JAVA_RUNTIME_ERROR = (int) (2070l); - - private FaultCodes() {} - - static { - // General errors 0 series - putCodeMessage(GEN_UNKNOWN, "Unknown"); - putCodeMessage(GEN_GENERAL_ERROR, "General Error"); - putCodeMessage(GEN_CRITICAL_ERROR, "Critical Error"); - putCodeMessage(GEN_FATAL_ERROR, "Fatal Error"); - - // Collection-related errors 200 series - putCodeMessage(COL_COLLECTION_NOT_FOUND, "Collection Not Found"); - putCodeMessage(COL_DOCUMENT_NOT_FOUND, "Collection Document Not Found"); - putCodeMessage(COL_DUPLICATE_COLLECTION, "Collection Duplicated"); - putCodeMessage(COL_NULL_RESULT, "Collection Null Result"); - putCodeMessage(COL_NO_FILER, "Collection No Filer"); - putCodeMessage(COL_NO_INDEXMANAGER, "Collection No IndexManager"); - putCodeMessage(COL_DOCUMENT_MALFORMED, "Collection Document Malformed"); - putCodeMessage(COL_CANNOT_STORE, "Collection Cannot Store"); - putCodeMessage(COL_CANNOT_RETRIEVE, "Collection Cannot Retrieve"); - putCodeMessage(COL_COLLECTION_READ_ONLY, "Collection Read-only"); - putCodeMessage(COL_COLLECTION_CLOSED, "Collection Closed"); - putCodeMessage(COL_CANNOT_CREATE, "Collection Cannot Create"); - putCodeMessage(COL_CANNOT_DROP, "Collection Cannot Drop"); - putCodeMessage(COL_INVALID_RESULT, "Collection Invalid Result"); - - // Index-related errors 300 series - putCodeMessage(IDX_VALUE_NOT_FOUND, "Index Value Not Found"); - putCodeMessage(IDX_INDEX_NOT_FOUND, "Index Not Found"); - putCodeMessage(IDX_MATCHES_NOT_FOUND, "Index Matches Not Found"); - putCodeMessage(IDX_DUPLICATE_INDEX, "Index Duplicate Index"); - putCodeMessage(IDX_NOT_SUPPORTED, "Index Not Supported"); - putCodeMessage(IDX_STYLE_NOT_FOUND, "Index Style Not Found"); - putCodeMessage(IDX_CORRUPTED, "Index Corrupted"); - putCodeMessage(IDX_CANNOT_CREATE, "Index Cannot Create"); - - // Transaction-related errors 400 series - putCodeMessage(TRX_DOC_LOCKED, "Transaction Document Locked"); - putCodeMessage(TRX_NO_CONTEXT, "Transaction No Context"); - putCodeMessage(TRX_NOT_ACTIVE, "Transaction Not Active"); - putCodeMessage(TRX_NOT_SUPPORTED, "Transaction Not Supported"); - - // Database-related errors 500 series - putCodeMessage(DBE_NO_PARENT, "Database No Parent"); - putCodeMessage(DBE_CANNOT_DROP, "Database Cannot Drop"); - putCodeMessage(DBE_CANNOT_CREATE, "Database Cannot Create"); - - // Query-related errors 600 series - putCodeMessage(QRY_NULL_RESULT, "Query Null Result"); - putCodeMessage(QRY_COMPILATION_ERROR, "Query Compilation Error"); - putCodeMessage(QRY_PROCESSING_ERROR, "Query Processing Error"); - putCodeMessage(QRY_NOT_SUPPORTED, "Query Not Supported"); - putCodeMessage(QRY_STYLE_NOT_FOUND, "Query Style Not Found"); - - // Security-related errors 700 series - putCodeMessage(SEC_INVALID_USER, "Security Invalid User"); - putCodeMessage(SEC_INVALID_GROUP, "Security Invalid Group"); - putCodeMessage(SEC_INVALID_ACCESS, "Security Invalid Access"); - putCodeMessage(SEC_INVALID_CREDENTIALS, "Security Invalid Credentials"); - - // URI-related errors 800 series - putCodeMessage(URI_EMPTY, "URI Empty"); - putCodeMessage(URI_NULL, "URI Null"); - putCodeMessage(URI_PARSE_ERROR, "URI Parse Error"); - - // Java-related errors 2000 series - putCodeMessage(JAVA_RUNTIME_ERROR, "Java Runtime Error"); - } - - private static void putCodeMessage(int code, String message) { - faultMessages.put(new Integer(code), message); - } - - /** - * getMessage returns a textual form for the specified fault code. - * - * @param code The Fault Code - * @return It's textual form - */ - public static String getMessage(int code) { - String msg = (String) faultMessages.get(new Integer(code)); - return msg != null ? msg : ""; - } - - /** - * createXMLDBException creates an XMLDBException instance based - * on the specified Exception. If the Exception is a DBException, - * it will extract any important information from it (like fault - * codes and messages) - * - * @param e The Exception to use - * @return An XMLDBException instance - */ - public static XMLDBException createXMLDBException(Exception e) { - if (e instanceof XMLDBException) - return (XMLDBException) e; - - int faultCode = e instanceof RuntimeException ? JAVA_RUNTIME_ERROR : GEN_UNKNOWN; - return createXMLDBException(faultCode, null, e); - } - - /** - * Creates an XMLDBException instance based - * on the specified fault code, message, and Exception. If the Exception is a DBException, - * it will extract any important information from it (like fault - * codes and messages). If the exception is an instance of XindiceException, - * the exception class name and message of any Throwable(s) available - * via XindiceException.getCause will also be incorporated - * into the message. If a chain of wrapped XindiceExceptions is available, - * the chain will be followed incorporating the class name and message - * at each level. - * TODO: This should only be considered a temporary fix - * TODO: until such time as the xmldb API can be refined to allow for wrapped - * TODO: throwables in XMLDBException. - * - * @param faultCode the fault code for the created exception - * @param e The Exception to use - * @return An XMLDBException instance - */ - public static XMLDBException createXMLDBException(int faultCode, String message, Exception e) { - if (e instanceof XMLDBException) { - return (XMLDBException) e; - } - - if (e instanceof DBException) { - faultCode = ((DBException) e).faultCode; - } - - return new XMLDBException(ErrorCodes.VENDOR_ERROR, faultCode, message, e); - } - - /** - * getFaultCodeType examines the provided exception to determine - * the general fault code that is associated with it. General - * fault codes are reduced from actual fault codes to be one of - * the GEN_ prefixed fault code values. - * - * @param e The Exception to examine - * @return The General Fault Code - */ - public static int getFaultCodeType(Exception e) { - int code = 0; - if (e instanceof DBException) - code = ((DBException) e).faultCode; - - // Strip it to the General series - code = code % 100; - // Narrow to a General value - code = code - (code % 10); - return code; - } - - /** - * getFaultCodeSeries examines the provided exception to - * determine the fault code series that is associated with it. - * Series are reduced from actual fault codes to be one of - * the fault code prefixes (ex: COL, DB, SEC). - * - * @param e The Exception to examine - * @return The Fault Code Series - */ - public static int getFaultCodeSeries(Exception e) { - int code = 0; - if (e instanceof DBException) - code = ((DBException) e).faultCode; - - // Strip it to the series - code = code - (code % 100); - return code; - } - - /** - * getFaultCode examines the provided exception to determine - * the fault code that is associated with it. - * - * @param e The Exception to examine - * @return The Fault Code - */ - public static int getFaultCode(Exception e) { - if (e instanceof DBException) - return ((DBException) e).faultCode; - else - return 0; - } - - /** - * getFaultMessage examines the provided exception to determine - * the fault message that is associated with it. - * - * @param e The Exception to examine - * @return The Fault Message - */ - public static String getFaultMessage(Exception e) { - return getMessage(getFaultCode(e)); - } + private static final Map faultMessages = new HashMap(); + public static final int GEN = (int) (0l); + public static final int OBJ = (int) (100l); + public static final int COL = (int) (200l); + public static final int IDX = (int) (300l); + public static final int TRX = (int) (400l); + public static final int DBE = (int) (500l); + public static final int QRY = (int) (600l); + public static final int SEC = (int) (700l); + public static final int URI = (int) (800l); + public static final int JAVA = (int) (2000l); + public static final int GEN_UNKNOWN = (int) (0l); + public static final int GEN_GENERAL_ERROR = (int) (40l); + public static final int GEN_CRITICAL_ERROR = (int) (70l); + public static final int GEN_FATAL_ERROR = (int) (90l); + public static final int COL_COLLECTION_NOT_FOUND = (int) (200l); + public static final int COL_DOCUMENT_NOT_FOUND = (int) (201l); + public static final int COL_DUPLICATE_COLLECTION = (int) (240l); + public static final int COL_NULL_RESULT = (int) (241l); + public static final int COL_NO_FILER = (int) (242l); + public static final int COL_NO_INDEXMANAGER = (int) (242l); + public static final int COL_DOCUMENT_MALFORMED = (int) (243l); + public static final int COL_CANNOT_STORE = (int) (244l); + public static final int COL_CANNOT_RETRIEVE = (int) (245l); + public static final int COL_COLLECTION_READ_ONLY = (int) (246l); + public static final int COL_COLLECTION_CLOSED = (int) (247l); + public static final int COL_CANNOT_CREATE = (int) (270l); + public static final int COL_CANNOT_DROP = (int) (271l); + public static final int COL_INVALID_RESULT = (int) (277l); + public static final int IDX_VALUE_NOT_FOUND = (int) (300l); + public static final int IDX_INDEX_NOT_FOUND = (int) (301l); + public static final int IDX_MATCHES_NOT_FOUND = (int) (340l); + public static final int IDX_DUPLICATE_INDEX = (int) (341l); + public static final int IDX_NOT_SUPPORTED = (int) (370l); + public static final int IDX_STYLE_NOT_FOUND = (int) (371l); + public static final int IDX_CORRUPTED = (int) (372l); + public static final int IDX_CANNOT_CREATE = (int) (373l); + public static final int TRX_DOC_LOCKED = (int) (400l); + public static final int TRX_NO_CONTEXT = (int) (440l); + public static final int TRX_NOT_ACTIVE = (int) (441l); + public static final int TRX_NOT_SUPPORTED = (int) (470l); + public static final int DBE_NO_PARENT = (int) (500l); + public static final int DBE_CANNOT_DROP = (int) (570l); + public static final int DBE_CANNOT_CREATE = (int) (571l); + public static final int QRY_NULL_RESULT = (int) (600l); + public static final int QRY_COMPILATION_ERROR = (int) (640l); + public static final int QRY_PROCESSING_ERROR = (int) (641l); + public static final int QRY_NOT_SUPPORTED = (int) (670l); + public static final int QRY_STYLE_NOT_FOUND = (int) (671l); + public static final int SEC_INVALID_USER = (int) (770l); + public static final int SEC_INVALID_GROUP = (int) (771l); + public static final int SEC_INVALID_ACCESS = (int) (772l); + public static final int SEC_INVALID_CREDENTIALS = (int) (773l); + public static final int URI_EMPTY = (int) (800l); + public static final int URI_NULL = (int) (801l); + public static final int URI_PARSE_ERROR = (int) (820l); + public static final int JAVA_RUNTIME_ERROR = (int) (2070l); + + private FaultCodes() {} + + static { + // General errors 0 series + putCodeMessage(GEN_UNKNOWN, "Unknown"); + putCodeMessage(GEN_GENERAL_ERROR, "General Error"); + putCodeMessage(GEN_CRITICAL_ERROR, "Critical Error"); + putCodeMessage(GEN_FATAL_ERROR, "Fatal Error"); + + // Collection-related errors 200 series + putCodeMessage(COL_COLLECTION_NOT_FOUND, "Collection Not Found"); + putCodeMessage(COL_DOCUMENT_NOT_FOUND, "Collection Document Not Found"); + putCodeMessage(COL_DUPLICATE_COLLECTION, "Collection Duplicated"); + putCodeMessage(COL_NULL_RESULT, "Collection Null Result"); + putCodeMessage(COL_NO_FILER, "Collection No Filer"); + putCodeMessage(COL_NO_INDEXMANAGER, "Collection No IndexManager"); + putCodeMessage(COL_DOCUMENT_MALFORMED, "Collection Document Malformed"); + putCodeMessage(COL_CANNOT_STORE, "Collection Cannot Store"); + putCodeMessage(COL_CANNOT_RETRIEVE, "Collection Cannot Retrieve"); + putCodeMessage(COL_COLLECTION_READ_ONLY, "Collection Read-only"); + putCodeMessage(COL_COLLECTION_CLOSED, "Collection Closed"); + putCodeMessage(COL_CANNOT_CREATE, "Collection Cannot Create"); + putCodeMessage(COL_CANNOT_DROP, "Collection Cannot Drop"); + putCodeMessage(COL_INVALID_RESULT, "Collection Invalid Result"); + + // Index-related errors 300 series + putCodeMessage(IDX_VALUE_NOT_FOUND, "Index Value Not Found"); + putCodeMessage(IDX_INDEX_NOT_FOUND, "Index Not Found"); + putCodeMessage(IDX_MATCHES_NOT_FOUND, "Index Matches Not Found"); + putCodeMessage(IDX_DUPLICATE_INDEX, "Index Duplicate Index"); + putCodeMessage(IDX_NOT_SUPPORTED, "Index Not Supported"); + putCodeMessage(IDX_STYLE_NOT_FOUND, "Index Style Not Found"); + putCodeMessage(IDX_CORRUPTED, "Index Corrupted"); + putCodeMessage(IDX_CANNOT_CREATE, "Index Cannot Create"); + + // Transaction-related errors 400 series + putCodeMessage(TRX_DOC_LOCKED, "Transaction Document Locked"); + putCodeMessage(TRX_NO_CONTEXT, "Transaction No Context"); + putCodeMessage(TRX_NOT_ACTIVE, "Transaction Not Active"); + putCodeMessage(TRX_NOT_SUPPORTED, "Transaction Not Supported"); + + // Database-related errors 500 series + putCodeMessage(DBE_NO_PARENT, "Database No Parent"); + putCodeMessage(DBE_CANNOT_DROP, "Database Cannot Drop"); + putCodeMessage(DBE_CANNOT_CREATE, "Database Cannot Create"); + + // Query-related errors 600 series + putCodeMessage(QRY_NULL_RESULT, "Query Null Result"); + putCodeMessage(QRY_COMPILATION_ERROR, "Query Compilation Error"); + putCodeMessage(QRY_PROCESSING_ERROR, "Query Processing Error"); + putCodeMessage(QRY_NOT_SUPPORTED, "Query Not Supported"); + putCodeMessage(QRY_STYLE_NOT_FOUND, "Query Style Not Found"); + + // Security-related errors 700 series + putCodeMessage(SEC_INVALID_USER, "Security Invalid User"); + putCodeMessage(SEC_INVALID_GROUP, "Security Invalid Group"); + putCodeMessage(SEC_INVALID_ACCESS, "Security Invalid Access"); + putCodeMessage(SEC_INVALID_CREDENTIALS, "Security Invalid Credentials"); + + // URI-related errors 800 series + putCodeMessage(URI_EMPTY, "URI Empty"); + putCodeMessage(URI_NULL, "URI Null"); + putCodeMessage(URI_PARSE_ERROR, "URI Parse Error"); + + // Java-related errors 2000 series + putCodeMessage(JAVA_RUNTIME_ERROR, "Java Runtime Error"); + } + + private static void putCodeMessage(int code, String message) { + faultMessages.put(new Integer(code), message); + } + + /** + * getMessage returns a textual form for the specified fault code. + * + * @param code The Fault Code + * @return It's textual form + */ + public static String getMessage(int code) { + String msg = (String) faultMessages.get(new Integer(code)); + return msg != null ? msg : ""; + } + + /** + * createXMLDBException creates an XMLDBException instance based + * on the specified Exception. If the Exception is a DBException, + * it will extract any important information from it (like fault + * codes and messages) + * + * @param e The Exception to use + * @return An XMLDBException instance + */ + public static XMLDBException createXMLDBException(Exception e) { + if (e instanceof XMLDBException) + return (XMLDBException) e; + + int faultCode = e instanceof RuntimeException ? JAVA_RUNTIME_ERROR : GEN_UNKNOWN; + return createXMLDBException(faultCode, null, e); + } + + /** + * Creates an XMLDBException instance based + * on the specified fault code, message, and Exception. If the Exception is a DBException, + * it will extract any important information from it (like fault + * codes and messages). If the exception is an instance of XindiceException, + * the exception class name and message of any Throwable(s) available + * via XindiceException.getCause will also be incorporated + * into the message. If a chain of wrapped XindiceExceptions is available, + * the chain will be followed incorporating the class name and message + * at each level. + * TODO: This should only be considered a temporary fix + * TODO: until such time as the xmldb API can be refined to allow for wrapped + * TODO: throwables in XMLDBException. + * + * @param faultCode the fault code for the created exception + * @param e The Exception to use + * @return An XMLDBException instance + */ + public static XMLDBException createXMLDBException(int faultCode, String message, Exception e) { + if (e instanceof XMLDBException) { + return (XMLDBException) e; + } + + if (e instanceof DBException) { + faultCode = ((DBException) e).faultCode; + } + + return new XMLDBException(ErrorCodes.VENDOR_ERROR, faultCode, message, e); + } + + /** + * getFaultCodeType examines the provided exception to determine + * the general fault code that is associated with it. General + * fault codes are reduced from actual fault codes to be one of + * the GEN_ prefixed fault code values. + * + * @param e The Exception to examine + * @return The General Fault Code + */ + public static int getFaultCodeType(Exception e) { + int code = 0; + if (e instanceof DBException) + code = ((DBException) e).faultCode; + + // Strip it to the General series + code = code % 100; + // Narrow to a General value + code = code - (code % 10); + return code; + } + + /** + * getFaultCodeSeries examines the provided exception to + * determine the fault code series that is associated with it. + * Series are reduced from actual fault codes to be one of + * the fault code prefixes (ex: COL, DB, SEC). + * + * @param e The Exception to examine + * @return The Fault Code Series + */ + public static int getFaultCodeSeries(Exception e) { + int code = 0; + if (e instanceof DBException) + code = ((DBException) e).faultCode; + + // Strip it to the series + code = code - (code % 100); + return code; + } + + /** + * getFaultCode examines the provided exception to determine + * the fault code that is associated with it. + * + * @param e The Exception to examine + * @return The Fault Code + */ + public static int getFaultCode(Exception e) { + if (e instanceof DBException) + return ((DBException) e).faultCode; + else + return 0; + } + + /** + * getFaultMessage examines the provided exception to determine + * the fault message that is associated with it. + * + * @param e The Exception to examine + * @return The Fault Message + */ + public static String getFaultMessage(Exception e) { + return getMessage(getFaultCode(e)); + } } 1.5 +122 -99 xml-xindice/java/src/org/apache/xindice/core/DocumentCache.java Index: DocumentCache.java =================================================================== RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/core/DocumentCache.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- DocumentCache.java 3 Jul 2003 19:23:07 -0000 1.4 +++ DocumentCache.java 14 Jul 2003 19:07:14 -0000 1.5 @@ -59,16 +59,17 @@ * $Id$ */ +import java.util.Map; +import java.util.WeakHashMap; + import org.apache.xindice.core.data.Key; import org.apache.xindice.xml.NodeSource; import org.apache.xindice.xml.SymbolTable; import org.apache.xindice.xml.dom.DBDocument; import org.apache.xindice.xml.dom.DocumentImpl; - -import org.w3c.dom.*; - -import java.util.Map; -import java.util.WeakHashMap; +import org.w3c.dom.Document; +import org.w3c.dom.Node; +import org.w3c.dom.NodeList; /** * DocumentCache implements a simple Document caching system for @@ -76,98 +77,120 @@ */ public final class DocumentCache { - private Map table = new WeakHashMap(); + private Map table = new WeakHashMap(); - public Document getDocument(Collection col, Key key) { - Object v = table.get(new CacheKey(col, key)); - Document doc = null; - if (v instanceof Document) - doc = (Document) v; - else if (v instanceof byte[]) { - try { - SymbolTable s = col.getSymbols(); - NodeSource ns = new NodeSource(col, key); - doc = new DocumentImpl((byte[]) v, s, ns); - } - catch (Exception e) {} - } - return doc; - } - - public void putDocument(Collection col, Key key, byte[] bytes) { - CacheKey ckey = new CacheKey(col, key); - table.put(ckey, bytes); - } - - public void putDocument(Collection col, Key key, Document doc) { - CacheKey ckey = new CacheKey(col, key); - table.put(ckey, doc); - } - - public void removeDocument(Collection col, Key key) { - table.remove(new CacheKey(col, key)); - } - - public static int getCacheControl(Document doc) { - String cache = DBDocument.CACHE; - NodeList childNodes = doc.getChildNodes(); - int size = childNodes.getLength(); - for (int i = 0; i < size; i++) { - Node n = childNodes.item(i); - if (n.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE && n.getNodeName().equals(DBDocument.CACHE_CONTROL)) { - cache = n.getNodeValue().trim(); - break; - } - } - - if (cache != null) { - if (cache.equals(DBDocument.CACHE)) - return -1; - else if (cache.equals(DBDocument.NOCACHE)) - return 0; - else - return Integer.parseInt(cache); - } - else - return -1; - } - - /** - * CacheKey - */ - - private class CacheKey { - private Collection col; - private String strVal; - private Key key; - - public CacheKey(Collection col, Key key) { - this.col = col; - this.key = key; - } - - public Collection getCollection() { - return col; - } - - public Key getKey() { - return key; - } - - public String toString() { - if (strVal == null) - strVal = col.getCanonicalDocumentName(key); - return strVal; - } - - public int hashCode() { - if (strVal == null) - strVal = col.getCanonicalDocumentName(key); - return strVal.hashCode(); - } - - public boolean equals(Object o) { - return o instanceof CacheKey && col == ((CacheKey) o).col && key.equals(((CacheKey) o).key); - } - } + /** + * @param col + * @param key + * @return + */ + public Document getDocument(Collection col, Key key) { + Object v = table.get(new CacheKey(col, key)); + Document doc = null; + if (v instanceof Document) + doc = (Document) v; + else if (v instanceof byte[]) { + try { + SymbolTable s = col.getSymbols(); + NodeSource ns = new NodeSource(col, key); + doc = new DocumentImpl((byte[]) v, s, ns); + } + catch (Exception e) {} + } + return doc; + } + + /** + * @param col + * @param key + * @param bytes + */ + public void putDocument(Collection col, Key key, byte[] bytes) { + CacheKey ckey = new CacheKey(col, key); + table.put(ckey, bytes); + } + + /** + * @param col + * @param key + * @param doc + */ + public void putDocument(Collection col, Key key, Document doc) { + CacheKey ckey = new CacheKey(col, key); + table.put(ckey, doc); + } + + /** + * @param col + * @param key + */ + public void removeDocument(Collection col, Key key) { + table.remove(new CacheKey(col, key)); + } + + /** + * @param doc + * @return + */ + public static int getCacheControl(Document doc) { + String cache = DBDocument.CACHE; + NodeList childNodes = doc.getChildNodes(); + int size = childNodes.getLength(); + for (int i = 0; i < size; i++) { + Node n = childNodes.item(i); + if (n.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE && n.getNodeName().equals(DBDocument.CACHE_CONTROL)) { + cache = n.getNodeValue().trim(); + break; + } + } + + if (cache != null) { + if (cache.equals(DBDocument.CACHE)) + return -1; + else if (cache.equals(DBDocument.NOCACHE)) + return 0; + else + return Integer.parseInt(cache); + } + else + return -1; + } + + /** + * CacheKey + */ + private class CacheKey { + private Collection col; + private String strVal; + private Key key; + + public CacheKey(Collection col, Key key) { + this.col = col; + this.key = key; + } + + public Collection getCollection() { + return col; + } + + public Key getKey() { + return key; + } + + public String toString() { + if (strVal == null) + strVal = col.getCanonicalDocumentName(key); + return strVal; + } + + public int hashCode() { + if (strVal == null) + strVal = col.getCanonicalDocumentName(key); + return strVal.hashCode(); + } + + public boolean equals(Object o) { + return o instanceof CacheKey && col == ((CacheKey) o).col && key.equals(((CacheKey) o).key); + } + } } 1.5 +18 -19 xml-xindice/java/src/org/apache/xindice/core/DBException.java Index: DBException.java =================================================================== RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/core/DBException.java,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- DBException.java 31 Oct 2002 06:59:56 -0000 1.4 +++ DBException.java 14 Jul 2003 19:07:14 -0000 1.5 @@ -68,23 +68,22 @@ */ public class DBException extends XindiceException { - public int faultCode; + public int faultCode; - public DBException() { - this(FaultCodes.GEN_UNKNOWN, "", null); - } + public DBException() { + this(FaultCodes.GEN_UNKNOWN, "", null); + } - public DBException(int faultCode) { - this(faultCode, "", null); - } + public DBException(int faultCode) { + this(faultCode, "", null); + } - public DBException(int faultCode, String message) { - this(faultCode, message, null); - } - - public DBException(int faultCode, String message, Throwable cause) { - super(message, cause); - this.faultCode = faultCode; - } + public DBException(int faultCode, String message) { + this(faultCode, message, null); + } + public DBException(int faultCode, String message, Throwable cause) { + super(message, cause); + this.faultCode = faultCode; + } } 1.3 +3 -3 xml-xindice/java/src/org/apache/xindice/core/Container.java Index: Container.java =================================================================== RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/core/Container.java,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- Container.java 31 Oct 2002 06:59:56 -0000 1.2 +++ Container.java 14 Jul 2003 19:07:14 -0000 1.3 @@ -60,14 +60,14 @@ */ import org.apache.xindice.core.data.Key; - -import org.w3c.dom.*; +import org.w3c.dom.Document; /** * Container is a generic container for Key and Document pairs. */ public interface Container { + /** * getCollection returns the Collection that the Document contained * belongs to. 1.21 +293 -270 xml-xindice/java/src/org/apache/xindice/core/Database.java Index: Database.java =================================================================== RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/core/Database.java,v retrieving revision 1.20 retrieving revision 1.21 diff -u -r1.20 -r1.21 --- Database.java 14 Jul 2003 18:31:57 -0000 1.20 +++ Database.java 14 Jul 2003 19:07:14 -0000 1.21 @@ -80,273 +80,296 @@ * Database is the primary container for the Xindice Database Engine. */ public final class Database extends Collection implements Named { - public static final String DBROOT = "dbroot"; - private static final String QUERYENGINE = "queryengine"; - private static final String DATABASE = "database"; - private static final String COLKEY = "database.xml"; - private static final String METADATA = "use-metadata"; - public static final String NAME = "name"; - - private static Log log = LogFactory.getLog("org.apache.xindice.core"); - - public static final String PROP_XINDICE_HOME = "xindice.home"; - - private static final Map databases = new HashMap(); // String to Database - - private DocumentCache docCache = new DocumentCache(); - - private SystemCollection systemCollection = null; - - private MetaSystemCollection metaSystemCollection = null; - - private boolean sysInit = false; - private boolean metaInit = false; - private boolean metaEnabled = false; - // key = canonical name, value = timerecord - private Map timestamps = new HashMap(); - - private QueryEngine engine = new QueryEngine(this); - - /** - * This will merely return an instance of a Database for the given - * name if one has already been loaded. - * - * @param name - * @return Database - */ - public static Database getDatabase(String name) { - - Database database = (Database) databases.get(name); - if (null == database) { - // in case it's currently being added (only pay the sync hit on a miss) - synchronized (databases) { - database = (Database) databases.get(name); - } - } - - return database; - } - - /** - * This will return an instance of a Database for the given - * name if one has already been loaded, otherwise it will - * create a new instance. - * - * @param config - * @return Database - */ - public static Database getDatabase(Configuration config) { - - String name = config.getAttribute(Database.NAME); - - // no name in the config file ... can't the database - if (null == name) { - throw new ConfigurationException("Database configuration didn't contain a database name"); - } - - Database database = (Database) databases.get(name); - if (null == database) { - // in case it's currently being added (only pay the sync hit on a miss) - synchronized (databases) { - // was it created while we waited? - database = (Database) databases.get(name); - if (null == database) { - database = new Database(); - database.setConfig(config); - - databases.put(database.getName(), database); - } - } - } - - return database; - } - - public static String[] listDatabases() { - return (String[]) databases.keySet().toArray(new String[0]); - } - - public void setConfig(Configuration config) { - this.config = config; - - this.name = config.getAttribute(NAME); - setCanonicalName('/' + getName()); - - String dbroot = config.getAttribute(DBROOT); - File dbrootDir = new File(dbroot); - if (!dbrootDir.isAbsolute()) { - dbrootDir = new File(System.getProperty(PROP_XINDICE_HOME), dbroot); - } - setCollectionRoot(dbrootDir); - log.info("Database points to " + dbrootDir.getAbsolutePath()); - log.debug("Database dir exists: " + (dbrootDir == null ? false : dbrootDir.exists())); - - try { - Configuration queryCfg = config.getChild(QUERYENGINE); - if (queryCfg != null) - this.engine.setConfig(queryCfg); - } - catch (Exception e) { - - log.warn(e); - } - - if (!sysInit) { - this.systemCollection = new SystemCollection(this); - - try { - this.systemCollection.init(); - } - catch (XindiceException e) { - log.warn(e); - } - - this.collections.put(systemCollection.getName(), systemCollection); - this.sysInit = true; - } - - try { - // Bootstrap from the database itself... This is accomplished - // by intercepting the setConfig call and using a Configuration - // retrieved from the database instead of the standard config - Document colDoc = systemCollection.getCollection(SystemCollection.CONFIGS).getDocument(COLKEY); - if (colDoc == null) { - DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); - colDoc = db.newDocument(); - Element root = colDoc.createElement(DATABASE); - root.setAttribute(NAME, name); - colDoc.appendChild(root); - systemCollection.getCollection(SystemCollection.CONFIGS).setDocument(COLKEY, colDoc); - } - - super.setConfig(new Configuration(colDoc.getDocumentElement(), false)); - } - catch (Exception e) { - log.warn(e); - } - - // Register the Database with the VM - // databases.put(getName(), this); - - // initialize the meta collection - // but only if it's turned on in the config. - String metaCfg = config.getAttribute(METADATA); - if (metaCfg.equalsIgnoreCase("on")) { - metaEnabled = true; - if (!metaInit) { - this.metaSystemCollection = new MetaSystemCollection(this); - try { - this.metaSystemCollection.init(); - } - catch (XindiceException e) { - log.warn("Error initializing the meta collection", e); - } - // should this attach the meta collection to the database? - - collections.put(metaSystemCollection.getName(), metaSystemCollection); - metaInit = true; - log.info("Meta information initialized"); - } - } - - // observer - DBObserver.getInstance().setDatabaseConfig(this, collections, config); - } - - public SystemCollection getSystemCollection() { - return systemCollection; - } - - /** - * Return the MetaSystem collection for this database. - * - * It will return null if metadata is not enabled on this database. - * @return MetaSystemCollection - */ - public MetaSystemCollection getMetaSystemCollection() { - return metaSystemCollection; - } - - /** - * Return whether or not metadata is enabled on this database. - * @return boolean - */ - public boolean isMetaEnabled() { - return metaEnabled; - } - - public Database getDatabase() { - return this; - } - - /** - * flushConfig ensures that the Collection configuration has been - * properly flushed to disk after a modification. - */ - public void flushConfig() { - - try { - Document d = config.getElement().getOwnerDocument(); - systemCollection.getCollection(SystemCollection.CONFIGS).setDocument(COLKEY, d); - } - catch (Exception e) { - log.error("Error Writing Configuration '" + name + "', for database " + getName(), e); - } - - // observer - DBObserver.getInstance().flushDatabaseConfig(this, config); - } - - public boolean close() throws DBException { - flushConfig(); - - synchronized (databases) { - databases.remove(getName()); - } - - return true; - } - - /** - * getDocumentCache returns the Database-level Document Cache. - * - * @return The DocumentCache - */ - public DocumentCache getDocumentCache() { - return docCache; - } - - /** - * getQueryEngine returns a reference to the Database's current - * operating QueryEngine implementation. - * - * @return The QueryEngine instance - */ - public QueryEngine getQueryEngine() { - return engine; - } - - // methods for recording the times when meta data is enabled. - public synchronized void recordTime(String path, long created, long modified) { - TimeRecord rec = (TimeRecord) timestamps.get(path); - if (null == rec) { - rec = new TimeRecord(created, modified); - timestamps.put(path, rec); - } - else { - if (created > 0) - rec.setCreatedTime(created); - if (modified > 0) - rec.setModifiedTime(modified); - } - } - - public synchronized void removeTime(String path) { - timestamps.remove(path); - } - - public synchronized TimeRecord getTime(String path) { - TimeRecord rec = (TimeRecord) timestamps.get(path); - return rec; - } + + public static final String DBROOT = "dbroot"; + public static final String NAME = "name"; + public static final String PROP_XINDICE_HOME = "xindice.home"; + private static final String QUERYENGINE = "queryengine"; + private static final String COLKEY = "database.xml"; + private static final String DATABASE = "database"; + private static final String METADATA = "use-metadata"; + private static Log log = LogFactory.getLog("org.apache.xindice.core"); + private static final Map databases = new HashMap(); // String to Database + + /** + * This will return an instance of a Database for the given + * name if one has already been loaded, otherwise it will + * create a new instance. + * + * @param config + * @return Database + */ + public static Database getDatabase(Configuration config) { + + String name = config.getAttribute(Database.NAME); + + // no name in the config file ... can't the database + if (null == name) { + throw new ConfigurationException("Database configuration didn't contain a database name"); + } + + Database database = (Database) databases.get(name); + if (null == database) { + // in case it's currently being added (only pay the sync hit on a miss) + synchronized (databases) { + // was it created while we waited? + database = (Database) databases.get(name); + if (null == database) { + database = new Database(); + + try { + database.setConfig(config); + } + catch (XindiceException x) { // TODO: Configurable interface should use ConfigurationException instead of XindiceException. + + throw new ConfigurationException(x); + } + + databases.put(database.getName(), database); + } + } + } + + return database; + } + + /** + * This will merely return an instance of a Database for the given + * name if one has already been loaded. + * + * @param name + * @return Database + */ + public static Database getDatabase(String name) { + + Database database = (Database) databases.get(name); + if (null == database) { + // in case it's currently being added (only pay the sync hit on a miss) + synchronized (databases) { + database = (Database) databases.get(name); + } + } + + return database; + } + + public static String[] listDatabases() { + return (String[]) databases.keySet().toArray(new String[0]); + } + + // + // Instance... + // + private DocumentCache docCache = new DocumentCache(); + private QueryEngine engine = new QueryEngine(this); + private boolean metaEnabled = false; + private boolean metaInit = false; + private MetaSystemCollection metaSystemCollection = null; + private boolean sysInit = false; + private SystemCollection systemCollection = null; + /** key = canonical name, value = timerecord */ + private Map timestamps = new HashMap(); + + /** + * @see org.apache.xindice.core.DBObject#close() + */ + public boolean close() throws DBException { + flushConfig(); + + synchronized (databases) { + databases.remove(getName()); + } + + return true; + } + + /** + * flushConfig ensures that the Collection configuration has been + * properly flushed to disk after a modification. + */ + public void flushConfig() { + + try { + Document d = getConfig().getElement().getOwnerDocument(); + systemCollection.getCollection(SystemCollection.CONFIGS).setDocument(COLKEY, d); + } + catch (Exception e) { + log.error("Error Writing Configuration '" + getName() + "', for database " + getName(), e); + } + + // observer + DBObserver.getInstance().flushDatabaseConfig(this, getConfig()); + } + + /** + * @see org.apache.xindice.core.Collection#getDatabase() + */ + public Database getDatabase() { + return this; + } + + /** + * getDocumentCache returns the Database-level Document Cache. + * + * @return The DocumentCache + */ + public DocumentCache getDocumentCache() { + return docCache; + } + + /** + * Return the MetaSystem collection for this database. + * + * It will return null if metadata is not enabled on this database. + * @return MetaSystemCollection + */ + public MetaSystemCollection getMetaSystemCollection() { + return metaSystemCollection; + } + + /** + * getQueryEngine returns a reference to the Database's current + * operating QueryEngine implementation. + * + * @return The QueryEngine instance + */ + public QueryEngine getQueryEngine() { + return engine; + } + + /** + * @see org.apache.xindice.core.Collection#getSystemCollection() + */ + public SystemCollection getSystemCollection() { + return systemCollection; + } + + /** + * @param path + * @return + */ + public synchronized TimeRecord getTime(String path) { + TimeRecord rec = (TimeRecord) timestamps.get(path); + return rec; + } + + /** + * Return whether or not metadata is enabled on this database. + * @return boolean + */ + public boolean isMetaEnabled() { + return metaEnabled; + } + + // methods for recording the times when meta data is enabled. + public synchronized void recordTime(String path, long created, long modified) { + TimeRecord rec = (TimeRecord) timestamps.get(path); + if (null == rec) { + rec = new TimeRecord(created, modified); + timestamps.put(path, rec); + } + else { + if (created > 0) + rec.setCreatedTime(created); + if (modified > 0) + rec.setModifiedTime(modified); + } + } + + /** + * @param path + */ + public synchronized void removeTime(String path) { + timestamps.remove(path); + } + + /** + * @see org.apache.xindice.util.Configurable#setConfig(org.apache.xindice.util.Configuration) + */ + public void setConfig(Configuration config) throws XindiceException { + super.setConfig(config); + + setName(config.getAttribute(NAME)); + setCanonicalName('/' + getName()); + + String dbroot = config.getAttribute(DBROOT); + File dbrootDir = new File(dbroot); + if (!dbrootDir.isAbsolute()) { + dbrootDir = new File(System.getProperty(PROP_XINDICE_HOME), dbroot); + } + setCollectionRoot(dbrootDir); + log.info("Database points to " + dbrootDir.getAbsolutePath()); + log.debug("Database dir exists: " + (dbrootDir == null ? false : dbrootDir.exists())); + + try { + Configuration queryCfg = config.getChild(QUERYENGINE); + if (queryCfg != null) + this.engine.setConfig(queryCfg); + } + catch (Exception e) { + + log.warn(e); + } + + if (!sysInit) { + this.systemCollection = new SystemCollection(this); + + try { + this.systemCollection.init(); + } + catch (XindiceException e) { + log.warn(e); + } + + super.addCollection(systemCollection); + this.sysInit = true; + } + + try { + // Bootstrap from the database itself... This is accomplished + // by intercepting the setConfig call and using a Configuration + // retrieved from the database instead of the standard config + Document colDoc = systemCollection.getCollection(SystemCollection.CONFIGS).getDocument(COLKEY); + if (colDoc == null) { + DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder(); + colDoc = db.newDocument(); + Element root = colDoc.createElement(DATABASE); + root.setAttribute(NAME, getName()); + colDoc.appendChild(root); + systemCollection.getCollection(SystemCollection.CONFIGS).setDocument(COLKEY, colDoc); + } + + super.setConfig(new Configuration(colDoc.getDocumentElement(), false)); + } + catch (Exception e) { + log.warn(e); + } + + // Register the Database with the VM + // databases.put(getName(), this); + + // initialize the meta collection + // but only if it's turned on in the config. + String metaCfg = config.getAttribute(METADATA); + if (metaCfg.equalsIgnoreCase("on")) { + metaEnabled = true; + if (!metaInit) { + this.metaSystemCollection = new MetaSystemCollection(this); + try { + this.metaSystemCollection.init(); + } + catch (XindiceException e) { + log.warn("Error initializing the meta collection", e); + } + // should this attach the meta collection to the database? + + super.addCollection(metaSystemCollection); + metaInit = true; + log.info("Meta information initialized"); + } + } + + // observer + DBObserver.getInstance().setDatabaseConfig(this, getCollections(), config); + } } 1.21 +1485 -1476xml-xindice/java/src/org/apache/xindice/core/Collection.java Index: Collection.java =================================================================== RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/core/Collection.java,v retrieving revision 1.20 retrieving revision 1.21 diff -u -r1.20 -r1.21 --- Collection.java 14 Jul 2003 17:23:56 -0000 1.20 +++ Collection.java 14 Jul 2003 19:07:15 -0000 1.21 @@ -58,7 +58,13 @@ * * $Id$ */ +import java.io.File; +import java.io.UnsupportedEncodingException; +import java.net.InetAddress; +import java.util.ArrayList; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.xindice.core.data.DocumentSet; import org.apache.xindice.core.data.EmptyDocumentSet; import org.apache.xindice.core.data.EmptyNodeSet; @@ -70,10 +76,10 @@ import org.apache.xindice.core.filer.Filer; import org.apache.xindice.core.indexer.IndexManager; import org.apache.xindice.core.indexer.Indexer; +import org.apache.xindice.core.meta.MetaData; import org.apache.xindice.core.meta.inline.InlineMetaMap; import org.apache.xindice.core.meta.inline.InlineMetaService; import org.apache.xindice.core.meta.inline.ResourceTypeReader; -import org.apache.xindice.core.meta.MetaData; import org.apache.xindice.core.query.QueryEngine; import org.apache.xindice.util.Configurable; import org.apache.xindice.util.Configuration; @@ -94,14 +100,6 @@ import org.w3c.dom.NodeList; import org.w3c.dom.ProcessingInstruction; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import java.io.File; -import java.io.UnsupportedEncodingException; -import java.net.InetAddress; -import java.util.ArrayList; - /** * Collection represents a collection of Documents maintains links to * the Filer storage implementation, and the Indexes associated with @@ -109,1470 +107,1481 @@ **/ public class Collection extends CollectionManager implements Named, DBObject, Configurable { - private static final String NAME = "name"; - private static final String FILER = "filer"; - private static final String CLASS = "class"; - private static final String INDEXES = "indexes"; - private static final String INLINE_METADATA = "inline-metadata"; - private static final String COMPRESSED = "compressed"; - private static final String CACHE = "cache"; - private static final String SYMBOLS = "symbols"; - private static final String CLASSNAME = "xindice-class"; - - private static final DocumentSet EMPTY_DOCUMENTSET = new EmptyDocumentSet(); - private static final NodeSet EMPTY_NODESET = new EmptyNodeSet(); - private static final String[] EMPTY_STRING_ARRAY = {}; - - private static Log log = LogFactory.getLog("org.apache.xindice.core"); - - private static int host_id; - static { - try { - InetAddress a = InetAddress.getLocalHost(); - byte[] b = a.getAddress(); - host_id = 0; - host_id += b[0]; - host_id += (b[1] << 8); - host_id += (b[2] << 16); - host_id += (b[3] << 24); - host_id = Math.abs(host_id); - } - catch (Exception e) {} - }; - - private Collection parent = null; - - // Object ID Stuff - private int collection_id = 0; - private long document_id = System.currentTimeMillis(); - private Object oidMutex = new Object(); - private String oidTemplate = null; - - protected String name; - private String canonicalName; - private File collectionRoot; - - private Filer filer = null; - - private boolean compressed = false; - private SymbolTable symbols = null; - private boolean internalSymbols = false; - - private IndexManager indexManager; - private DocumentCache documentCache; - - private InlineMetaService inlineMetaService; - - protected Collection() {} - - public Collection(Collection collection) { - this(); - parent = collection; - } - - public void setConfig(Configuration config) throws XindiceException { - this.config = config; - - name = config.getAttribute(NAME); - compressed = config.getBooleanAttribute(COMPRESSED, true); - - /* - * If inline metadata is desired, get an InlineMetaService object. - */ - if (config.getBooleanAttribute(INLINE_METADATA, false)) { - inlineMetaService = new InlineMetaService(); - } - - /* - * Wait to set up the local debug header until everything needed - * by debugHeader() is complete! - */ - String localDebugHeader = debugHeader() + "setConfig: "; - - if (inlineMetaService == null) { - log.debug(localDebugHeader + "inline metadata DISABLED"); - } - else { - log.debug(localDebugHeader + "inline metadata ENABLED"); - } - - if (parent != null) { - setCanonicalName(parent.getCanonicalName() + '/' + name); - log.debug(localDebugHeader + "canonical name=<" + getCanonicalName() + ">"); - setCollectionRoot(new File(parent.getCollectionRoot(), name)); - log.debug(localDebugHeader + "collection root=<" + getCollectionRoot().toString() + ">"); - } - - if (config.getBooleanAttribute(CACHE, true)) - documentCache = getDatabase().getDocumentCache(); - - // If no Filer is defined, skip Symbols and Indexes - Configuration filerConfig = config.getChild(FILER); - if (filerConfig != null) { - log.debug(localDebugHeader + "have filer config..."); - - // Symbol Table Setup - Configuration symConfig = config.getChild(SYMBOLS); - internalSymbols = (symConfig != null); - if (internalSymbols) { - log.debug(localDebugHeader + "have internal symbols <" + TextWriter.toString(symConfig.getElement()) + ">"); - try { - symbols = new SymbolTable(symConfig.getElement()); - } - catch (Exception e) { - if (log.isDebugEnabled()) { - log.debug("Error building symbol table from internal symbols", e); - } - } - } - else { - log.debug(localDebugHeader + "no internal symbols..."); - try { - symbols = getSystemCollection().loadSymbols(this); - log.debug( - localDebugHeader - + "loaded symbols from system collection <" - + TextWriter.toString(symbols.streamToXML(new DocumentImpl())) - + ">"); - } - catch (Exception e) { - if (log.isDebugEnabled()) { - log.debug("Error building symbol table from system collection...", e); - } - } - } - - String className = filerConfig.getAttribute(CLASS); - log.debug(localDebugHeader + "file class=<" + className + ">"); - try { - filer = (Filer) Class.forName(className).newInstance(); - // filer.setCollection(this); - filer.setLocation(getCollectionRoot(), getName()); - filer.setConfig(filerConfig); - if (!filer.exists()) - filer.create(); - filer.open(); - } - catch (Exception e) { - if (log.isWarnEnabled()) { - log.warn("Filer '" + className + "' not available", e); - } - } - - // Index Manager - try { - indexManager = new IndexManager(this); - Configuration idxConfig = config.getChild(INDEXES, true); - indexManager.setConfig(idxConfig); - } - catch (Exception e) { - if (log.isDebugEnabled()) { - log.debug("No message", e); - } - } - } - - super.setConfig(config); - - // observer - DBObserver.getInstance().setCollectionConfig(this, config); - } - - public final String getName() { - return name; - } - - public final File getCollectionRoot() { - return collectionRoot; - } - - protected final void setCollectionRoot(File collectionRoot) { - this.collectionRoot = collectionRoot; - if (!collectionRoot.exists()) - collectionRoot.mkdirs(); - } - - /** - * getParentCollection returns the parent Collection of this - * Collection. - * - * @return The parent Collection (or null) - */ - public final Collection getParentCollection() throws DBException { - return parent; - } - - public final boolean dropCollection(Collection collection) throws DBException { - boolean success = super.dropCollection(collection); - getDatabase().flushConfig(); - return success; - } - - public final Collection createCollection(String path, Configuration config) throws DBException { - Collection col = super.createCollection(path, config); - getDatabase().flushConfig(); - return col; - } - - // Convenience Methods - - /** - * getDatabase returns the Database owner for this Collection. - * - * @return The Database - */ - public Database getDatabase() { - return parent.getDatabase(); - } - - /** - * getSystemCollection returns the System Collection. - * - * @return The System Collection - */ - public SystemCollection getSystemCollection() throws DBException { - return getDatabase().getSystemCollection(); - } - - /** - * getQueryEngine returns the Database's Query Engine - * - * @return The Query Engine - */ - public QueryEngine getQueryEngine() throws DBException { - return getDatabase().getQueryEngine(); - } - - private void checkFiler(int faultCode) throws DBException { - if (filer == null) - throw new DBException(faultCode, "This Collection '" + name + "' cannot store Documents"); - } - - /** - * getIndexer retrieves an Indexer by name. - * - * @param name The Indexer name - * @return The Indexer (or null) - */ - public final Indexer getIndexer(String name) throws DBException { - checkFiler(FaultCodes.COL_NO_INDEXMANAGER); - return indexManager.get(name); - } - - /** - * listIndexers returns a list of the currently registered Indexers - * as an array of String. - * - * @return The Indexer list - */ - public final String[] listIndexers() throws DBException { - checkFiler(FaultCodes.COL_NO_INDEXMANAGER); - return indexManager.list(); - } - - /** - * dropIndexer physically removes the specified Indexer and any - * associated system resources that the Indexer uses. - * - * @param index The Indexer to drop - * @return Whether or not the Indexer was dropped - */ - public final boolean dropIndexer(Indexer index) throws DBException { - checkFiler(FaultCodes.COL_NO_INDEXMANAGER); - - if (index == null) - throw new DBException(FaultCodes.IDX_INDEX_NOT_FOUND, "Index Value Null"); - - boolean success = indexManager.drop(index.getName()); - getDatabase().flushConfig(); - return success; - } - - /** - * createIndexer creates a new Indexer object and any associated - * system resources that the Indexer will need. - * - * @param config The Indexer's configuration - * @return The newly created Indexer - */ - public final Indexer createIndexer(Configuration config) throws DBException { - checkFiler(FaultCodes.COL_NO_INDEXMANAGER); - Indexer idx = indexManager.create(config); - getDatabase().flushConfig(); - return idx; - } - - /** - * getFiler returns the low-level Filer instances underlying the - * Collection instance. - * - * @return The requested Filer - */ - public final Filer getFiler() { - return filer; - } - - /** - * return the IndexManager being used by this Collection. - * - * @return The IndexManager - */ - public final IndexManager getIndexManager() throws DBException { - checkFiler(FaultCodes.COL_NO_INDEXMANAGER); - return indexManager; - } - - /** - * getSymbols returns the SymbolTable in use by this - * Collection. - * - * @return The Symbol Table - */ - public final SymbolTable getSymbols() throws DBException { - return symbols; - } - - /** - * Turns an XML string into a parsed document and caches it. - * - * @param key The key to use when caching - * @param xml The string to parse - * @return A parsed DOM document or null if failure - */ - private Document parseDocument(Key key, String xml) throws DBException { - Document doc = null; - try { - doc = DOMParser.toDocument(xml); - - // Have to move it to Xindice DOM for XMLObject AutoLinking - byte[] b = DOMCompressor.Compress(doc, symbols); - doc = new DocumentImpl(b, symbols, new NodeSource(this, key)); - - if (documentCache != null) - documentCache.putDocument(this, key, b); - } - catch (Exception e) { - throw new DBException(FaultCodes.COL_DOCUMENT_MALFORMED, "Unable to parse Document", e); - } - return doc; - } - - /** - * getCanonicalName returns the canonical name for this Object. - * <br> - * ex: /local/test/ocs - * - * @return The canonical name - */ - public final String getCanonicalName() { - return canonicalName; - } - - protected final void setCanonicalName(String canonicalName) { - this.canonicalName = canonicalName; - - // Calculate The OID Template - collection_id = Math.abs(canonicalName.hashCode()); - StringBuffer sb = new StringBuffer("00000000000000000000000000000000"); - String host = Integer.toString(host_id, 16); - String collection = Integer.toString(collection_id, 16); - sb.insert(8 - host.length(), host); - sb.insert(16 - collection.length(), collection); - sb.setLength(32); - oidTemplate = sb.toString(); - } - - /** - * getCanonicalDocumentName returns the canonical name for the specified - * Key in relation to this Collection. - * <br> - * ex: /local/test/ocs/ytd - * - * @param key The Key - * @return The canonical name - */ - public final String getCanonicalDocumentName(Key key) { - return getCanonicalDocumentName(key.toString()); - } - - public final String getCanonicalDocumentName(String key) { - StringBuffer sb = new StringBuffer(); - sb.append(canonicalName); - sb.append('/'); - sb.append(key); - return sb.toString(); - } - - public final boolean open() throws DBException { - return true; - } - - public boolean isOpened() throws DBException { - return true; - } - - public boolean exists() throws DBException { - return true; - } - - public boolean close() throws DBException { - return true; - } - - public boolean create() throws DBException { - // update the meta information if necessary - updateCollectionMeta(); - - DBObserver.getInstance().createCollection(this); - return true; - } - - public boolean drop() throws DBException { - if (this == getDatabase()) - throw new DBException(FaultCodes.DBE_CANNOT_DROP, "You Cannot Drop The Database"); - - DBObserver.getInstance().dropCollection(this); - - // drop the meta if necessary - if (isMetaEnabled()) { - MetaSystemCollection metacol = getMetaSystemCollection(); - metacol.dropCollectionMeta(this); - } - - // Drop Child Collections - String[] cols = listCollections(); - for (int i = 0; i < cols.length; i++) - dropCollection(getCollection(cols[i])); - - if (filer != null) { - // Drop Indexers - String[] idx = indexManager.list(); - for (int i = 0; i < idx.length; i++) - dropIndexer(getIndexer(idx[i])); - - // Now Drop The Filer - filer.drop(); - } - - getCollectionRoot().delete(); - getDatabase().flushConfig(); - - return true; - } - - // All Document Handling Code Follows - - /** - * createNewOID allocates a new Object ID to be used as a Key in the - * Collection. - * - * @return The newly generated Key - */ - public final Key createNewOID() { - long ct = System.currentTimeMillis(); - - synchronized (oidMutex) { - if (ct <= document_id) - ct = document_id + 1; - document_id = ct; - } - - StringBuffer sb = new StringBuffer(oidTemplate); - String document = Long.toString(document_id, 16); - sb.insert(32 - document.length(), document); - sb.setLength(32); - - return new Key(sb.toString()); - } - - /** - * createNewKey allocates a new Key to be used as a Key in the - * Collection. - * - * @param key The Key hint - * @return The newly generated Key - */ - protected final Key createNewKey(Object key) { - if (key == null) - return createNewOID(); - if (key instanceof Key) - return (Key) key; - else - return new Key(key.toString()); - } - - public final void flushSymbolTable() throws DBException { - if (symbols.isDirty() && !internalSymbols) - getSystemCollection().saveSymbols(this, symbols); - } - - /* - * Lowest-level method for saving a binary entry into the database. - * Does not update non-inline metadata. - */ - private void putBinary(Key key, byte[] bytes, boolean create) throws DBException { - - if (inlineMetaService == null) { - throw new DBException( - FaultCodes.COL_CANNOT_STORE, - "Cannot store a binary resource in collection " + name + ": inline-metadata is not enabled"); - } - - if (!create) { - byte[] storedBytes = getBinary(key); - if (storedBytes == null) { - /* - * XXX TODO - * Do we need a COL_KEY_ALREADY_PRESENT fault - * so that the caller can interpret this exception? - */ - throw new DBException( - FaultCodes.COL_CANNOT_STORE, - "Error storing binary object with key '" + key + "': the 'create' flag is false and" + " the key is not in the database"); - } - } - - InlineMetaMap map = inlineMetaService.getEmptyMap(); - map.put("type", ResourceTypeReader.BINARY); - Value value = inlineMetaService.createValue(map, bytes, 0, bytes.length); - filer.writeRecord(key, value); - } - - /** - * This is the lowest-level method for storing a record into the backing store. - * It does not update non-inline metadata. - */ - private void putDocument(Key key, Document document /* TODO used this variable , boolean create*/ - ) throws DBException { - - String localDebugHeader = debugHeader() + "putDocument: docKey=<" + key.toString() + ">: "; - - log.debug(localDebugHeader + "document=<" + TextWriter.toString(document).toString() + ">"); - - checkFiler(FaultCodes.COL_NO_FILER); - - if (document instanceof DBDocument) { - // This is a shitty shitty hack... Kill immediately - DBDocument dbDoc = (DBDocument) document; - if (dbDoc.getSource() == null) - dbDoc.setSource(new NodeSource(this, key)); - } - - /* - * The possibilities are restricted because only XML - * is handled by this method. There are only a few - * pieces of information that need to be constructed: - * 1) the xindice DOM document is needed for all XML objects, as - * it is handed to the IndexManager and the DBObserver. - * 2) the packed document, if this is a compressed XML object, - * is needed for the cache and the BTree (via the Value object). - * 3) the string-converted-to-utf-8 bytes, if this is a non-compressed - * XML object, is needed for the BTree (via the Value object). - * 4) A Value object, with a header if headers are enabled, and - * otherwise without headers, for the BTree. - */ - - byte[] packedDocument = null; - byte[] utf8Document = null; - - if (compressed) { - try { - - packedDocument = DOMCompressor.Compress(document, symbols); - log.debug(localDebugHeader + "length=" + packedDocument.length); - - // Why must it be re-created? - document = new DocumentImpl(packedDocument, symbols, new NodeSource(this, key)); - - log.debug(localDebugHeader + "packedDocument: length=" + packedDocument.length + " document=<" + TextWriter.toString(document) + ">"); - } - catch (Exception e) { - throw new DBException(FaultCodes.COL_CANNOT_STORE, localDebugHeader + "Error compressing Document '" + key + "'", e); - } - } - else { - try { - utf8Document = TextWriter.toString(document).getBytes("utf-8"); - log.debug(localDebugHeader + "utf8Document: length=" + utf8Document.length + " document=<" + new String(utf8Document, "utf-8") + ">"); - } - catch (UnsupportedEncodingException e) { - throw new DBException(FaultCodes.GEN_FATAL_ERROR, "utf-8 encoding not supported", e); - } - } - - /* - * XXX TODO - * Can this be moved into the if(compressed) block? - */ - flushSymbolTable(); - - // Temporary until insert and update are separate - Document oldDoc = getDocument(key); - if (oldDoc != null) { - indexManager.removeDocument(key, oldDoc); - } - indexManager.addDocument(key, document); - - /* - * Construct the Value object that is stored in the BTree. - */ - Value value; - if (inlineMetaService == null) { - if (compressed) { - value = new Value(packedDocument); - } - else { - value = new Value(utf8Document); - } - } - else { - InlineMetaMap map = inlineMetaService.getEmptyMap(); - map.put("type", ResourceTypeReader.XML); - if (compressed) { - value = inlineMetaService.createValue(map, packedDocument, 0, packedDocument.length); - } - else { - value = inlineMetaService.createValue(map, utf8Document, 0, utf8Document.length); - } - } - filer.writeRecord(key, value); - - // Cache Stuff - if (documentCache != null) { - if (compressed) - documentCache.putDocument(this, key, packedDocument); - else - documentCache.putDocument(this, key, document); - } - - DBObserver.getInstance().putDocument(this, key, document, oldDoc == null); - } - - /** - * update the modified time of this collection when appropriate - */ - protected void updateCollectionMeta() { - // update the meta data if necessary - if (isMetaEnabled()) { - MetaSystemCollection metacol = getMetaSystemCollection(); - MetaData meta = null; - try { - meta = metacol.getCollectionMeta(this); - } - catch (DBException e) { - // something strange has happened.. can't get the - // meta data for this collection - if (log.isWarnEnabled()) - log.warn("Error fetching collection meta. " + e); - return; - } - - if (log.isInfoEnabled()) - log.info("Updating modified time for this collection's meta"); - long now = System.currentTimeMillis(); - if (null == meta) { - meta = new MetaData(MetaData.COLLECTION, getCanonicalName(), now, now); - } - else { - // this collection already has a meta. so update its modified time. - meta.setContext(0, now); - } - try { - metacol.setCollectionMeta(this, meta); - } - catch (DBException e) { - if (log.isWarnEnabled()) - log.warn("Error setting the collection meta. " + e); - return; - } - } - } - - /** - * update the modified time of this document when appropriate - */ - protected void updateDocumentMeta(String id) throws DBException { - // update the meta data if necessary - if (!isMetaEnabled()) - return; - - Document doc = getDocument(id); - if (null == doc) - throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND, "Document " + id + " does not exist"); - - MetaSystemCollection metacol = getMetaSystemCollection(); - MetaData meta = metacol.getDocumentMeta(this, id); - - String path = getCanonicalDocumentName(id); - - /* - TimeRecord rec = null; - if( null == meta || !meta.hasContext() ) - rec = getDatabase().getTime(path); - - long created = (null != rec) ? rec.getCreatedTime() : System.currentTimeMillis(); - long modified = (null != rec) ? rec.getModifiedTime() : System.currentTimeMillis(); - */ - - // this is wrong.. but it should work for now... - long created = System.currentTimeMillis(); - long modified = System.currentTimeMillis(); - - if (null == meta) { - meta = new MetaData(MetaData.DOCUMENT, path, created, modified); - } - else if (!meta.hasContext()) { - meta.setContext(created, modified); - } - else { - meta.setContext(0, modified); - } - metacol.setDocumentMeta(this, id, meta); - } - - /** - * insertBinary inserts a new binary object into a Xindice Collection. - * - * @param docKey The document Key - * @param document The document to insert - * @throws DBException if inline-metadata is not enabled, the key is - * already in the database, or an error occurs while saving. - */ - public void insertBinary(Object docKey, byte[] bytes) throws DBException { - - if (inlineMetaService == null) { - throw new DBException( - FaultCodes.COL_CANNOT_STORE, - "Cannot insert a binary resource in collection " + name + ": inline-metadata is not enabled."); - } - - putBinary(createNewKey(docKey), bytes, true); - - // update the meta information if necessary - updateCollectionMeta(); - } - - /** - * Insert a binary object into a Xindice Collection. A unique key - * is automatically generated. by which the binary object can be - * retrieved in the future. Note: because the key is automatically - * unique, this insert method will never cause a collision with an - * object already in the database. - * - * @param bytes The bytes making up the binary object to insert - * @return Key automatically generated for the binary object - * @throws DBException if inline-metadata is not enabled, or an - * error occurs while saving. - */ - public Key insertBinary(byte[] bytes) throws DBException { - - if (inlineMetaService == null) { - throw new DBException( - FaultCodes.COL_CANNOT_STORE, - "Cannot insert a binary resource in collection " + name + ": inline-metadata is not enabled."); - } - - Key key = createNewOID(); - putBinary(key, bytes, true); - - // update the meta information if necessary - updateCollectionMeta(); - - return key; - } - - /** - * insertDocument inserts a new Document into a Xindice Collection. - * - * @param document The Document - * @return The new Object Identifier - */ - public final Key insertDocument(Document document) throws DBException { - Key key = createNewOID(); - putDocument(key, document /*, true */ - ); - // update the meta information if necessary - updateCollectionMeta(); - return key; - } - - /** - * insertDocument inserts a new Document into a Xindice Collection. - * - * @param docKey The document Key - * @param document The document to insert - */ - public final void insertDocument(Object docKey, Document document) throws DBException { - putDocument(createNewKey(docKey), document /*, true */ - ); - // update the meta information if necessary - updateCollectionMeta(); - } - - /** - * setDocument overwrites/updates an existing Document in a - * Xindice Collection. - * - * @param docKey The Document Key - * @param document The Document - */ - public final void setDocument(Object docKey, Document document) throws DBException { - putDocument(createNewKey(docKey), document /*, false */ - ); - // update the meta for this document - updateDocumentMeta(docKey.toString()); - } - - /** - * remove removes an object from the Collection based on its Key, - * regardless of it's type. - * - * @param key The Object's Key - */ - public final void remove(Object key) throws DBException { - checkFiler(FaultCodes.COL_NO_FILER); - - Key objKey = createNewKey(key); - - Document oldDoc = getDocument(objKey); - if (oldDoc != null) - indexManager.removeDocument(objKey, oldDoc); - - if (documentCache != null) - documentCache.removeDocument(this, objKey); - - if (!filer.deleteRecord(objKey)) - throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND, "Document Does Not Exist"); - - // update the meta for this collection if necessary - updateCollectionMeta(); - // remove the document meta - if (isMetaEnabled()) { - getMetaSystemCollection().dropDocumentMeta(this, objKey.toString()); - } - DBObserver.getInstance().dropDocument(this, objKey); - } - - /** - * Retrieve a binary database entry by key. - * This low-level method will not update non-inline metadata. - * - * @param docKey identifying the desired database entry - * @return byte[] containing the binary database entry - * @throws DBException if inline-metadata is not enabled - * (binary resource cannot be stored in a collection - * which does not have inline-metadata enabled), - * in case of backing store error, and in case of - * header corruption - */ - public final byte[] getBinary(Object docKey) throws DBException { - - log.debug(debugHeader() + "getBinary: docKey=<" + docKey.toString() + ">"); - - if (inlineMetaService != null) { - throw new DBException( - FaultCodes.COL_DOCUMENT_NOT_FOUND, - "There are no binary resources in collection" + name + ": inline-metadata is not enabled."); - } - - Object entry = getEntry(docKey); - if (entry == null) { - return null; - } - - if (!(entry instanceof byte[])) { - throw new DBException( - FaultCodes.COL_INVALID_RESULT, - "The resource associated with key '" + docKey.toString() + "' in collection '" + name + "'is not binary"); - } - - return (byte[]) entry; - } - - /** - * getDocument retrieves a Document by Key. - * - * @param docKey The Document Key - * @return The Document - */ - public final Document getDocument(Object docKey) throws DBException { - - log.debug(debugHeader() + "getDocument: docKey=<" + docKey.toString() + ">"); - - Object entry = getEntry(docKey); - if (entry == null) { - return null; - } - - if (!(entry instanceof Document)) { - throw new DBException( - FaultCodes.COL_INVALID_RESULT, - "The resource associated with key '" + docKey.toString() + "' in collection '" + name + "'is not XML"); - } - - return (Document) entry; - } - - /** - * Retrieve a database entry by key. - * If no matching entry is found, null is returned; if - * an XML entry is found, a Document is returned; if a - * binary entryis found, byte[] is returned. - * This low-level method will not update non-inline metadata. - * - * @param docKey identifying the desired database entry - * @return Object containing the database entry, or null if no - * matching entry is found - * @throws DBException in case of backing store error, - * and in case of header corruption - */ - public final Object getEntry(Object docKey) throws DBException { - - /* - * I would prefer to throw an exception (NPE) in this case, - * but we have a test indicating a null return... - */ - if (docKey == null) { - return null; - } - - String localDebugHeader = debugHeader() + "getEntry: docKey=<" + docKey.toString() + ">: "; - - log.debug(localDebugHeader); - - checkFiler(FaultCodes.COL_NO_FILER); - - Key key = createNewKey(docKey); - - /* - * If the key has a corresponding value in the cache, return it - * and save a disk access. - * - * At some point the current document-centric cache implementation - * needs to be converted to an entry cache which can hold both - * Document and byte[]. - */ - if (documentCache != null) { - Document document = documentCache.getDocument(this, key); - log.debug(localDebugHeader + "cache search returned: " + document); - if (document != null) { - return document; - } - } - - Record record = filer.readRecord(key); - if (record == null) { - return null; - } - - log.debug(localDebugHeader + "record value: length=" + record.getValue().getLength()); - - Value value; - InlineMetaMap metaMap = null; - if (inlineMetaService == null) { - log.debug(localDebugHeader + "type not available"); - value = record.getValue(); - } - else { - log.debug(localDebugHeader + "decomposing header..."); - InlineMetaService.DatabaseEntry databaseEntry = inlineMetaService.readDatabaseEntry(record.getValue()); - metaMap = databaseEntry.map; - value = databaseEntry.value; - - log.debug(localDebugHeader + "type=" + metaMap.get("type") + " length=" + value.getLength()); - } - - if (inlineMetaService == null || metaMap.get("type").equals(ResourceTypeReader.XML)) { - - log.debug(localDebugHeader + "XML document"); - - Document document; - if (compressed) { - - document = new DocumentImpl(value.getData(), symbols, new NodeSource(this, key)); - - flushSymbolTable(); - - log.debug(localDebugHeader + "compressed XML document: document=<" + TextWriter.toString(document) + ">"); - - if (documentCache != null) { - documentCache.putDocument(this, key, value.getData()); - } - } - else { - log.debug(localDebugHeader + "pre parseDocument(): value=<" + value.toString() + ">"); - document = parseDocument(key, value.toString()); - } - - DBObserver.getInstance().loadDocument(this, record, document); - return document; - } - else { - return value.getData(); - } - } - - /** - * getContainer retrieves a Container from the Collection. The Container - * encapsulates all information needed in dealing with a Document outside - * of the context of a Collection (ex: DocumentContext). - * - * @param docKey The Document Key - * @return The Container - */ - public final Container getContainer(Object docKey) throws DBException { - Key key = createNewKey(docKey); - Document doc = getDocument(key); - return doc != null ? new ColContainer(key, doc) : null; - } - - /** - * getObject instantiates and returns an XMLSerializable object based on the - * provided Key. Xindice takes care of instantiating the correct class, but - * only if a class was registered with the Document in the first place. - * - * @param key The Document Key - * @return an Castable XMLSerializable Instance - */ - public final XMLSerializable getObject(Object key) throws DBException { - String className = null; - - Document doc = getDocument(key); - - if (doc != null) { - NodeList childNodes = doc.getChildNodes(); - int size = childNodes.getLength(); - for (int i = 0; i < size; i++) { - Node n = childNodes.item(i); - if (n.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE && n.getNodeName().equals(CLASSNAME)) { - className = n.getNodeValue().trim(); - break; - } - } - - if (className != null) { - try { - XMLSerializable obj = (XMLSerializable) Class.forName(className).newInstance(); - obj.streamFromXML(doc.getDocumentElement()); - return obj; - } - catch (Exception e) { - if (log.isDebugEnabled()) { - log.debug("No message", e); - } - } - } - } - - return null; - } - - private void putObject(Key key, XMLSerializable obj /*, boolean create */ - ) throws DBException { - - String localDebugHeader = debugHeader() + "putObject: key=<" + key.toString() + ">: "; - - Document doc = new DocumentImpl(); - ProcessingInstruction pi = doc.createProcessingInstruction(CLASSNAME, obj.getClass().getName()); - doc.appendChild(pi); - Element elem = obj.streamToXML(doc); - log.debug(localDebugHeader + "elem=<" + TextWriter.toString(elem) + ">"); - doc.appendChild(elem); - putDocument(key, doc /*, create */ - ); - } - - /** - * setObject sets an XMLSerializable object in the Collection based on the - * provided Key. Xindice takes care of associating the implementation class - * with the XMLSerializable object. - * - * @param key The Key to use - * @param obj The Object to set - */ - public final void setObject(Object key, XMLSerializable obj) throws DBException { - putObject(createNewKey(key), obj /*, false */ - ); - } - - /** - * insertObject inserts an XMLSerializable object into the Collection and - * returns a newly generated Key. Xindice takes care of associating the - * implementation class with the XMLSerializable object. - * - * @param obj The Object to insert - * @return The newly generated Key - */ - public final Key insertObject(XMLSerializable obj) throws DBException { - Key key = createNewOID(); - putObject(key, obj /*, true */ - ); - return key; - } - - /** - * insertObject inserts an XMLSerializable object into the Collection based - * on the specified Key. Xindice takes care of associating the - * implementation class with the XMLSerializable object. - * - * @param key The Key to use - * @param obj The Object to insert - */ - public final void insertObject(String key, XMLSerializable obj) throws DBException { - putObject(createNewKey(key), obj /*, true */ - ); - } - - /** - * queryCollection performs a query against the current collection - * using the specified style and query String. - * - * @param style The query style to use (ex: XPath) - * @param query The query to execute - * @param nsMap The namespace Map (if any) - * @return The resulting NodeSet - */ - public final NodeSet queryCollection(String style, String query, NamespaceMap nsMap) throws DBException { - // a collection in which you are unable to file documents will have no filer - // (for example the root collection). Rather than throwing an exception return - // a constant result (nothing) - return null == filer ? EMPTY_NODESET : getQueryEngine().query(this, style, query, nsMap, null); - } - - /** - * queryDocument performs a query against a single Document using - * the specified style, query string, and Document ID. - * - * @param style The query style to use (ex: XPath) - * @param query The query to execute - * @param nsMap The namespace Map (if any) - * @param key The Document to query - * @return The resulting NodeSet - */ - public final NodeSet queryDocument(String style, String query, NamespaceMap nsMap, Object key) throws DBException { - checkFiler(FaultCodes.QRY_STYLE_NOT_FOUND); - Key[] k = null; - if (key instanceof Key[]) - k = (Key[]) key; - else - k = new Key[] { createNewKey(key)}; - return getQueryEngine().query(this, style, query, nsMap, k); - } - - /** - * getDocumentSet returns the set of Documents being maintained - * by this Collection. - * - * @return The DocumentSet - */ - public final DocumentSet getDocumentSet() throws DBException { - // a collection in which you are unable to file documents will have no filer - // (for example the root collection). Rather than throwing an exception return - // a constant result (nothing) - return null == filer ? EMPTY_DOCUMENTSET : new ColDocumentSet(filer.getRecordSet()); - } - - /** - * listDocuments returns a list of all document keys stored by this - * collection. - * - * @return the list of document keys - */ - public final String[] listDocuments() throws DBException { - // a collection in which you are unable to file documents will have no filer - // (for example the root collection). Rather than throwing an exception return - // a constant result (nothing) - if (null == filer) - { - return EMPTY_STRING_ARRAY; - } - else - { - RecordSet set = filer.getRecordSet(); - - // todo: what happens if the size if > than the size of an int. - // I'm pretty sure some sort of runtime exception will occur - // in the ArrayList.add method. - - // give a hint to the size of the record set, saves on arraylist array copies. - ArrayList temp = new ArrayList((int)filer.getRecordCount()); - - while (set.hasMoreRecords()) { - Key key = set.getNextKey(); - temp.add(key.toString()); - } - - return (String[]) temp.toArray(new String[0]); - } - } - - /** - * getDocumentCount returns the count of Documents being maintained - * by this Collection. - * - * @return The Document count - */ - public final long getDocumentCount() throws DBException { - // a collection in which you are unable to file documents will have no filer - // (for example the root collection). Rather than throwing an exception return - // a constant result (nothing) - return null == filer ? 0 : filer.getRecordCount(); - } - - public void dispose() { - try { - ((Collection) this).close(); - } - catch (Exception e) { - if (log.isDebugEnabled()) { - log.debug("No message", e); - } - } - } - - private String debugHeader() { - return "[" - + Thread.currentThread().getName() - + "] Collection:" - + " name=" - + name - + " compressed=" - + compressed - + " inline-metadata=" - + (inlineMetaService != null) - + " "; - } - - // META DATA RELATED DOCS - /** - * Returns whether or not meta data is enabled. - * @return boolean whether or not meta data is enabled. - */ - public boolean isMetaEnabled() { - return getDatabase().isMetaEnabled(); - } - - /** - * Return the MetaData for this collection. - * - * If metadata is not enabled in the configuration, the MetaData object - * returned will be null. - * @return MetaData this collection's metadata. - */ - public MetaData getCollectionMeta() throws DBException { - MetaData meta = null; - if (!isMetaEnabled()) { - if (log.isWarnEnabled()) { - log.warn("Meta information requested but not enabled in config!"); - } - return meta; - } - MetaSystemCollection metacol = getMetaSystemCollection(); - meta = metacol.getCollectionMeta(this); - long now = System.currentTimeMillis(); - if (null == meta) { - meta = new MetaData(MetaData.COLLECTION, getCanonicalName(), now, now); - metacol.setCollectionMeta(this, meta); - } - return meta; - } - - /** - * Reset the metadata object for this collection. - * @param meta the Metadata to use - */ - public void setCollectionMeta(MetaData meta) throws DBException { - if (!isMetaEnabled()) { - if (log.isWarnEnabled()) { - log.warn("Meta information requested but not enabled in config!"); - } - return; - } - if (null != meta) { - if (meta.getType() != MetaData.COLLECTION) - throw new DBException(FaultCodes.GEN_UNKNOWN, "Mismatch type of meta data for collection " + getCanonicalName()); - - MetaSystemCollection metacol = getMetaSystemCollection(); - metacol.setCollectionMeta(this, meta); - } - } - - /** - * Return the MetaData object for a document within this collection. - * - * If metadata is not enabled, the MetaData object returned will be null. - * @param id the document whose metadata you want - */ - public MetaData getDocumentMeta(String id) throws DBException { - MetaData meta = null; - if (!isMetaEnabled()) { - if (log.isWarnEnabled()) { - log.warn("Meta information requested but not enabled in config!"); - } - return meta; - } - Document doc = getDocument(id); - if (null == doc) - throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND, "Document " + id + " does not exist"); - - MetaSystemCollection metacol = getMetaSystemCollection(); - meta = metacol.getDocumentMeta(this, id); - - String path = getCanonicalDocumentName(id); - - /* - TimeRecord rec = null; - if( null == meta || !meta.hasContext() ) - rec = getDatabase().getTime(path); - - long created = (null != rec) ? rec.getCreatedTime() : System.currentTimeMillis(); - long modified = (null != rec) ? rec.getModifiedTime() : System.currentTimeMillis(); - */ - - // this is wrong.. but it should work for now... - long created = System.currentTimeMillis(); - long modified = System.currentTimeMillis(); - - if (null == meta) { - meta = new MetaData(MetaData.DOCUMENT, path, created, modified); - metacol.setDocumentMeta(this, id, meta); - } - else if (!meta.hasContext()) { - meta.setContext(created, modified); - } - - return meta; - } - - /** - * Set the metadata associated with a document within this collection. - * - * @param id the document name - * @param meta the metadata object to be used. - */ - public void setDocumentMeta(String id, MetaData meta) throws DBException { - if (!isMetaEnabled()) { - if (log.isWarnEnabled()) { - log.warn("Meta information requested but not enabled in config!"); - } - return; - } - Document doc = getDocument(id); - if (null == doc) - throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND, "Document " + id + " does not exist"); - - if (null != meta) { - if (meta.getType() == MetaData.UNKNOWN || meta.getType() == MetaData.COLLECTION) - throw new DBException(FaultCodes.GEN_UNKNOWN, "Mismatch type of meta data for document " + getCanonicalDocumentName(id)); - - MetaSystemCollection metacol = getMetaSystemCollection(); - metacol.setDocumentMeta(this, id, meta); - } - } - - /** - * Return the MetaSystemCollection for the database containing this - * collection. - * - * @return MetaSystemCollection - */ - private MetaSystemCollection getMetaSystemCollection() //throws DBException - { - return getDatabase().getMetaSystemCollection(); - } - - /** - * ColDocumentSet - */ - private class ColDocumentSet implements DocumentSet { - private RecordSet set; - - public ColDocumentSet(RecordSet set) { - this.set = set; - } - - public boolean hasMoreDocuments() throws DBException { - return set.hasMoreRecords(); - } - - public Container getNextContainer() throws DBException { - if (set.hasMoreRecords()) { - Record rec = set.getNextRecord(); - Key key = rec.getKey(); - Value val = rec.getValue(); - if (val.getData() != null) { - try { - if (compressed) { - Document doc = new DocumentImpl(val.getData(), symbols, new NodeSource(Collection.this, key)); - return new ColContainer(key, doc); - } - else - return new ColContainer(key, DOMParser.toDocument(val)); - } - catch (Exception e) { - if (log.isDebugEnabled()) { - log.debug("No message", e); - } - } - } - } - return null; - } - - public Document getNextDocument() throws DBException { - Container c = getNextContainer(); - if (c != null) - return c.getDocument(); - else - return null; - } - } - - /** - * ColContainer - */ - private class ColContainer implements Container { - private Key key; - private Document document; - - public ColContainer(Key key, Document document) { - this.key = key; - this.document = document; - } - - public Collection getCollection() { - return Collection.this; - } - - public Key getKey() { - return key; - } - - public String getCanonicalName() throws DBException { - return getCanonicalDocumentName(key); - } - - public Document getDocument() { - return document; - } - - public Document rollback() throws DBException { - document = Collection.this.getDocument(key); - return document; - } - - public void commit(Document doc) throws DBException { - document = doc; - commit(); - } - - public void commit() throws DBException { - putDocument(key, document /*, false */ - ); - } - - public void remove() throws DBException { - Collection.this.remove(key); - } - } + + /** + * ColContainer + */ + private class ColContainer implements Container { + private Document document; + private Key key; + + public ColContainer(Key key, Document document) { + this.key = key; + this.document = document; + } + + public void commit() throws DBException { + putDocument(key, document /*, false */ + ); + } + + public void commit(Document doc) throws DBException { + document = doc; + commit(); + } + + public String getCanonicalName() throws DBException { + return getCanonicalDocumentName(key); + } + + public Collection getCollection() { + return Collection.this; + } + + public Document getDocument() { + return document; + } + + public Key getKey() { + return key; + } + + public void remove() throws DBException { + Collection.this.remove(key); + } + + public Document rollback() throws DBException { + document = Collection.this.getDocument(key); + return document; + } + } + + /** + * ColDocumentSet + */ + private class ColDocumentSet implements DocumentSet { + private RecordSet set; + + public ColDocumentSet(RecordSet set) { + this.set = set; + } + + public Container getNextContainer() throws DBException { + if (set.hasMoreRecords()) { + Record rec = set.getNextRecord(); + Key key = rec.getKey(); + Value val = rec.getValue(); + if (val.getData() != null) { + try { + if (compressed) { + Document doc = new DocumentImpl(val.getData(), symbols, new NodeSource(Collection.this, key)); + return new ColContainer(key, doc); + } + else + return new ColContainer(key, DOMParser.toDocument(val)); + } + catch (Exception e) { + if (log.isDebugEnabled()) { + log.debug("No message", e); + } + } + } + } + return null; + } + + public Document getNextDocument() throws DBException { + Container c = getNextContainer(); + if (c != null) + return c.getDocument(); + else + return null; + } + + public boolean hasMoreDocuments() throws DBException { + return set.hasMoreRecords(); + } + } + + private static final String CACHE = "cache"; + private static final String CLASS = "class"; + private static final String CLASSNAME = "xindice-class"; + private static final String COMPRESSED = "compressed"; + private static final DocumentSet EMPTY_DOCUMENTSET = new EmptyDocumentSet(); + private static final NodeSet EMPTY_NODESET = new EmptyNodeSet(); + private static final String[] EMPTY_STRING_ARRAY = {}; + private static final String FILER = "filer"; + private static int host_id; + private static final String INDEXES = "indexes"; + private static final String INLINE_METADATA = "inline-metadata"; + private static Log log = LogFactory.getLog("org.apache.xindice.core"); + private static final String NAME = "name"; + private static final String SYMBOLS = "symbols"; + + static { + try { + InetAddress a = InetAddress.getLocalHost(); + byte[] b = a.getAddress(); + host_id = 0; + host_id += b[0]; + host_id += (b[1] << 8); + host_id += (b[2] << 16); + host_id += (b[3] << 24); + host_id = Math.abs(host_id); + } + catch (Exception e) { + + log.warn(e); + } + } + + private String canonicalName; + // Object ID Stuff + private int collection_id = 0; + private File collectionRoot; + private boolean compressed = false; + private long document_id = System.currentTimeMillis(); + private DocumentCache documentCache; + private Filer filer = null; + private IndexManager indexManager; + private InlineMetaService inlineMetaService; + private boolean internalSymbols = false; + private String name; + private Object oidMutex = new Object(); + private String oidTemplate = null; + private Collection parent = null; + private SymbolTable symbols = null; + + protected Collection() {} + + /** + * + * @param parentCollection + */ + public Collection(Collection parentCollection) { + this(); + this.parent = parentCollection; + } + + private void checkFiler(int faultCode) throws DBException { + if (filer == null) + throw new DBException(faultCode, "This Collection '" + name + "' cannot store Documents"); + } + + /** + * @see org.apache.xindice.core.DBObject#close() + */ + public boolean close() throws DBException { + return true; + } + + /** + * @see org.apache.xindice.core.DBObject#create() + */ + public boolean create() throws DBException { + // update the meta information if necessary + updateCollectionMeta(); + + DBObserver.getInstance().createCollection(this); + return true; + } + + /** + * @see org.apache.xindice.core.CollectionManager#createCollection(java.lang.String, org.apache.xindice.util.Configuration) + */ + public final Collection createCollection(String path, Configuration config) throws DBException { + Collection col = super.createCollection(path, config); + getDatabase().flushConfig(); + return col; + } + + /** + * createIndexer creates a new Indexer object and any associated + * system resources that the Indexer will need. + * + * @param config The Indexer's configuration + * @return The newly created Indexer + */ + public final Indexer createIndexer(Configuration config) throws DBException { + checkFiler(FaultCodes.COL_NO_INDEXMANAGER); + Indexer idx = indexManager.create(config); + getDatabase().flushConfig(); + return idx; + } + + /** + * createNewKey allocates a new Key to be used as a Key in the + * Collection. + * + * @param key The Key hint + * @return The newly generated Key + */ + protected final Key createNewKey(Object key) { + if (key == null) + return createNewOID(); + if (key instanceof Key) + return (Key) key; + else + return new Key(key.toString()); + } + + /** + * createNewOID allocates a new Object ID to be used as a Key in the + * Collection. + * + * @return The newly generated Key + */ + public final Key createNewOID() { + long ct = System.currentTimeMillis(); + + synchronized (oidMutex) { + if (ct <= document_id) + ct = document_id + 1; + document_id = ct; + } + + StringBuffer sb = new StringBuffer(oidTemplate); + String document = Long.toString(document_id, 16); + sb.insert(32 - document.length(), document); + sb.setLength(32); + + return new Key(sb.toString()); + } + + private String debugHeader() { + return "[" + + Thread.currentThread().getName() + + "] Collection:" + + " name=" + + name + + " compressed=" + + compressed + + " inline-metadata=" + + (inlineMetaService != null) + + " "; + } + + /** + * @see org.apache.xindice.util.Disposable#dispose() + */ + public void dispose() { + try { + ((Collection) this).close(); + } + catch (Exception e) { + if (log.isDebugEnabled()) { + log.debug("No message", e); + } + } + } + + /** + * @see org.apache.xindice.core.DBObject#drop() + */ + public boolean drop() throws DBException { + if (this == getDatabase()) + throw new DBException(FaultCodes.DBE_CANNOT_DROP, "You Cannot Drop The Database"); + + DBObserver.getInstance().dropCollection(this); + + // drop the meta if necessary + if (isMetaEnabled()) { + MetaSystemCollection metacol = getMetaSystemCollection(); + metacol.dropCollectionMeta(this); + } + + // Drop Child Collections + String[] cols = listCollections(); + for (int i = 0; i < cols.length; i++) + dropCollection(getCollection(cols[i])); + + if (filer != null) { + // Drop Indexers + String[] idx = indexManager.list(); + for (int i = 0; i < idx.length; i++) + dropIndexer(getIndexer(idx[i])); + + // Now Drop The Filer + filer.drop(); + } + + getCollectionRoot().delete(); + getDatabase().flushConfig(); + + return true; + } + + /** + * @see org.apache.xindice.core.CollectionManager#dropCollection(org.apache.xindice.core.Collection) + */ + public final boolean dropCollection(Collection collection) throws DBException { + boolean success = super.dropCollection(collection); + getDatabase().flushConfig(); + return success; + } + + /** + * dropIndexer physically removes the specified Indexer and any + * associated system resources that the Indexer uses. + * + * @param index The Indexer to drop + * @return Whether or not the Indexer was dropped + */ + public final boolean dropIndexer(Indexer index) throws DBException { + checkFiler(FaultCodes.COL_NO_INDEXMANAGER); + + if (index == null) + throw new DBException(FaultCodes.IDX_INDEX_NOT_FOUND, "Index Value Null"); + + boolean success = indexManager.drop(index.getName()); + getDatabase().flushConfig(); + return success; + } + + /** + * @see org.apache.xindice.core.DBObject#exists() + */ + public boolean exists() throws DBException { + return true; + } + + /** + * @throws DBException + */ + public final void flushSymbolTable() throws DBException { + if (symbols.isDirty() && !internalSymbols) + getSystemCollection().saveSymbols(this, symbols); + } + + /** + * Retrieve a binary database entry by key. + * This low-level method will not update non-inline metadata. + * + * @param docKey identifying the desired database entry + * @return byte[] containing the binary database entry + * @throws DBException if inline-metadata is not enabled + * (binary resource cannot be stored in a collection + * which does not have inline-metadata enabled), + * in case of backing store error, and in case of + * header corruption + */ + public final byte[] getBinary(Object docKey) throws DBException { + + log.debug(debugHeader() + "getBinary: docKey=<" + docKey.toString() + ">"); + + if (inlineMetaService != null) { + throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND, "There are no binary resources in collection" + name + ": inline-metadata is not enabled."); + } + + Object entry = getEntry(docKey); + if (entry == null) { + return null; + } + + if (!(entry instanceof byte[])) { + throw new DBException(FaultCodes.COL_INVALID_RESULT, "The resource associated with key '" + docKey.toString() + "' in collection '" + name + "'is not binary"); + } + + return (byte[]) entry; + } + + /** + * getCanonicalDocumentName returns the canonical name for the specified + * Key in relation to this Collection. + * <br> + * ex: /local/test/ocs/ytd + * + * @param key The Key + * @return The canonical name + */ + public final String getCanonicalDocumentName(Key key) { + return getCanonicalDocumentName(key.toString()); + } + + /** + * @param key + * @return + */ + public final String getCanonicalDocumentName(String key) { + StringBuffer sb = new StringBuffer(); + sb.append(canonicalName); + sb.append('/'); + sb.append(key); + return sb.toString(); + } + + /** + * getCanonicalName returns the canonical name for this Object. + * <br> + * ex: /local/test/ocs + * + * @return The canonical name + */ + public final String getCanonicalName() { + return canonicalName; + } + + /** + * Return the MetaData for this collection. + * + * If metadata is not enabled in the configuration, the MetaData object + * returned will be null. + * @return MetaData this collection's metadata. + */ + public MetaData getCollectionMeta() throws DBException { + MetaData meta = null; + if (!isMetaEnabled()) { + if (log.isWarnEnabled()) { + log.warn("Meta information requested but not enabled in config!"); + } + return meta; + } + MetaSystemCollection metacol = getMetaSystemCollection(); + meta = metacol.getCollectionMeta(this); + long now = System.currentTimeMillis(); + if (null == meta) { + meta = new MetaData(MetaData.COLLECTION, getCanonicalName(), now, now); + metacol.setCollectionMeta(this, meta); + } + return meta; + } + + /** + * @return + */ + public final File getCollectionRoot() { + return collectionRoot; + } + + /** + * getContainer retrieves a Container from the Collection. The Container + * encapsulates all information needed in dealing with a Document outside + * of the context of a Collection (ex: DocumentContext). + * + * @param docKey The Document Key + * @return The Container + */ + public final Container getContainer(Object docKey) throws DBException { + Key key = createNewKey(docKey); + Document doc = getDocument(key); + return doc != null ? new ColContainer(key, doc) : null; + } + + /** + * getDatabase returns the Database owner for this Collection. + * + * @return The Database + */ + public Database getDatabase() { + return parent.getDatabase(); + } + + /** + * getDocument retrieves a Document by Key. + * + * @param docKey The Document Key + * @return The Document + */ + public final Document getDocument(Object docKey) throws DBException { + + log.debug(debugHeader() + "getDocument: docKey=<" + docKey.toString() + ">"); + + Object entry = getEntry(docKey); + if (entry == null) { + return null; + } + + if (!(entry instanceof Document)) { + throw new DBException(FaultCodes.COL_INVALID_RESULT, "The resource associated with key '" + docKey.toString() + "' in collection '" + name + "'is not XML"); + } + + return (Document) entry; + } + + /** + * getDocumentCount returns the count of Documents being maintained + * by this Collection. + * + * @return The Document count + */ + public final long getDocumentCount() throws DBException { + // a collection in which you are unable to file documents will have no filer + // (for example the root collection). Rather than throwing an exception return + // a constant result (nothing) + return null == filer ? 0 : filer.getRecordCount(); + } + + /** + * Return the MetaData object for a document within this collection. + * + * If metadata is not enabled, the MetaData object returned will be null. + * @param id the document whose metadata you want + */ + public MetaData getDocumentMeta(String id) throws DBException { + MetaData meta = null; + if (!isMetaEnabled()) { + if (log.isWarnEnabled()) { + log.warn("Meta information requested but not enabled in config!"); + } + return meta; + } + Document doc = getDocument(id); + if (null == doc) + throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND, "Document " + id + " does not exist"); + + MetaSystemCollection metacol = getMetaSystemCollection(); + meta = metacol.getDocumentMeta(this, id); + + String path = getCanonicalDocumentName(id); + + /* + TimeRecord rec = null; + if( null == meta || !meta.hasContext() ) + rec = getDatabase().getTime(path); + + long created = (null != rec) ? rec.getCreatedTime() : System.currentTimeMillis(); + long modified = (null != rec) ? rec.getModifiedTime() : System.currentTimeMillis(); + */ + + // this is wrong.. but it should work for now... + long created = System.currentTimeMillis(); + long modified = System.currentTimeMillis(); + + if (null == meta) { + meta = new MetaData(MetaData.DOCUMENT, path, created, modified); + metacol.setDocumentMeta(this, id, meta); + } + else if (!meta.hasContext()) { + meta.setContext(created, modified); + } + + return meta; + } + + /** + * getDocumentSet returns the set of Documents being maintained + * by this Collection. + * + * @return The DocumentSet + */ + public final DocumentSet getDocumentSet() throws DBException { + // a collection in which you are unable to file documents will have no filer + // (for example the root collection). Rather than throwing an exception return + // a constant result (nothing) + return null == filer ? EMPTY_DOCUMENTSET : new ColDocumentSet(filer.getRecordSet()); + } + + /** + * Retrieve a database entry by key. + * If no matching entry is found, null is returned; if + * an XML entry is found, a Document is returned; if a + * binary entryis found, byte[] is returned. + * This low-level method will not update non-inline metadata. + * + * @param docKey identifying the desired database entry + * @return Object containing the database entry, or null if no + * matching entry is found + * @throws DBException in case of backing store error, + * and in case of header corruption + */ + public final Object getEntry(Object docKey) throws DBException { + + /* + * I would prefer to throw an exception (NPE) in this case, + * but we have a test indicating a null return... + */ + if (docKey == null) { + return null; + } + + String localDebugHeader = debugHeader() + "getEntry: docKey=<" + docKey.toString() + ">: "; + + log.debug(localDebugHeader); + + checkFiler(FaultCodes.COL_NO_FILER); + + Key key = createNewKey(docKey); + + /* + * If the key has a corresponding value in the cache, return it + * and save a disk access. + * + * At some point the current document-centric cache implementation + * needs to be converted to an entry cache which can hold both + * Document and byte[]. + */ + if (documentCache != null) { + Document document = documentCache.getDocument(this, key); + log.debug(localDebugHeader + "cache search returned: " + document); + if (document != null) { + return document; + } + } + + Record record = filer.readRecord(key); + if (record == null) { + return null; + } + + log.debug(localDebugHeader + "record value: length=" + record.getValue().getLength()); + + Value value; + InlineMetaMap metaMap = null; + if (inlineMetaService == null) { + log.debug(localDebugHeader + "type not available"); + value = record.getValue(); + } + else { + log.debug(localDebugHeader + "decomposing header..."); + InlineMetaService.DatabaseEntry databaseEntry = inlineMetaService.readDatabaseEntry(record.getValue()); + metaMap = databaseEntry.map; + value = databaseEntry.value; + + log.debug(localDebugHeader + "type=" + metaMap.get("type") + " length=" + value.getLength()); + } + + if (inlineMetaService == null || metaMap.get("type").equals(ResourceTypeReader.XML)) { + + log.debug(localDebugHeader + "XML document"); + + Document document; + if (compressed) { + + document = new DocumentImpl(value.getData(), symbols, new NodeSource(this, key)); + + flushSymbolTable(); + + log.debug(localDebugHeader + "compressed XML document: document=<" + TextWriter.toString(document) + ">"); + + if (documentCache != null) { + documentCache.putDocument(this, key, value.getData()); + } + } + else { + log.debug(localDebugHeader + "pre parseDocument(): value=<" + value.toString() + ">"); + document = parseDocument(key, value.toString()); + } + + DBObserver.getInstance().loadDocument(this, record, document); + return document; + } + else { + return value.getData(); + } + } + + /** + * getFiler returns the low-level Filer instances underlying the + * Collection instance. + * + * @return The requested Filer + */ + public final Filer getFiler() { + return filer; + } + + /** + * getIndexer retrieves an Indexer by name. + * + * @param name The Indexer name + * @return The Indexer (or null) + */ + public final Indexer getIndexer(String name) throws DBException { + checkFiler(FaultCodes.COL_NO_INDEXMANAGER); + return indexManager.get(name); + } + + /** + * return the IndexManager being used by this Collection. + * + * @return The IndexManager + */ + public final IndexManager getIndexManager() throws DBException { + checkFiler(FaultCodes.COL_NO_INDEXMANAGER); + return indexManager; + } + + /** + * Return the MetaSystemCollection for the database containing this + * collection. + * + * @return MetaSystemCollection + */ + private MetaSystemCollection getMetaSystemCollection() //throws DBException + { + return getDatabase().getMetaSystemCollection(); + } + + public final String getName() { + return name; + } + + /** + * getObject instantiates and returns an XMLSerializable object based on the + * provided Key. Xindice takes care of instantiating the correct class, but + * only if a class was registered with the Document in the first place. + * + * @param key The Document Key + * @return an Castable XMLSerializable Instance + */ + public final XMLSerializable getObject(Object key) throws DBException { + String className = null; + + Document doc = getDocument(key); + + if (doc != null) { + NodeList childNodes = doc.getChildNodes(); + int size = childNodes.getLength(); + for (int i = 0; i < size; i++) { + Node n = childNodes.item(i); + if (n.getNodeType() == Node.PROCESSING_INSTRUCTION_NODE && n.getNodeName().equals(CLASSNAME)) { + className = n.getNodeValue().trim(); + break; + } + } + + if (className != null) { + try { + XMLSerializable obj = (XMLSerializable) Class.forName(className).newInstance(); + obj.streamFromXML(doc.getDocumentElement()); + return obj; + } + catch (Exception e) { + if (log.isDebugEnabled()) { + log.debug("No message", e); + } + } + } + } + + return null; + } + + /** + * getParentCollection returns the parent Collection of this + * Collection. + * + * @return The parent Collection (or null) + */ + public final Collection getParentCollection() throws DBException { + return parent; + } + + /** + * getQueryEngine returns the Database's Query Engine + * + * @return The Query Engine + */ + public QueryEngine getQueryEngine() throws DBException { + return getDatabase().getQueryEngine(); + } + + /** + * getSymbols returns the SymbolTable in use by this + * Collection. + * + * @return The Symbol Table + */ + public final SymbolTable getSymbols() throws DBException { + return symbols; + } + + /** + * getSystemCollection returns the System Collection. + * + * @return The System Collection + */ + public SystemCollection getSystemCollection() throws DBException { + return getDatabase().getSystemCollection(); + } + + /** + * Insert a binary object into a Xindice Collection. A unique key + * is automatically generated. by which the binary object can be + * retrieved in the future. Note: because the key is automatically + * unique, this insert method will never cause a collision with an + * object already in the database. + * + * @param bytes The bytes making up the binary object to insert + * @return Key automatically generated for the binary object + * @throws DBException if inline-metadata is not enabled, or an + * error occurs while saving. + */ + public Key insertBinary(byte[] bytes) throws DBException { + + if (inlineMetaService == null) { + throw new DBException(FaultCodes.COL_CANNOT_STORE, "Cannot insert a binary resource in collection " + name + ": inline-metadata is not enabled."); + } + + Key key = createNewOID(); + putBinary(key, bytes, true); + + // update the meta information if necessary + updateCollectionMeta(); + + return key; + } + + /** + * insertBinary inserts a new binary object into a Xindice Collection. + * + * @param docKey The document Key + * @param document The document to insert + * @throws DBException if inline-metadata is not enabled, the key is + * already in the database, or an error occurs while saving. + */ + public void insertBinary(Object docKey, byte[] bytes) throws DBException { + + if (inlineMetaService == null) { + throw new DBException(FaultCodes.COL_CANNOT_STORE, "Cannot insert a binary resource in collection " + name + ": inline-metadata is not enabled."); + } + + putBinary(createNewKey(docKey), bytes, true); + + // update the meta information if necessary + updateCollectionMeta(); + } + + /** + * insertDocument inserts a new Document into a Xindice Collection. + * + * @param document The Document + * @return The new Object Identifier + */ + public final Key insertDocument(Document document) throws DBException { + Key key = createNewOID(); + putDocument(key, document /*, true */ + ); + // update the meta information if necessary + updateCollectionMeta(); + return key; + } + + /** + * insertDocument inserts a new Document into a Xindice Collection. + * + * @param docKey The document Key + * @param document The document to insert + */ + public final void insertDocument(Object docKey, Document document) throws DBException { + putDocument(createNewKey(docKey), document /*, true */ + ); + // update the meta information if necessary + updateCollectionMeta(); + } + + /** + * insertObject inserts an XMLSerializable object into the Collection based + * on the specified Key. Xindice takes care of associating the + * implementation class with the XMLSerializable object. + * + * @param key The Key to use + * @param obj The Object to insert + */ + public final void insertObject(String key, XMLSerializable obj) throws DBException { + putObject(createNewKey(key), obj /*, true */ + ); + } + + /** + * insertObject inserts an XMLSerializable object into the Collection and + * returns a newly generated Key. Xindice takes care of associating the + * implementation class with the XMLSerializable object. + * + * @param obj The Object to insert + * @return The newly generated Key + */ + public final Key insertObject(XMLSerializable obj) throws DBException { + Key key = createNewOID(); + putObject(key, obj /*, true */ + ); + return key; + } + + // META DATA RELATED DOCS + /** + * Returns whether or not meta data is enabled. + * @return boolean whether or not meta data is enabled. + */ + public boolean isMetaEnabled() { + return getDatabase().isMetaEnabled(); + } + + public boolean isOpened() throws DBException { + return true; + } + + /** + * listDocuments returns a list of all document keys stored by this + * collection. + * + * @return the list of document keys + */ + public final String[] listDocuments() throws DBException { + // a collection in which you are unable to file documents will have no filer + // (for example the root collection). Rather than throwing an exception return + // a constant result (nothing) + if (null == filer) { + return EMPTY_STRING_ARRAY; + } + else { + RecordSet set = filer.getRecordSet(); + + // todo: what happens if the size if > than the size of an int. + // I'm pretty sure some sort of runtime exception will occur + // in the ArrayList.add method. + + // give a hint to the size of the record set, saves on arraylist array copies. + ArrayList temp = new ArrayList((int) filer.getRecordCount()); + + while (set.hasMoreRecords()) { + Key key = set.getNextKey(); + temp.add(key.toString()); + } + + return (String[]) temp.toArray(new String[0]); + } + } + + /** + * listIndexers returns a list of the currently registered Indexers + * as an array of String. + * + * @return The Indexer list + */ + public final String[] listIndexers() throws DBException { + checkFiler(FaultCodes.COL_NO_INDEXMANAGER); + return indexManager.list(); + } + + public final boolean open() throws DBException { + return true; + } + + /** + * Turns an XML string into a parsed document and caches it. + * + * @param key The key to use when caching + * @param xml The string to parse + * @return A parsed DOM document or null if failure + */ + private Document parseDocument(Key key, String xml) throws DBException { + Document doc = null; + try { + doc = DOMParser.toDocument(xml); + + // Have to move it to Xindice DOM for XMLObject AutoLinking + byte[] b = DOMCompressor.Compress(doc, symbols); + doc = new DocumentImpl(b, symbols, new NodeSource(this, key)); + + if (documentCache != null) + documentCache.putDocument(this, key, b); + } + catch (Exception e) { + throw new DBException(FaultCodes.COL_DOCUMENT_MALFORMED, "Unable to parse Document", e); + } + return doc; + } + + /* + * Lowest-level method for saving a binary entry into the database. + * Does not update non-inline metadata. + */ + private void putBinary(Key key, byte[] bytes, boolean create) throws DBException { + + if (inlineMetaService == null) { + throw new DBException(FaultCodes.COL_CANNOT_STORE, "Cannot store a binary resource in collection " + name + ": inline-metadata is not enabled"); + } + + if (!create) { + byte[] storedBytes = getBinary(key); + if (storedBytes == null) { + /* + * TODO: Do we need a COL_KEY_ALREADY_PRESENT fault so that the caller can interpret this exception? + */ + throw new DBException( + FaultCodes.COL_CANNOT_STORE, + "Error storing binary object with key '" + key + "': the 'create' flag is false and" + " the key is not in the database"); + } + } + + InlineMetaMap map = inlineMetaService.getEmptyMap(); + map.put("type", ResourceTypeReader.BINARY); + Value value = inlineMetaService.createValue(map, bytes, 0, bytes.length); + filer.writeRecord(key, value); + } + + /** + * This is the lowest-level method for storing a record into the backing store. + * It does not update non-inline metadata. + */ + private void putDocument(Key key, Document document) throws DBException { + + String localDebugHeader = debugHeader() + "putDocument: docKey=<" + key.toString() + ">: "; + + log.debug(localDebugHeader + "document=<" + TextWriter.toString(document).toString() + ">"); + + checkFiler(FaultCodes.COL_NO_FILER); + + if (document instanceof DBDocument) { + // This is a shitty shitty hack... Kill immediately + DBDocument dbDoc = (DBDocument) document; + if (dbDoc.getSource() == null) + dbDoc.setSource(new NodeSource(this, key)); + } + + /* + * The possibilities are restricted because only XML + * is handled by this method. There are only a few + * pieces of information that need to be constructed: + * 1) the xindice DOM document is needed for all XML objects, as + * it is handed to the IndexManager and the DBObserver. + * 2) the packed document, if this is a compressed XML object, + * is needed for the cache and the BTree (via the Value object). + * 3) the string-converted-to-utf-8 bytes, if this is a non-compressed + * XML object, is needed for the BTree (via the Value object). + * 4) A Value object, with a header if headers are enabled, and + * otherwise without headers, for the BTree. + */ + + byte[] packedDocument = null; + byte[] utf8Document = null; + + if (compressed) { + try { + + packedDocument = DOMCompressor.Compress(document, symbols); + log.debug(localDebugHeader + "length=" + packedDocument.length); + + // Why must it be re-created? + document = new DocumentImpl(packedDocument, symbols, new NodeSource(this, key)); + + log.debug(localDebugHeader + "packedDocument: length=" + packedDocument.length + " document=<" + TextWriter.toString(document) + ">"); + } + catch (Exception e) { + throw new DBException(FaultCodes.COL_CANNOT_STORE, localDebugHeader + "Error compressing Document '" + key + "'", e); + } + } + else { + try { + utf8Document = TextWriter.toString(document).getBytes("utf-8"); + log.debug(localDebugHeader + "utf8Document: length=" + utf8Document.length + " document=<" + new String(utf8Document, "utf-8") + ">"); + } + catch (UnsupportedEncodingException e) { + throw new DBException(FaultCodes.GEN_FATAL_ERROR, "utf-8 encoding not supported", e); + } + } + + /* + * TODO: Can this be moved into the if(compressed) block? + */ + flushSymbolTable(); + + // Temporary until insert and update are separate + Document oldDoc = getDocument(key); + if (oldDoc != null) { + indexManager.removeDocument(key, oldDoc); + } + indexManager.addDocument(key, document); + + /* + * Construct the Value object that is stored in the BTree. + */ + Value value; + if (inlineMetaService == null) { + if (compressed) { + value = new Value(packedDocument); + } + else { + value = new Value(utf8Document); + } + } + else { + InlineMetaMap map = inlineMetaService.getEmptyMap(); + map.put("type", ResourceTypeReader.XML); + if (compressed) { + value = inlineMetaService.createValue(map, packedDocument, 0, packedDocument.length); + } + else { + value = inlineMetaService.createValue(map, utf8Document, 0, utf8Document.length); + } + } + filer.writeRecord(key, value); + + // Cache Stuff + if (documentCache != null) { + if (compressed) + documentCache.putDocument(this, key, packedDocument); + else + documentCache.putDocument(this, key, document); + } + + DBObserver.getInstance().putDocument(this, key, document, oldDoc == null); + } + + private void putObject(Key key, XMLSerializable obj) throws DBException { + + String localDebugHeader = debugHeader() + "putObject: key=<" + key.toString() + ">: "; + + Document doc = new DocumentImpl(); + ProcessingInstruction pi = doc.createProcessingInstruction(CLASSNAME, obj.getClass().getName()); + doc.appendChild(pi); + Element elem = obj.streamToXML(doc); + log.debug(localDebugHeader + "elem=<" + TextWriter.toString(elem) + ">"); + doc.appendChild(elem); + putDocument(key, doc /*, create */ + ); + } + + /** + * queryCollection performs a query against the current collection + * using the specified style and query String. + * + * @param style The query style to use (ex: XPath) + * @param query The query to execute + * @param nsMap The namespace Map (if any) + * @return The resulting NodeSet + */ + public final NodeSet queryCollection(String style, String query, NamespaceMap nsMap) throws DBException { + // a collection in which you are unable to file documents will have no filer + // (for example the root collection). Rather than throwing an exception return + // a constant result (nothing) + return null == filer ? EMPTY_NODESET : getQueryEngine().query(this, style, query, nsMap, null); + } + + /** + * queryDocument performs a query against a single Document using + * the specified style, query string, and Document ID. + * + * @param style The query style to use (ex: XPath) + * @param query The query to execute + * @param nsMap The namespace Map (if any) + * @param key The Document to query + * @return The resulting NodeSet + */ + public final NodeSet queryDocument(String style, String query, NamespaceMap nsMap, Object key) throws DBException { + checkFiler(FaultCodes.QRY_STYLE_NOT_FOUND); + Key[] k = null; + if (key instanceof Key[]) + k = (Key[]) key; + else + k = new Key[] { createNewKey(key)}; + return getQueryEngine().query(this, style, query, nsMap, k); + } + + /** + * remove removes an object from the Collection based on its Key, + * regardless of it's type. + * + * @param key The Object's Key + */ + public final void remove(Object key) throws DBException { + checkFiler(FaultCodes.COL_NO_FILER); + + Key objKey = createNewKey(key); + + Document oldDoc = getDocument(objKey); + if (oldDoc != null) + indexManager.removeDocument(objKey, oldDoc); + + if (documentCache != null) + documentCache.removeDocument(this, objKey); + + if (!filer.deleteRecord(objKey)) + throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND, "Document Does Not Exist"); + + // update the meta for this collection if necessary + updateCollectionMeta(); + // remove the document meta + if (isMetaEnabled()) { + getMetaSystemCollection().dropDocumentMeta(this, objKey.toString()); + } + DBObserver.getInstance().dropDocument(this, objKey); + } + + protected final void setCanonicalName(String canonicalName) { + this.canonicalName = canonicalName; + + // Calculate The OID Template + collection_id = Math.abs(canonicalName.hashCode()); + StringBuffer sb = new StringBuffer("00000000000000000000000000000000"); + String host = Integer.toString(host_id, 16); + String collection = Integer.toString(collection_id, 16); + sb.insert(8 - host.length(), host); + sb.insert(16 - collection.length(), collection); + sb.setLength(32); + oidTemplate = sb.toString(); + } + + /** + * Reset the metadata object for this collection. + * @param meta the Metadata to use + */ + public void setCollectionMeta(MetaData meta) throws DBException { + if (!isMetaEnabled()) { + if (log.isWarnEnabled()) { + log.warn("Meta information requested but not enabled in config!"); + } + return; + } + if (null != meta) { + if (meta.getType() != MetaData.COLLECTION) + throw new DBException(FaultCodes.GEN_UNKNOWN, "Mismatch type of meta data for collection " + getCanonicalName()); + + MetaSystemCollection metacol = getMetaSystemCollection(); + metacol.setCollectionMeta(this, meta); + } + } + + protected final void setCollectionRoot(File collectionRoot) { + this.collectionRoot = collectionRoot; + if (!collectionRoot.exists()) + collectionRoot.mkdirs(); + } + + public void setConfig(Configuration config) throws XindiceException { + super.setConfig(config); + + name = config.getAttribute(NAME); + compressed = config.getBooleanAttribute(COMPRESSED, true); + + /* + * If inline metadata is desired, get an InlineMetaService object. + */ + if (config.getBooleanAttribute(INLINE_METADATA, false)) { + inlineMetaService = new InlineMetaService(); + } + + /* + * Wait to set up the local debug header until everything needed + * by debugHeader() is complete! + */ + String localDebugHeader = debugHeader() + "setConfig: "; + + if (inlineMetaService == null) { + log.debug(localDebugHeader + "inline metadata DISABLED"); + } + else { + log.debug(localDebugHeader + "inline metadata ENABLED"); + } + + if (parent != null) { + setCanonicalName(parent.getCanonicalName() + '/' + name); + log.debug(localDebugHeader + "canonical name=<" + getCanonicalName() + ">"); + setCollectionRoot(new File(parent.getCollectionRoot(), name)); + log.debug(localDebugHeader + "collection root=<" + getCollectionRoot().toString() + ">"); + } + + if (config.getBooleanAttribute(CACHE, true)) + documentCache = getDatabase().getDocumentCache(); + + // If no Filer is defined, skip Symbols and Indexes + Configuration filerConfig = config.getChild(FILER); + if (filerConfig != null) { + log.debug(localDebugHeader + "have filer config..."); + + // Symbol Table Setup + Configuration symConfig = config.getChild(SYMBOLS); + internalSymbols = (symConfig != null); + if (internalSymbols) { + log.debug(localDebugHeader + "have internal symbols <" + TextWriter.toString(symConfig.getElement()) + ">"); + try { + symbols = new SymbolTable(symConfig.getElement()); + } + catch (Exception e) { + if (log.isDebugEnabled()) { + log.debug("Error building symbol table from internal symbols", e); + } + } + } + else { + log.debug(localDebugHeader + "no internal symbols..."); + try { + symbols = getSystemCollection().loadSymbols(this); + log.debug(localDebugHeader + "loaded symbols from system collection <" + TextWriter.toString(symbols.streamToXML(new DocumentImpl())) + ">"); + } + catch (Exception e) { + if (log.isDebugEnabled()) { + log.debug("Error building symbol table from system collection...", e); + } + } + } + + String className = filerConfig.getAttribute(CLASS); + log.debug(localDebugHeader + "file class=<" + className + ">"); + try { + filer = (Filer) Class.forName(className).newInstance(); + // filer.setCollection(this); + filer.setLocation(getCollectionRoot(), getName()); + filer.setConfig(filerConfig); + if (!filer.exists()) + filer.create(); + filer.open(); + } + catch (Exception e) { + if (log.isWarnEnabled()) { + log.warn("Filer '" + className + "' not available", e); + } + } + + // Index Manager + try { + indexManager = new IndexManager(this); + Configuration idxConfig = config.getChild(INDEXES, true); + indexManager.setConfig(idxConfig); + } + catch (Exception e) { + if (log.isDebugEnabled()) { + log.debug("No message", e); + } + } + } + + super.setConfig(config); + + // observer + DBObserver.getInstance().setCollectionConfig(this, config); + } + + /** + * setDocument overwrites/updates an existing Document in a + * Xindice Collection. + * + * @param docKey The Document Key + * @param document The Document + */ + public final void setDocument(Object docKey, Document document) throws DBException { + putDocument(createNewKey(docKey), document /*, false */ + ); + // update the meta for this document + updateDocumentMeta(docKey.toString()); + } + + /** + * Set the metadata associated with a document within this collection. + * + * @param id the document name + * @param meta the metadata object to be used. + */ + public void setDocumentMeta(String id, MetaData meta) throws DBException { + if (!isMetaEnabled()) { + if (log.isWarnEnabled()) { + log.warn("Meta information requested but not enabled in config!"); + } + return; + } + Document doc = getDocument(id); + if (null == doc) + throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND, "Document " + id + " does not exist"); + + if (null != meta) { + if (meta.getType() == MetaData.UNKNOWN || meta.getType() == MetaData.COLLECTION) + throw new DBException(FaultCodes.GEN_UNKNOWN, "Mismatch type of meta data for document " + getCanonicalDocumentName(id)); + + MetaSystemCollection metacol = getMetaSystemCollection(); + metacol.setDocumentMeta(this, id, meta); + } + } + + /** + * @param string + */ + protected void setName(String string) { + name = string; + } + + /** + * setObject sets an XMLSerializable object in the Collection based on the + * provided Key. Xindice takes care of associating the implementation class + * with the XMLSerializable object. + * + * @param key The Key to use + * @param obj The Object to set + */ + public final void setObject(Object key, XMLSerializable obj) throws DBException { + putObject(createNewKey(key), obj /*, false */ + ); + } + + /** + * update the modified time of this collection when appropriate + */ + protected void updateCollectionMeta() { + // update the meta data if necessary + if (isMetaEnabled()) { + MetaSystemCollection metacol = getMetaSystemCollection(); + MetaData meta = null; + try { + meta = metacol.getCollectionMeta(this); + } + catch (DBException e) { + // something strange has happened.. can't get the + // meta data for this collection + if (log.isWarnEnabled()) + log.warn("Error fetching collection meta. " + e); + return; + } + + if (log.isInfoEnabled()) + log.info("Updating modified time for this collection's meta"); + long now = System.currentTimeMillis(); + if (null == meta) { + meta = new MetaData(MetaData.COLLECTION, getCanonicalName(), now, now); + } + else { + // this collection already has a meta. so update its modified time. + meta.setContext(0, now); + } + try { + metacol.setCollectionMeta(this, meta); + } + catch (DBException e) { + if (log.isWarnEnabled()) + log.warn("Error setting the collection meta. " + e); + return; + } + } + } + + /** + * update the modified time of this document when appropriate + */ + protected void updateDocumentMeta(String id) throws DBException { + // update the meta data if necessary + if (!isMetaEnabled()) + return; + + Document doc = getDocument(id); + if (null == doc) + throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND, "Document " + id + " does not exist"); + + MetaSystemCollection metacol = getMetaSystemCollection(); + MetaData meta = metacol.getDocumentMeta(this, id); + + String path = getCanonicalDocumentName(id); + + /* + TimeRecord rec = null; + if( null == meta || !meta.hasContext() ) + rec = getDatabase().getTime(path); + + long created = (null != rec) ? rec.getCreatedTime() : System.currentTimeMillis(); + long modified = (null != rec) ? rec.getModifiedTime() : System.currentTimeMillis(); + */ + + // this is wrong.. but it should work for now... + long created = System.currentTimeMillis(); + long modified = System.currentTimeMillis(); + + if (null == meta) { + meta = new MetaData(MetaData.DOCUMENT, path, created, modified); + } + else if (!meta.hasContext()) { + meta.setContext(created, modified); + } + else { + meta.setContext(0, modified); + } + metacol.setDocumentMeta(this, id, meta); + } } 1.13 +94 -100 xml-xindice/java/src/org/apache/xindice/core/SystemCollection.java Index: SystemCollection.java =================================================================== RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/core/SystemCollection.java,v retrieving revision 1.12 retrieving revision 1.13 diff -u -r1.12 -r1.13 --- SystemCollection.java 11 Dec 2002 00:22:56 -0000 1.12 +++ SystemCollection.java 14 Jul 2003 19:07:15 -0000 1.13 @@ -59,15 +59,13 @@ * $Id$ */ +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import org.apache.xindice.util.Configuration; import org.apache.xindice.xml.SymbolTable; import org.apache.xindice.xml.SymbolTableSymbols; import org.apache.xindice.xml.dom.DOMParser; - -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; - -import org.w3c.dom.*; +import org.w3c.dom.Document; /** * SystemCollection represents the System Collection. Beyond @@ -77,98 +75,94 @@ public final class SystemCollection extends Collection { - public static final String SYSCOL = "system"; - - public static final String SYMBOLS = "SysSymbols"; - public static final String OBJECTS = "SysObjects"; - public static final String CONFIGS = "SysConfig"; - public static final String USERS = "SysUsers"; - public static final String GROUPS = "SysGroups"; - public static final String ACCESS = "SysAccess"; - - private static Log log = LogFactory.getLog("org.apache.xindice.core"); - - public SystemCollection(Database db) { - super(db); - } - - void init() throws DBException { - // Bootstrap the System Collection - - String SysCol = - "<collection name=\""+SYSCOL+"\">" - - // System Collections - + " <collections>" - - // Symbol Tables Collection - + " <collection name=\""+SYMBOLS+"\" compressed=\"true\">" - + " <filer class=\"org.apache.xindice.core.filer.BTreeFiler\" />" - // Textual Representation of Hard-coded Symbol Table - + SymbolTableSymbols.getDefinition() - + " </collection>" - - // System Configuration Collection - + " <collection name=\""+CONFIGS+"\" compressed=\"false\">" - + " <filer class=\"org.apache.xindice.core.filer.BTreeFiler\" />" - + " </collection>" - - + " </collections>" - + "</collection>"; - - try { - Document sysDoc = DOMParser.toDocument(SysCol); - Configuration sysCfg = new Configuration(sysDoc, false); - setConfig(sysCfg); - } - catch ( Exception e ) { - if (log.isFatalEnabled()) { - log.fatal("FATAL ERROR: Generating System Collection '"+SYSCOL+"'", e); - } - System.exit(1); - } - } - - private String getSymbolTableName(Collection col) { - String name = col.getCanonicalName(); - int idx = name.indexOf('/', 1); - name = name.substring(idx+1); - return name.replace('/', '_'); - } - - /** - * loadSymbols retrieves the SymbolTable for the specified Collection. - * - * @param collection The Collection whose SymbolTable is required - * @return The requested SymbolTable - */ - public SymbolTable loadSymbols(Collection collection) throws DBException { - String name = getSymbolTableName(collection); - - Collection symCol = getCollection(SYMBOLS); - - SymbolTable symbols = (SymbolTable)symCol.getObject(name); - if ( symbols == null ) { - symbols = new SymbolTable(); - saveSymbols(collection, symbols); - } - return symbols; - } - - /** - * saveSymbols save the SymbolTable for the specified Collection. - * - * @param collection The Collection that owns the SymbolTable - * @param symbols The SymbolTable - */ - public void saveSymbols(Collection collection, SymbolTable symbols) throws DBException { - String name = getSymbolTableName(collection); - - Collection symCol = getCollection(SYMBOLS); - - if ( symbols != null ) { - symCol.setObject(name, symbols); - symbols.setDirty(false); - } - } + public static final String SYSCOL = "system"; + public static final String SYMBOLS = "SysSymbols"; + public static final String OBJECTS = "SysObjects"; + public static final String CONFIGS = "SysConfig"; + public static final String USERS = "SysUsers"; + public static final String GROUPS = "SysGroups"; + public static final String ACCESS = "SysAccess"; + private static Log log = LogFactory.getLog("org.apache.xindice.core"); + + /** + * @param db + */ + public SystemCollection(Database db) { + super(db); + } + + void init() throws DBException { + // Bootstrap the System Collection + + String SysCol = "<collection name=\"" + SYSCOL + "\">" + // System Collections + +" <collections>" + // Symbol Tables Collection + +" <collection name=\"" + SYMBOLS + "\" compressed=\"true\">" + " <filer class=\"org.apache.xindice.core.filer.BTreeFiler\" />" + // Textual Representation of Hard-coded Symbol Table + +SymbolTableSymbols.getDefinition() + " </collection>" + // System Configuration Collection + +" <collection name=\"" + + CONFIGS + + "\" compressed=\"false\">" + + " <filer class=\"org.apache.xindice.core.filer.BTreeFiler\" />" + + " </collection>" + + " </collections>" + + "</collection>"; + + try { + Document sysDoc = DOMParser.toDocument(SysCol); + Configuration sysCfg = new Configuration(sysDoc, false); + setConfig(sysCfg); + } + catch (Exception e) { + if (log.isFatalEnabled()) { + log.fatal("FATAL ERROR: Generating System Collection '" + SYSCOL + "'", e); + } + System.exit(1); + } + } + + private String getSymbolTableName(Collection col) { + String name = col.getCanonicalName(); + int idx = name.indexOf('/', 1); + name = name.substring(idx + 1); + return name.replace('/', '_'); + } + + /** + * loadSymbols retrieves the SymbolTable for the specified Collection. + * + * @param collection The Collection whose SymbolTable is required + * @return The requested SymbolTable + */ + public SymbolTable loadSymbols(Collection collection) throws DBException { + String name = getSymbolTableName(collection); + + Collection symCol = getCollection(SYMBOLS); + + SymbolTable symbols = (SymbolTable) symCol.getObject(name); + if (symbols == null) { + symbols = new SymbolTable(); + saveSymbols(collection, symbols); + } + return symbols; + } + + /** + * saveSymbols save the SymbolTable for the specified Collection. + * + * @param collection The Collection that owns the SymbolTable + * @param symbols The SymbolTable + */ + public void saveSymbols(Collection collection, SymbolTable symbols) throws DBException { + String name = getSymbolTableName(collection); + + Collection symCol = getCollection(SYMBOLS); + + if (symbols != null) { + symCol.setObject(name, symbols); + symbols.setDirty(false); + } + } } 1.11 +208 -193 xml-xindice/java/src/org/apache/xindice/core/CollectionManager.java Index: CollectionManager.java =================================================================== RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/core/CollectionManager.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- CollectionManager.java 26 Nov 2002 02:17:18 -0000 1.10 +++ CollectionManager.java 14 Jul 2003 19:07:15 -0000 1.11 @@ -77,196 +77,211 @@ */ public class CollectionManager implements Configurable, Disposable { - private static final String COLLECTIONS = "collections"; - private static final String COLLECTION = "collection"; - private static final String NAME = "name"; - - private static Log log = LogFactory.getLog("org.apache.xindice.core"); - - private static final String[] EmptyStrings = new String[0]; - - protected Map collections = new HashMap(); // Collection - - protected Configuration config = null; - - protected CollectionManager() { - } - - public void setConfig(Configuration config) throws XindiceException { - this.config = config; - - Configuration colConfig = config.getChild(COLLECTIONS); - if ( colConfig != null ) { - colConfig.processChildren(COLLECTION, - new ConfigurationCallback() { - public void process(Configuration cfg) throws XindiceException { - // check for an existing Collection by name and, if found, skip creating a new Collection - // else, create a new child Collection, configure it an add it - // if the Collection already exists in our collections list, - // creating a new one will cause the old one to be discarded - // while holding open file handles, etc. - Collection col = (Collection)collections.get(cfg.getAttribute(NAME)); - if(col == null) - { - col = new Collection((Collection)CollectionManager.this); - col.setConfig(cfg); - collections.put(col.getName(), col); - } - // else, assume col is configured elsewhere... - // I'm not sure this should be happening, but it does - // it is not safe to call col.setConfig again since it does a bunch - // of stuff (like creating a new Filer and overwriting the existing one, etc.) - } - }); - } - } - - public Configuration getConfig() { - return config; - } - - /** - * getCollection retrieves a Collection by name. - * - * @param path The Collection path - * @return The Collection (or null) - */ - public Collection getCollection(String path) throws DBException { - if ( path.indexOf("/") != -1 ) { - CollectionManager cm = this; - StringTokenizer st = new StringTokenizer(path, "/"); - while ( cm != null && st.hasMoreTokens()) { - path = st.nextToken(); - cm = (CollectionManager)cm.collections.get(path); - } - return (Collection)cm; - } - else - return (Collection)collections.get(path); - } - - /** - * listCollections retrieves a list of Collections as an array of - * Strings. - * - * @return The Collection list - */ - public final String[] listCollections() throws DBException { - return (String[]) collections.keySet().toArray(EmptyStrings); - } - - /** - * Returns number of child collections - * - * @return number of collections - */ - public final long countCollections() throws DBException { - return (long) collections.size(); - } - - /** - * dropCollection physically removes the specified Collection and any - * associated system resources that the Collection uses. - * - * @param collection The Collection to drop - * @return Whether or not the Collection was dropped - */ - public boolean dropCollection(Collection collection) throws DBException { - if ( collection == null ) - throw new DBException(FaultCodes.COL_COLLECTION_NOT_FOUND, "Collection Value Null"); - - Collection cm = collection.getParentCollection(); - - if ( cm == null ) - throw new DBException(FaultCodes.DBE_CANNOT_DROP, "You Cannot Drop The Database"); - - if ( cm != this ) - return cm.dropCollection(collection); - else { - final String name = collection.getName(); - boolean dropped = collection.drop(); - if ( dropped ) { - collections.remove(name); - Configuration colConfig = config.getChild(COLLECTIONS); - colConfig.processChildren(COLLECTION, - new ConfigurationCallback() { - public void process(Configuration cfg) { - try { - if ( cfg.getAttribute(NAME).equals(name) ) - cfg.delete(); - } - catch ( Exception e ) { - if (log.isDebugEnabled()) { - log.debug("No message", e); - } - } - } - }); - } - return dropped; - } - } - - /** - * createCollection creates a new Collection object and any associated - * system resources that the Collection will need. - * - * @param path The relative path of the Collection - * @param cfg The Collection's configuration - * @return The newly created Collection - */ - public Collection createCollection(String path, Configuration cfg) - throws DBException { - if ( path.indexOf("/") != -1 ) { - CollectionManager cm = this; - StringTokenizer st = new StringTokenizer(path, "/"); - while ( cm != null && st.hasMoreTokens()) { - path = st.nextToken().trim(); - if ( path.length() == 0 ) - continue; - if ( st.hasMoreTokens() ) - cm = (CollectionManager)cm.collections.get(path); - else - return cm.createCollection(path, cfg); - } - throw new DBException(FaultCodes.COL_COLLECTION_NOT_FOUND, "Parent Collection '"+path+"' doesn't exist"); - } - - Collection collection = null; - - if ( CollectionManager.this instanceof Database ) - collection = new Collection((Database)CollectionManager.this); - else - collection = new Collection((Collection)CollectionManager.this); - - try { - // Do a name check to see if all is well - String n = cfg.getAttribute(NAME); - if ( n == null || n.trim().equals("") ) - throw new DBException(FaultCodes.COL_CANNOT_CREATE, "No name specified"); - - if ( getCollection(n) != null ) - throw new DBException(FaultCodes.COL_DUPLICATE_COLLECTION, "Duplicate Collection '"+n+"'"); - - Configuration colConfig = this.config.getChild(COLLECTIONS, true); - colConfig.add(cfg); - - collection.setConfig(cfg); - collection.create(); - collections.put(n, collection); - if (log.isInfoEnabled()) { - log.info("Created a new collection named '"+n+"'"); - } - } - catch ( DBException e ) { - throw e; - } - catch ( Exception e ) { - throw new DBException(FaultCodes.COL_CANNOT_CREATE, "Error Creating Collection '"+path+"'", e); - } - return collection; - } - - public void dispose() { - } + private static final String COLLECTION = "collection"; + private static final String COLLECTIONS = "collections"; + private static final String[] EmptyStrings = new String[0]; + private static Log log = LogFactory.getLog("org.apache.xindice.core"); + private static final String NAME = "name"; + private Map collections = new HashMap(); // Collection + private Configuration config = null; + + protected CollectionManager() {} + + /** + * + * @param collection + */ + protected void addCollection(Collection collection){ + + this.collections.put(collection.getName(), collection); + } + + /** + * Returns number of child collections + * + * @return number of collections + */ + public final long countCollections() throws DBException { + return (long) collections.size(); + } + + /** + * createCollection creates a new Collection object and any associated + * system resources that the Collection will need. + * + * @param path The relative path of the Collection + * @param cfg The Collection's configuration + * @return The newly created Collection + */ + public Collection createCollection(String path, Configuration cfg) throws DBException { + if (path.indexOf("/") != -1) { + CollectionManager cm = this; + StringTokenizer st = new StringTokenizer(path, "/"); + while (cm != null && st.hasMoreTokens()) { + path = st.nextToken().trim(); + if (path.length() == 0) + continue; + if (st.hasMoreTokens()) + cm = (CollectionManager) cm.collections.get(path); + else + return cm.createCollection(path, cfg); + } + throw new DBException(FaultCodes.COL_COLLECTION_NOT_FOUND, "Parent Collection '" + path + "' doesn't exist"); + } + + Collection collection = null; + + if (CollectionManager.this instanceof Database) + collection = new Collection((Database) CollectionManager.this); + else + collection = new Collection((Collection) CollectionManager.this); + + try { + // Do a name check to see if all is well + String n = cfg.getAttribute(NAME); + if (n == null || n.trim().equals("")) + throw new DBException(FaultCodes.COL_CANNOT_CREATE, "No name specified"); + + if (getCollection(n) != null) + throw new DBException(FaultCodes.COL_DUPLICATE_COLLECTION, "Duplicate Collection '" + n + "'"); + + Configuration colConfig = this.config.getChild(COLLECTIONS, true); + colConfig.add(cfg); + + collection.setConfig(cfg); + collection.create(); + collections.put(n, collection); + if (log.isInfoEnabled()) { + log.info("Created a new collection named '" + n + "'"); + } + } + catch (DBException e) { + throw e; + } + catch (Exception e) { + throw new DBException(FaultCodes.COL_CANNOT_CREATE, "Error Creating Collection '" + path + "'", e); + } + return collection; + } + + /** + * @see org.apache.xindice.util.Disposable#dispose() + */ + public void dispose() {} + + /** + * dropCollection physically removes the specified Collection and any + * associated system resources that the Collection uses. + * + * @param collection The Collection to drop + * @return Whether or not the Collection was dropped + */ + public boolean dropCollection(Collection collection) throws DBException { + if (collection == null) + throw new DBException(FaultCodes.COL_COLLECTION_NOT_FOUND, "Collection Value Null"); + + Collection cm = collection.getParentCollection(); + + if (cm == null) + throw new DBException(FaultCodes.DBE_CANNOT_DROP, "You Cannot Drop The Database"); + + if (cm != this) + return cm.dropCollection(collection); + else { + final String name = collection.getName(); + boolean dropped = collection.drop(); + if (dropped) { + collections.remove(name); + Configuration colConfig = config.getChild(COLLECTIONS); + colConfig.processChildren(COLLECTION, new ConfigurationCallback() { + public void process(Configuration cfg) { + try { + if (cfg.getAttribute(NAME).equals(name)) + cfg.delete(); + } + catch (Exception e) { + if (log.isDebugEnabled()) { + log.debug("No message", e); + } + } + } + }); + } + return dropped; + } + } + + /** + * getCollection retrieves a Collection by name. + * + * @param path The Collection path + * @return The Collection (or null) + */ + public Collection getCollection(String path) throws DBException { + if (path.indexOf("/") != -1) { + CollectionManager cm = this; + StringTokenizer st = new StringTokenizer(path, "/"); + while (cm != null && st.hasMoreTokens()) { + path = st.nextToken(); + cm = (CollectionManager) cm.collections.get(path); + } + return (Collection) cm; + } + else + return (Collection) collections.get(path); + } + + /** + * @return + */ + protected Map getCollections() { + return this.collections; + } + + /** + * @see org.apache.xindice.util.Configurable#getConfig() + */ + public Configuration getConfig() { + return config; + } + + /** + * listCollections retrieves a list of Collections as an array of + * Strings. + * + * @return The Collection list + */ + public final String[] listCollections() throws DBException { + return (String[]) collections.keySet().toArray(EmptyStrings); + } + + /** + * @see org.apache.xindice.util.Configurable#setConfig(org.apache.xindice.util.Configuration) + */ + public void setConfig(Configuration config) throws XindiceException { + this.config = config; + + Configuration colConfig = config.getChild(COLLECTIONS); + if (colConfig != null) { + colConfig.processChildren(COLLECTION, new ConfigurationCallback() { + public void process(Configuration cfg) throws XindiceException { + // check for an existing Collection by name and, if found, skip creating a new Collection + // else, create a new child Collection, configure it an add it + // if the Collection already exists in our collections list, + // creating a new one will cause the old one to be discarded + // while holding open file handles, etc. + Collection col = (Collection) collections.get(cfg.getAttribute(NAME)); + if (col == null) { + col = new Collection((Collection) CollectionManager.this); + col.setConfig(cfg); + collections.put(col.getName(), col); + } + // else, assume col is configured elsewhere... + // I'm not sure this should be happening, but it does + // it is not safe to call col.setConfig again since it does a bunch + // of stuff (like creating a new Filer and overwriting the existing one, etc.) + } + }); + } + } } 1.11 +177 -179 xml-xindice/java/src/org/apache/xindice/client/xmldb/embed/DatabaseImpl.java Index: DatabaseImpl.java =================================================================== RCS file: /home/cvs/xml-xindice/java/src/org/apache/xindice/client/xmldb/embed/DatabaseImpl.java,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- DatabaseImpl.java 10 Jul 2003 21:42:48 -0000 1.10 +++ DatabaseImpl.java 14 Jul 2003 19:07:16 -0000 1.11 @@ -56,7 +56,6 @@ * * $Id$ */ - package org.apache.xindice.client.xmldb.embed; import org.apache.xindice.client.xmldb.CommonConfigurable; @@ -88,184 +87,183 @@ */ public class DatabaseImpl extends CommonConfigurable implements org.xmldb.api.base.Database { - private static Log log = LogFactory.getLog("org.apache.xindice.client.embed"); - - /* prefix used to denote XML:DB URI's that should use this driver */ - static String DRIVER_NAME = "xindice-embed"; + private static Log log = LogFactory.getLog("org.apache.xindice.client.embed"); - /* XML:DB conformance level of this driver */ - private String CONFORMANCE_LEVEL = "0"; + /** prefix used to denote XML:DB URI's that should use this driver */ + public static final String DRIVER_NAME = "xindice-embed"; - protected Database db; - - /** - * Creates new <code>DatabaseImpl</code> instance. The configuration is - * loaded from the file defined in the PROP_XINDICE_CONFIGURATION system - * variable. - * - * This is only a temporarly solution since the question of a new init - * method is raised in the xmldb:api group. Another solution could be to - * use the Configurable interface and only create the database when the - * getCollection method is called. - */ - public DatabaseImpl() throws FileNotFoundException, XindiceException { - - Configuration config = loadConfiguration(); - this.db = Database.getDatabase(config); - - if (null == this.db) { - log.fatal("Unable to configure database"); - - throw new XindiceException("Unable to configure database"); - } - else if (log.isInfoEnabled()) { - log.info("Database name: '" + this.db.getName() + "'"); - } - } - - protected Configuration loadConfiguration() throws FileNotFoundException, XindiceException, ReadOnlyException { - Configuration config; - String configFile = System.getProperty(Xindice.PROP_XINDICE_CONFIGURATION); - if (configFile != null && !configFile.equals("")) { - if (log.isInfoEnabled()) { - log.info("Specified configuration file: '" + configFile + "'"); - } - FileInputStream configXMLFile = new FileInputStream(new File(configFile)); - - config = new Configuration(DOMParser.toDocument(configXMLFile), false); - } - else { - if (log.isInfoEnabled()) { - log.info("No configuration file specified, going with the default configuration"); - } - config = new Configuration(DOMParser.toDocument(Xindice.DEFAULT_CONFIGURATION), false); - } - - config = config.getChild("root-collection", false); - return config; - } - - /** - * Determines whether this <code>Database</code> implementation can handle - * the URI. It should return true if the Database instance knows how to - * handle the URI and false otherwise. - * - * @param uri the URI to check for. - * @return true if the URI can be handled, false otherwise. - * @exception XMLDBException with expected error codes.<br /> - * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor - * specific errors that occur.<br /> - * <code>ErrroCodes.INVALID_URI</code> If the URI is not in a valid format. <br /> - */ - public boolean acceptsURI(String uri) throws XMLDBException { - - return ((uri != null) && uri.startsWith(getName() + "://")); - } - - /** - * Retrieves a <code>Collection</code> instance based on the URI provided - * in the <code>uri</code> parameter. The format of the URI is defined in the - * documentation for DatabaseManager.getCollection().<p/> - * - * Authentication is handled via username and password however it is not - * required that the database support authentication. Databases that do not - * support authentication MUST ignore the - * <code>username</code> and <code>password</code> if those provided are not - * null. - * - * @param uri the URI to use to locate the collection. - * @param password The password to use for authentication to the database or - * null if the database does not support authentication. - * @return A <code>Collection</code> instance for the requested collection or - * null if the collection could not be found. - * @return The <code>Collection</code> instance - * @exception XMLDBException with expected error codes.<br /> - * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor - * specific errors that occur.<br /> - * <code>ErrroCodes.INVALID_URI</code> If the URI is not in a valid format. <br /> - * <code>ErrroCodes.PERMISSION_DENIED</code> If the <code>username</code> - * and <code>password</code> were not accepted by the database. - */ - public Collection getCollection(String uri, String userName, String password) throws XMLDBException { - /* TODO: introduce authentication some day */ - - if (!acceptsURI(uri)) { - throw new XMLDBException(ErrorCodes.INVALID_URI, "Invalid URL: " + uri); - } - - /* Chop off driver prefix, and '://' */ - uri = uri.substring(getName().length() + 3); - - /* Extract host name & port, if present */ - int firstSlash = uri.indexOf('/'); - if (firstSlash == -1) { - throw new XMLDBException(ErrorCodes.INVALID_URI); - } - - String collPath = uri.substring(firstSlash); - - // The path must start with a / - if (collPath.startsWith("/")) { - // find the database name. We just skip the first slash - int colIndex = collPath.indexOf('/', 1); - - // We assume there's no collection specified - String dbName = collPath.substring(1); - String colName = "/"; - - // if colIndex isn't -1 then we need to pick out the db and collection - if (colIndex != -1) { - dbName = collPath.substring(1, colIndex); - - // The rest of the name locates the collection - colName = collPath.substring(colIndex); - } - - if (colName.equals("")) { - colName = "/"; - } - - try { - return new CollectionImpl(db, colName); - } - catch (XMLDBException e) { - if (e.errorCode == ErrorCodes.NO_SUCH_COLLECTION) { - // per getCollection contract, return null if not found - return null; - } - throw e; - } - } - else { - throw new XMLDBException(ErrorCodes.INVALID_URI, "Collection name must begin with a '/'"); - } - } - - /** - * Returns the prefix used in XML:DB to denote URI's that this driver can - * handle. - * - * @return the prefix driver name - * @exception XMLDBException with expected error codes.<br /> - * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor - * specific errors that occur.<br /> - */ - public String getName() throws XMLDBException { - return DRIVER_NAME; - } - - /** - * Returns the XML:DB API Conformance level for the implementation. This can - * be used by client programs to determine what functionality is available to - * them. - * - * @return the XML:DB API conformance level for this implementation. - * @exception XMLDBException with expected error codes.<br /> - * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor - * specific errors that occur.<br /> - */ - public String getConformanceLevel() throws XMLDBException { - return CONFORMANCE_LEVEL; - } + /** XML:DB conformance level of this driver */ + private String CONFORMANCE_LEVEL = "0"; + private Database database; + + /** + * Creates new <code>DatabaseImpl</code> instance. The configuration is + * loaded from the file defined in the PROP_XINDICE_CONFIGURATION system + * variable. + * + * This is only a temporarly solution since the question of a new init + * method is raised in the xmldb:api group. Another solution could be to + * use the Configurable interface and only create the database when the + * getCollection method is called. + */ + public DatabaseImpl() throws FileNotFoundException, XindiceException { + + Configuration config = loadConfiguration(); + this.database = Database.getDatabase(config); + + if (null == this.database) { + log.fatal("Unable to configure database"); + + throw new XindiceException("Unable to configure database"); + } + else if (log.isInfoEnabled()) { + log.info("Database name: '" + this.database.getName() + "'"); + } + } + + protected Configuration loadConfiguration() throws FileNotFoundException, XindiceException, ReadOnlyException { + Configuration config; + String configFile = System.getProperty(Xindice.PROP_XINDICE_CONFIGURATION); + if (configFile != null && !configFile.equals("")) { + if (log.isInfoEnabled()) { + log.info("Specified configuration file: '" + configFile + "'"); + } + FileInputStream configXMLFile = new FileInputStream(new File(configFile)); + + config = new Configuration(DOMParser.toDocument(configXMLFile), false); + } + else { + if (log.isInfoEnabled()) { + log.info("No configuration file specified, going with the default configuration"); + } + config = new Configuration(DOMParser.toDocument(Xindice.DEFAULT_CONFIGURATION), false); + } + + config = config.getChild("root-collection", false); + return config; + } + + /** + * Determines whether this <code>Database</code> implementation can handle + * the URI. It should return true if the Database instance knows how to + * handle the URI and false otherwise. + * + * @param uri the URI to check for. + * @return true if the URI can be handled, false otherwise. + * @exception XMLDBException with expected error codes.<br /> + * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor + * specific errors that occur.<br /> + * <code>ErrroCodes.INVALID_URI</code> If the URI is not in a valid format. <br /> + */ + public boolean acceptsURI(String uri) throws XMLDBException { + + return ((uri != null) && uri.startsWith(getName() + "://")); + } + + /** + * Retrieves a <code>Collection</code> instance based on the URI provided + * in the <code>uri</code> parameter. The format of the URI is defined in the + * documentation for DatabaseManager.getCollection().<p/> + * + * Authentication is handled via username and password however it is not + * required that the database support authentication. Databases that do not + * support authentication MUST ignore the + * <code>username</code> and <code>password</code> if those provided are not + * null. + * + * @param uri the URI to use to locate the collection. + * @param password The password to use for authentication to the database or + * null if the database does not support authentication. + * @return A <code>Collection</code> instance for the requested collection or + * null if the collection could not be found. + * @return The <code>Collection</code> instance + * @exception XMLDBException with expected error codes.<br /> + * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor + * specific errors that occur.<br /> + * <code>ErrroCodes.INVALID_URI</code> If the URI is not in a valid format. <br /> + * <code>ErrroCodes.PERMISSION_DENIED</code> If the <code>username</code> + * and <code>password</code> were not accepted by the database. + */ + public Collection getCollection(String uri, String userName, String password) throws XMLDBException { + /* TODO: introduce authentication some day */ + + if (!acceptsURI(uri)) { + throw new XMLDBException(ErrorCodes.INVALID_URI, "Invalid URL: " + uri); + } + + /* Chop off driver prefix, and '://' */ + uri = uri.substring(getName().length() + 3); + + /* Extract host name & port, if present */ + int firstSlash = uri.indexOf('/'); + if (firstSlash == -1) { + throw new XMLDBException(ErrorCodes.INVALID_URI); + } + + String collPath = uri.substring(firstSlash); + + // The path must start with a / + if (collPath.startsWith("/")) { + // find the database name. We just skip the first slash + int colIndex = collPath.indexOf('/', 1); + + // We assume there's no collection specified + String dbName = collPath.substring(1); + String colName = "/"; + + // if colIndex isn't -1 then we need to pick out the db and collection + if (colIndex != -1) { + dbName = collPath.substring(1, colIndex); + + // The rest of the name locates the collection + colName = collPath.substring(colIndex); + } + + if (colName.equals("")) { + colName = "/"; + } + + try { + return new CollectionImpl(database, colName); + } + catch (XMLDBException e) { + if (e.errorCode == ErrorCodes.NO_SUCH_COLLECTION) { + // per getCollection contract, return null if not found + return null; + } + throw e; + } + } + else { + throw new XMLDBException(ErrorCodes.INVALID_URI, "Collection name must begin with a '/'"); + } + } + + /** + * Returns the prefix used in XML:DB to denote URI's that this driver can + * handle. + * + * @return the prefix driver name + * @exception XMLDBException with expected error codes.<br /> + * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor + * specific errors that occur.<br /> + */ + public String getName() throws XMLDBException { + return DRIVER_NAME; + } + + /** + * Returns the XML:DB API Conformance level for the implementation. This can + * be used by client programs to determine what functionality is available to + * them. + * + * @return the XML:DB API conformance level for this implementation. + * @exception XMLDBException with expected error codes.<br /> + * <code>ErrorCodes.VENDOR_ERROR</code> for any vendor + * specific errors that occur.<br /> + */ + public String getConformanceLevel() throws XMLDBException { + return CONFORMANCE_LEVEL; + } }