Author: vgritsenko
Date: Mon Nov 12 10:06:00 2007
New Revision: 594237
URL: http://svn.apache.org/viewvc?rev=594237&view=rev
Log:
rearranging methods - use logical groupings
Modified:
xml/xindice/trunk/java/src/org/apache/xindice/core/Collection.java
Modified: xml/xindice/trunk/java/src/org/apache/xindice/core/Collection.java
URL: http://svn.apache.org/viewvc/xml/xindice/trunk/java/src/org/apache/xindice/core/Collection.java?rev=594237&r1=594236&r2=594237&view=diff
==============================================================================
--- xml/xindice/trunk/java/src/org/apache/xindice/core/Collection.java (original)
+++ xml/xindice/trunk/java/src/org/apache/xindice/core/Collection.java Mon Nov 12 10:06:00 2007
@@ -324,6 +324,49 @@
}
}
+ /**
+ * createNewKey allocates a new key to be used as a key in the
+ * collection. Passed in <code>key</code> parameter string value
+ * used for the key. If passed key parameter is null, new OID is generated.
+ *
+ * @param key The Key hint, can be null
+ * @return The newly generated Key
+ */
+ protected final Key createNewKey(Object key) {
+ if (key == null) {
+ return createNewOID();
+ } else if (key instanceof Key) {
+ return (Key) key;
+ } else {
+ return new Key(key.toString());
+ }
+ }
+
+ /**
+ * Turns an XML string into a parsed document retrieved
+ * from the uncompressed collection.
+ *
+ * @param key The key to use when caching
+ * @param xml The string to parse
+ * @return A parsed DOM document or null if failure
+ * @throws DBException if operation failed
+ */
+ private Document parseDocument(Key key, String xml) throws DBException {
+ try {
+ Document doc = DOMParser.toDocument(xml);
+ ((DBDocument) doc).setSource(new NodeSource(this, key));
+
+ // Have to compress to update collection's SymbolTable,
+ // which is used even for uncompressed collections
+ DOMCompressor.compress(doc, symbols);
+
+ return doc;
+ } catch (Exception e) {
+ throw new DBException(FaultCodes.COL_DOCUMENT_MALFORMED,
+ "Unable to parse document '" + key + "' in '" + getCanonicalName() + "'", e);
+ }
+ }
+
// -- Database Object Methods -------------------------------------------
@@ -664,7 +707,42 @@
}
- // ----------------------------------------------------------------------
+ // -- Core Collection API Public Methods: Index Management --------------
+
+ /**
+ * return the IndexManager being used by this Collection.
+ *
+ * @return The IndexManager
+ * @throws DBException if operation failed
+ */
+ public final IndexManager getIndexManager() throws DBException {
+ checkFiler(FaultCodes.COL_NO_INDEXMANAGER);
+ return indexManager;
+ }
+
+ /**
+ * getIndexer retrieves an Indexer by name.
+ *
+ * @param name The Indexer name
+ * @return The Indexer (or null)
+ * @throws DBException if operation failed
+ */
+ 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
+ * @throws DBException if operation failed
+ */
+ public final String[] listIndexers() throws DBException {
+ checkFiler(FaultCodes.COL_NO_INDEXMANAGER);
+ return indexManager.list();
+ }
/**
* createIndexer creates a new Indexer object and any associated
@@ -682,23 +760,29 @@
}
/**
- * createNewKey allocates a new key to be used as a key in the
- * collection. Passed in <code>key</code> parameter string value
- * used for the key. If passed key parameter is null, new OID is generated.
+ * dropIndexer physically removes the specified Indexer and any
+ * associated system resources that the Indexer uses.
*
- * @param key The Key hint, can be null
- * @return The newly generated Key
+ * @param index The Indexer to drop
+ * @return Whether or not the Indexer was dropped
+ * @throws DBException if operation failed
*/
- protected final Key createNewKey(Object key) {
- if (key == null) {
- return createNewOID();
- } else if (key instanceof Key) {
- return (Key) key;
- } else {
- return new Key(key.toString());
+ 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 is null");
}
+
+ boolean success = indexManager.drop(index.getName());
+ getDatabase().flushConfig();
+ return success;
}
+
+ // -- Core Collection API Public Methods: Data Management ---------------
+
/**
* createNewOID allocates a new Object ID to be used as a Key in the
* Collection.
@@ -722,47 +806,130 @@
}
/**
- * dropIndexer physically removes the specified Indexer and any
- * associated system resources that the Indexer uses.
+ * Retrieve a database entry by key.
*
- * @param index The Indexer to drop
- * @return Whether or not the Indexer was dropped
- * @throws DBException if operation failed
+ * If no matching entry is found, null is returned, otherwise this
+ * method returns Entry that identifies resource type and holds its
+ * value and metadata.
+ *
+ * @param docKey identifying the desired database entry
+ * @return Entry containing the database entry and its metadata, or null
+ * if no matching entry is found
+ * @throws DBException in case of backing store error,
+ * and in case of header corruption
*/
- public final boolean dropIndexer(Indexer index) throws DBException {
- checkFiler(FaultCodes.COL_NO_INDEXMANAGER);
+ public final Entry getEntry(Object docKey) throws DBException {
- if (index == null) {
- throw new DBException(FaultCodes.IDX_INDEX_NOT_FOUND,
- "Index value is null");
+ // 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;
}
- boolean success = indexManager.drop(index.getName());
- getDatabase().flushConfig();
- return success;
+ String localDebugHeader = null;
+ if (log.isTraceEnabled()) {
+ localDebugHeader = debugHeader() + "getEntry: docKey=<" + docKey + ">: ";
+ log.trace(localDebugHeader);
+ }
+
+ checkFiler(FaultCodes.COL_NO_FILER);
+
+ Key key = getIdentityKey(createNewKey(docKey));
+ synchronized (key) {
+
+ /*
+ * 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) {
+ Entry entry = documentCache.getEntry(this, key);
+ if (entry != null) {
+ if (log.isTraceEnabled()) {
+ log.trace(localDebugHeader + "Returning cached: " + entry.getValue());
+ }
+
+ return entry;
+ }
+ }
+
+ Record record = filer.readRecord(key);
+ if (record == null) {
+ return null;
+ }
+
+ Value value;
+ InlineMetaMap metaMap = null;
+ if (inlineMetaService == null) {
+ value = record.getValue();
+
+ if (log.isTraceEnabled()) {
+ log.trace(localDebugHeader + "Type is not available, Length=" + value.getLength());
+ }
+ } else {
+ InlineMetaService.DatabaseEntry databaseEntry = inlineMetaService.readDatabaseEntry(record.getValue());
+ metaMap = databaseEntry.map;
+ value = databaseEntry.value;
+
+ if (log.isTraceEnabled()) {
+ log.trace(localDebugHeader + "Type=" + metaMap.get("type") + ", Length=" + value.getLength());
+ }
+ }
+
+ Map entryMeta = Entry.createMetaMap(record);
+ if (inlineMetaService == null || metaMap.get("type").equals(ResourceTypeReader.XML)) {
+ Document document;
+ if (compressed) {
+ document = new DocumentImpl(value.getData(), symbols, new NodeSource(this, key));
+ flushSymbolTable();
+ if (log.isTraceEnabled()) {
+ log.trace(localDebugHeader +
+ "Compressed XML document=<" + TextWriter.toString(document) + ">");
+ }
+
+ if (documentCache != null) {
+ documentCache.putDocumentEntry(this, key, value.getData(), entryMeta);
+ }
+ } else {
+ String documentChars = value.toString();
+ if (log.isTraceEnabled()) {
+ log.trace(localDebugHeader + "Pre parseDocument(): value=<" + documentChars + ">");
+ }
+
+ // FIXME There should be no reason here to re-compress the document & flush symbols table?
+ document = parseDocument(key, documentChars);
+ flushSymbolTable();
+
+ if (documentCache != null) {
+ documentCache.putDocumentEntry(this, key, documentChars, entryMeta);
+ }
+ }
+
+ DBObserver.getInstance().loadDocument(this, record, document);
+ return new Entry(key, document, entryMeta);
+ } else {
+ if (log.isTraceEnabled()) {
+ log.trace(localDebugHeader + "Binary document");
+ }
+
+ return new Entry(key, value.getData(), entryMeta);
+ }
+ }
}
/**
- * Retrieve a binary database entry by key.
- * This low-level method will not update non-inline metadata.
+ * getDocument retrieves a Document by Key.
*
- * @param key 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
+ * @param key The Document Key
+ * @return The Document
+ * @throws DBException if operation failed
*/
- public final byte[] getBinary(Object key) throws DBException {
- if (log.isTraceEnabled()) {
- log.trace(debugHeader() + "Get binary: " + key);
- }
-
- if (inlineMetaService == null) {
- throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND,
- "Collection '" + getCanonicalName() +
- "' has no binary resources (inline metadata is not enabled)");
+ public final Document getDocument(Object key) throws DBException {
+ if (log.isDebugEnabled()) {
+ log.debug(debugHeader() + "Get document: " + key);
}
Entry entry = getEntry(key);
@@ -770,76 +937,7 @@
return null;
}
- if (entry.getEntryType() != Entry.BINARY) {
- throw new DBException(FaultCodes.COL_INVALID_RESULT,
- "Resource '" + key + "' in collection '" +
- getCanonicalName() + "' is not a binary resource");
- }
-
- return (byte[]) entry.getValue();
- }
-
- /**
- * 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.
- * @throws DBException if operation failed
- */
- public MetaData getCollectionMeta() throws DBException {
- if (!isMetaEnabled()) {
- if (log.isWarnEnabled()) {
- log.warn("Meta information requested but not enabled in config!");
- }
- return null;
- }
-
- MetaSystemCollection metacol = getMetaSystemCollection();
- MetaData meta = metacol.getCollectionMeta(this);
- if (null == meta) {
- long now = System.currentTimeMillis();
- meta = new MetaData(MetaData.COLLECTION, getCanonicalName(), now, now);
- metacol.setCollectionMeta(this, meta);
- }
-
- return meta;
- }
-
- /**
- * 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
- * @throws DBException if operation failed
- */
- public final Container getContainer(Object docKey) throws DBException {
- Key key = createNewKey(docKey);
- Document doc = getDocument(key);
- return doc != null ? new ColContainer(key, doc) : null;
- }
-
- /**
- * getDocument retrieves a Document by Key.
- *
- * @param key The Document Key
- * @return The Document
- * @throws DBException if operation failed
- */
- public final Document getDocument(Object key) throws DBException {
- if (log.isDebugEnabled()) {
- log.debug(debugHeader() + "Get document: " + key);
- }
-
- Entry entry = getEntry(key);
- if (entry == null) {
- return null;
- }
-
- if (entry.getEntryType() != Entry.DOCUMENT) {
+ if (entry.getEntryType() != Entry.DOCUMENT) {
throw new DBException(FaultCodes.COL_INVALID_RESULT,
"Resource '" + key + "' in collection '" +
getCanonicalName() + "' is not a document");
@@ -849,268 +947,6 @@
}
/**
- * getDocumentCount returns the count of Documents being maintained
- * by this Collection.
- *
- * @return The Document count
- * @throws DBException if operation failed
- */
- 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
- * @return meta data for requested resource
- * @throws DBException if operation failed
- */
- public MetaData getDocumentMeta(String id) throws DBException {
- if (!isMetaEnabled()) {
- if (log.isWarnEnabled()) {
- log.warn("Meta information requested but not enabled in config!");
- }
- return null;
- }
-
- Key key = getIdentityKey(createNewKey(id));
- synchronized (key) {
- if (getEntry(id) == null) {
- throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND,
- "Resource '" + id + "' does not exist in '" + getCanonicalName() + "'");
- }
-
- MetaSystemCollection metacol = getMetaSystemCollection();
- MetaData meta = metacol.getDocumentMeta(this, id);
-
- /*
- FIXME It is more efficient to store (and retrieve) created/modified timestamps
- from the Record itself instead of storing them in the separate MetaData
- object. Storing in the Record avoids writing two documents on each update
- (Document itself and its MetaData).
- Retrieval of the timestamps from Record can be implemented via TimeRecord.
-
- 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 now = System.currentTimeMillis();
- if (meta == null) {
- meta = new MetaData(MetaData.DOCUMENT, getCanonicalDocumentName(id), now, now);
- metacol.setDocumentMeta(this, id, meta);
- } else if (!meta.hasContext()) {
- meta.setContext(now, now);
- }
-
- return meta;
- }
- }
-
- /**
- * getDocumentSet returns the set of Documents being maintained
- * by this Collection.
- *
- * @return The DocumentSet
- * @throws DBException if operation failed
- */
- 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, otherwise this
- * method returns Entry that identifies resource type and holds its
- * value and metadata.
- *
- * @param docKey identifying the desired database entry
- * @return Entry containing the database entry and its metadata, or null
- * if no matching entry is found
- * @throws DBException in case of backing store error,
- * and in case of header corruption
- */
- public final Entry 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 = null;
- if (log.isTraceEnabled()) {
- localDebugHeader = debugHeader() + "getEntry: docKey=<" + docKey + ">: ";
- log.trace(localDebugHeader);
- }
-
- checkFiler(FaultCodes.COL_NO_FILER);
-
- Key key = getIdentityKey(createNewKey(docKey));
- synchronized (key) {
-
- /*
- * 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) {
- Entry entry = documentCache.getEntry(this, key);
- if (entry != null) {
- if (log.isTraceEnabled()) {
- log.trace(localDebugHeader + "Returning cached: " + entry.getValue());
- }
-
- return entry;
- }
- }
-
- Record record = filer.readRecord(key);
- if (record == null) {
- return null;
- }
-
- Value value;
- InlineMetaMap metaMap = null;
- if (inlineMetaService == null) {
- value = record.getValue();
-
- if (log.isTraceEnabled()) {
- log.trace(localDebugHeader + "Type is not available, Length=" + value.getLength());
- }
- } else {
- InlineMetaService.DatabaseEntry databaseEntry = inlineMetaService.readDatabaseEntry(record.getValue());
- metaMap = databaseEntry.map;
- value = databaseEntry.value;
-
- if (log.isTraceEnabled()) {
- log.trace(localDebugHeader + "Type=" + metaMap.get("type") + ", Length=" + value.getLength());
- }
- }
-
- Map entryMeta = Entry.createMetaMap(record);
- if (inlineMetaService == null || metaMap.get("type").equals(ResourceTypeReader.XML)) {
- Document document;
- if (compressed) {
- document = new DocumentImpl(value.getData(), symbols, new NodeSource(this, key));
- flushSymbolTable();
- if (log.isTraceEnabled()) {
- log.trace(localDebugHeader +
- "Compressed XML document=<" + TextWriter.toString(document) + ">");
- }
-
- if (documentCache != null) {
- documentCache.putDocumentEntry(this, key, value.getData(), entryMeta);
- }
- } else {
- String documentChars = value.toString();
- if (log.isTraceEnabled()) {
- log.trace(localDebugHeader + "Pre parseDocument(): value=<" + documentChars + ">");
- }
-
- // FIXME There should be no reason here to re-compress the document & flush symbols table?
- document = parseDocument(key, documentChars);
- flushSymbolTable();
-
- if (documentCache != null) {
- documentCache.putDocumentEntry(this, key, documentChars, entryMeta);
- }
- }
-
- DBObserver.getInstance().loadDocument(this, record, document);
- return new Entry(key, document, entryMeta);
- } else {
- if (log.isTraceEnabled()) {
- log.trace(localDebugHeader + "Binary document");
- }
-
- return new Entry(key, value.getData(), entryMeta);
- }
- }
- }
-
- /**
- * Retrieve a database entry metadata by key.
- *
- * If no matching entry is found, null is returned, otherwise this method
- * return Entry that holds metadata only.
- *
- * @param docKey identifying the desired database entry
- * @return Entry containing the metadata of 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 Entry getEntryMeta(Object docKey) throws DBException {
- if (docKey == null) {
- return null;
- }
-
- checkFiler(FaultCodes.COL_NO_FILER);
-
- Key key = getIdentityKey(createNewKey(docKey));
- synchronized (key) {
- /*
- * If the key has a corresponding value in the cache, return it
- * and save a disk access.
- */
- if (documentCache != null) {
- Entry entry = documentCache.getEntryMeta(this, key);
- if (entry != null) {
- return entry;
- }
- }
-
- Record record = filer.readRecord(key, true);
- if (record == null) {
- return null;
- }
-
- Map entryMeta = Entry.createMetaMap(record);
- return new Entry(key, entryMeta);
- }
- }
-
- /**
- * getIndexer retrieves an Indexer by name.
- *
- * @param name The Indexer name
- * @return The Indexer (or null)
- * @throws DBException if operation failed
- */
- 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
- * @throws DBException if operation failed
- */
- public final IndexManager getIndexManager() throws DBException {
- checkFiler(FaultCodes.COL_NO_INDEXMANAGER);
- return indexManager;
- }
-
- /**
* 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.
@@ -1154,46 +990,40 @@
}
/**
- * 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.
+ * Retrieve a binary database entry by key.
+ * This low-level method will not update non-inline metadata.
*
- * @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.
+ * @param key 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 Key insertBinary(byte[] bytes) throws DBException {
- return insertBinary(null, bytes);
- }
+ public final byte[] getBinary(Object key) throws DBException {
+ if (log.isTraceEnabled()) {
+ log.trace(debugHeader() + "Get binary: " + key);
+ }
- /**
- * insertBinary inserts a new binary object into a Xindice Collection.
- *
- * @param docKey The document Key
- * @param bytes The document to insert
- * @return key for the inserted binary
- * @throws DBException if inline-metadata is not enabled, the key is
- * already in the database, or an error occurs while saving.
- */
- public Key insertBinary(Object docKey, byte[] bytes) throws DBException {
if (inlineMetaService == null) {
- throw new DBException(FaultCodes.COL_CANNOT_STORE,
- "Cannot insert a binary resource in '" + getCanonicalName() +
- "' (inline-metadata is not enabled)");
+ throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND,
+ "Collection '" + getCanonicalName() +
+ "' has no binary resources (inline metadata is not enabled)");
}
- Key key = createNewKey(docKey);
- if (log.isInfoEnabled()) {
- log.info(debugHeader() + "Insert binary: " + key);
+ Entry entry = getEntry(key);
+ if (entry == null) {
+ return null;
}
- putBinary(key, bytes, ACTION_INSERT);
- // update the meta information if necessary
- updateCollectionMeta();
- return key;
+ if (entry.getEntryType() != Entry.BINARY) {
+ throw new DBException(FaultCodes.COL_INVALID_RESULT,
+ "Resource '" + key + "' in collection '" +
+ getCanonicalName() + "' is not a binary resource");
+ }
+
+ return (byte[]) entry.getValue();
}
/**
@@ -1263,129 +1093,112 @@
}
/**
- * Returns whether or not meta data is enabled.
+ * 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.
*
- * @return boolean whether or not meta data is enabled.
+ * @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 boolean isMetaEnabled() {
- return getDatabase().isMetaEnabled();
+ public Key insertBinary(byte[] bytes) throws DBException {
+ return insertBinary(null, bytes);
+ }
+
+ /**
+ * insertBinary inserts a new binary object into a Xindice Collection.
+ *
+ * @param docKey The document Key
+ * @param bytes The document to insert
+ * @return key for the inserted binary
+ * @throws DBException if inline-metadata is not enabled, the key is
+ * already in the database, or an error occurs while saving.
+ */
+ public Key insertBinary(Object docKey, byte[] bytes) throws DBException {
+ if (inlineMetaService == null) {
+ throw new DBException(FaultCodes.COL_CANNOT_STORE,
+ "Cannot insert a binary resource in '" + getCanonicalName() +
+ "' (inline-metadata is not enabled)");
+ }
+
+ Key key = createNewKey(docKey);
+ if (log.isInfoEnabled()) {
+ log.info(debugHeader() + "Insert binary: " + key);
+ }
+ putBinary(key, bytes, ACTION_INSERT);
+
+ // update the meta information if necessary
+ updateCollectionMeta();
+ return key;
}
/**
- * listDocuments returns a list of all entry keys stored by this
- * collection.
+ * setDocument inserts or updates an existing Document in a
+ * Xindice Collection.
*
- * @return the list of entry keys
+ * @param docKey The Document Key
+ * @param document The Document
+ * @return True if new document entry was created, false otherwise
* @throws DBException if operation failed
*/
- 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 {
- // TODO: ArrayList length is limited to the int, while filer record count is long
-
- // give a hint to the size of the record set, saves on arraylist array copies.
- ArrayList temp = new ArrayList((int) filer.getRecordCount());
-
- RecordSet set = filer.getRecordSet();
- while (set.hasMoreRecords()) {
- Key key = set.getNextKey();
- temp.add(key.toString());
- }
+ public final boolean setDocument(Object docKey, Document document) throws DBException {
+ if (log.isInfoEnabled()) {
+ log.info(debugHeader() + "Set document " + docKey);
+ }
- return (String[]) temp.toArray(new String[temp.size()]);
+ boolean res = putDocument(createNewKey(docKey), document, ACTION_STORE);
+ if (res) {
+ updateCollectionMeta();
}
- }
- /**
- * listIndexers returns a list of the currently registered Indexers
- * as an array of String.
- *
- * @return The Indexer list
- * @throws DBException if operation failed
- */
- public final String[] listIndexers() throws DBException {
- checkFiler(FaultCodes.COL_NO_INDEXMANAGER);
- return indexManager.list();
+ return res;
}
/**
- * Turns an XML string into a parsed document retrieved
- * from the uncompressed collection.
+ * 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 when caching
- * @param xml The string to parse
- * @return A parsed DOM document or null if failure
+ * @param key The Key to use
+ * @param obj The Object to set
* @throws DBException if operation failed
*/
- private Document parseDocument(Key key, String xml) throws DBException {
- try {
- Document doc = DOMParser.toDocument(xml);
- ((DBDocument) doc).setSource(new NodeSource(this, key));
-
- // Have to compress to update collection's SymbolTable,
- // which is used even for uncompressed collections
- DOMCompressor.compress(doc, symbols);
-
- return doc;
- } catch (Exception e) {
- throw new DBException(FaultCodes.COL_DOCUMENT_MALFORMED,
- "Unable to parse document '" + key + "' in '" + getCanonicalName() + "'", e);
+ public final void setObject(Object key, XMLSerializable obj) throws DBException {
+ if (log.isInfoEnabled()) {
+ log.info(debugHeader() + "Set object " + key);
}
+ putObject(createNewKey(key), obj, ACTION_STORE);
}
/**
- * Lowest-level method for saving a binary entry into the database. At this moment,
- * presence of inline metadata is known.
- * It now does update non-inline metadata if the user has configured it.
- * <br/><br/>
- * putBinary attempts to perform requested action, and success depends on action
- * and presense of the key in the collection.
- * <br/><br/>
- * @param key Entry key
- * @param bytes Value
- * @param action It can be either ACTION_INSERT, ACTION_UPDATE or ACTION_STORE
- * @return True if new binary entry was created, false otherwise
- * @throws DBException<ul>
- * <li>FaultCodes.COL_DUPLICATE_RESOURCE If entry with that key already present in
- * collection and action is ACTION_INSERT</li>
- * <li>FaultCodes.COL_DOCUMENT_NOT_FOUND If entry with that key is not present in
- * collection and action is ACTION_UPDATE
- * </ul>
+ * setBinary inserts or updates binary object into a Xindice Collection.
+ *
+ * @param docKey The document Key
+ * @param bytes The document to insert
+ * @return true if new binary was created, false otherwise
+ * @throws DBException if inline-metadata is not enabled, the key is
+ * already in the database, or an error occurs while saving.
*/
- private boolean putBinary(Key key, byte[] bytes, byte action) throws DBException {
- synchronized (getIdentityKey(key)) {
- Entry entry = getEntry(key);
- if (action == ACTION_INSERT && entry != null) {
- throw new DBException(FaultCodes.COL_DUPLICATE_RESOURCE,
- "Error inserting binary resource '" + key + "' in '" + getCanonicalName() +
- "': key is already in database");
- } else if (action == ACTION_UPDATE && entry == null) {
- throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND,
- "Error updating binary resource '" + key + "' in '" + getCanonicalName() +
- "': key does not exist in database");
- }
-
- if (entry != null && entry.getEntryType() == Entry.DOCUMENT) {
- // binary resources aren't stored in cache or indexes
- if (documentCache != null) {
- documentCache.removeEntry(this, key);
- }
- indexManager.removeDocument(key, (Document) entry.getValue());
- }
+ public boolean setBinary(Object docKey, byte[] bytes) throws DBException {
+ if (inlineMetaService == null) {
+ throw new DBException(FaultCodes.COL_CANNOT_STORE,
+ "Cannot insert a binary resource in '" + getCanonicalName() +
+ "' (inline-metadata is not enabled)");
+ }
- InlineMetaMap map = inlineMetaService.getEmptyMap();
- map.put("type", ResourceTypeReader.BINARY);
- Value value = inlineMetaService.createValue(map, bytes, 0, bytes.length);
- Record record = filer.writeRecord(key, value);
+ if (log.isInfoEnabled()) {
+ log.info(debugHeader() + "Set binary " + docKey);
+ }
- // update the meta for this document
- updateDocumentMeta(record);
- return entry == null;
+ boolean res = putBinary(createNewKey(docKey), bytes, ACTION_STORE);
+ if (res) {
+ updateCollectionMeta();
}
+
+ return res;
}
/**
@@ -1541,50 +1354,54 @@
}
/**
- * 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
- * @throws DBException if operation failed
+ * Lowest-level method for saving a binary entry into the database. At this moment,
+ * presence of inline metadata is known.
+ * It now does update non-inline metadata if the user has configured it.
+ * <br/><br/>
+ * putBinary attempts to perform requested action, and success depends on action
+ * and presense of the key in the collection.
+ * <br/><br/>
+ * @param key Entry key
+ * @param bytes Value
+ * @param action It can be either ACTION_INSERT, ACTION_UPDATE or ACTION_STORE
+ * @return True if new binary entry was created, false otherwise
+ * @throws DBException<ul>
+ * <li>FaultCodes.COL_DUPLICATE_RESOURCE If entry with that key already present in
+ * collection and action is ACTION_INSERT</li>
+ * <li>FaultCodes.COL_DOCUMENT_NOT_FOUND If entry with that key is not present in
+ * collection and action is ACTION_UPDATE
+ * </ul>
*/
- public final NodeSet queryCollection(String style, String query, NamespaceMap nsMap) throws DBException {
- if (log.isDebugEnabled()) {
- log.debug(debugHeader() + "Query collection, query " + query);
- }
+ private boolean putBinary(Key key, byte[] bytes, byte action) throws DBException {
+ synchronized (getIdentityKey(key)) {
+ Entry entry = getEntry(key);
+ if (action == ACTION_INSERT && entry != null) {
+ throw new DBException(FaultCodes.COL_DUPLICATE_RESOURCE,
+ "Error inserting binary resource '" + key + "' in '" + getCanonicalName() +
+ "': key is already in database");
+ } else if (action == ACTION_UPDATE && entry == null) {
+ throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND,
+ "Error updating binary resource '" + key + "' in '" + getCanonicalName() +
+ "': key does not exist in database");
+ }
- // 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);
- }
+ if (entry != null && entry.getEntryType() == Entry.DOCUMENT) {
+ // binary resources aren't stored in cache or indexes
+ if (documentCache != null) {
+ documentCache.removeEntry(this, key);
+ }
+ indexManager.removeDocument(key, (Document) entry.getValue());
+ }
- /**
- * 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
- * @throws DBException if operation failed
- */
- public final NodeSet queryDocument(String style, String query, NamespaceMap nsMap, Object key) throws DBException {
- if (log.isInfoEnabled()) {
- log.info(debugHeader() + "Query document " + key + ", query: " + query);
- }
+ InlineMetaMap map = inlineMetaService.getEmptyMap();
+ map.put("type", ResourceTypeReader.BINARY);
+ Value value = inlineMetaService.createValue(map, bytes, 0, bytes.length);
+ Record record = filer.writeRecord(key, value);
- checkFiler(FaultCodes.QRY_STYLE_NOT_FOUND);
- Key[] k;
- if (key instanceof Key[]) {
- k = (Key[]) key;
- } else {
- k = new Key[]{createNewKey(key)};
+ // update the meta for this document
+ updateDocumentMeta(record);
+ return entry == null;
}
- return getQueryEngine().query(this, style, query, nsMap, k);
}
/**
@@ -1626,7 +1443,47 @@
getMetaSystemCollection().dropDocumentMeta(this, objKey.toString());
}
}
- DBObserver.getInstance().dropDocument(this, objKey);
+ DBObserver.getInstance().dropDocument(this, objKey);
+ }
+
+
+ // -- Core Collection API Public Methods: Meta Data Management ----------
+
+ /**
+ * 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.
+ * @throws DBException if operation failed
+ */
+ public MetaData getCollectionMeta() throws DBException {
+ if (!isMetaEnabled()) {
+ if (log.isWarnEnabled()) {
+ log.warn("Meta information requested but not enabled in config!");
+ }
+ return null;
+ }
+
+ MetaSystemCollection metacol = getMetaSystemCollection();
+ MetaData meta = metacol.getCollectionMeta(this);
+ if (null == meta) {
+ long now = System.currentTimeMillis();
+ meta = new MetaData(MetaData.COLLECTION, getCanonicalName(), now, now);
+ metacol.setCollectionMeta(this, meta);
+ }
+
+ return meta;
}
/**
@@ -1657,53 +1514,99 @@
}
/**
- * setDocument inserts or updates an existing Document in a
- * Xindice Collection.
+ * Retrieve a database entry metadata by key.
*
- * @param docKey The Document Key
- * @param document The Document
- * @return True if new document entry was created, false otherwise
- * @throws DBException if operation failed
+ * If no matching entry is found, null is returned, otherwise this method
+ * return Entry that holds metadata only.
+ *
+ * @param docKey identifying the desired database entry
+ * @return Entry containing the metadata of 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 boolean setDocument(Object docKey, Document document) throws DBException {
- if (log.isInfoEnabled()) {
- log.info(debugHeader() + "Set document " + docKey);
+ public final Entry getEntryMeta(Object docKey) throws DBException {
+ if (docKey == null) {
+ return null;
}
- boolean res = putDocument(createNewKey(docKey), document, ACTION_STORE);
- if (res) {
- updateCollectionMeta();
- }
+ checkFiler(FaultCodes.COL_NO_FILER);
- return res;
+ Key key = getIdentityKey(createNewKey(docKey));
+ synchronized (key) {
+ /*
+ * If the key has a corresponding value in the cache, return it
+ * and save a disk access.
+ */
+ if (documentCache != null) {
+ Entry entry = documentCache.getEntryMeta(this, key);
+ if (entry != null) {
+ return entry;
+ }
+ }
+
+ Record record = filer.readRecord(key, true);
+ if (record == null) {
+ return null;
+ }
+
+ Map entryMeta = Entry.createMetaMap(record);
+ return new Entry(key, entryMeta);
+ }
}
/**
- * setBinary inserts or updates binary object into a Xindice Collection.
+ * Return the MetaData object for a document within this collection.
+ * If metadata is not enabled, the MetaData object returned will be null.
*
- * @param docKey The document Key
- * @param bytes The document to insert
- * @return true if new binary was created, false otherwise
- * @throws DBException if inline-metadata is not enabled, the key is
- * already in the database, or an error occurs while saving.
+ * @param id the document whose metadata you want
+ * @return meta data for requested resource
+ * @throws DBException if operation failed
*/
- public boolean setBinary(Object docKey, byte[] bytes) throws DBException {
- if (inlineMetaService == null) {
- throw new DBException(FaultCodes.COL_CANNOT_STORE,
- "Cannot insert a binary resource in '" + getCanonicalName() +
- "' (inline-metadata is not enabled)");
+ public MetaData getDocumentMeta(String id) throws DBException {
+ if (!isMetaEnabled()) {
+ if (log.isWarnEnabled()) {
+ log.warn("Meta information requested but not enabled in config!");
+ }
+ return null;
}
- if (log.isInfoEnabled()) {
- log.info(debugHeader() + "Set binary " + docKey);
- }
+ Key key = getIdentityKey(createNewKey(id));
+ synchronized (key) {
+ if (getEntry(id) == null) {
+ throw new DBException(FaultCodes.COL_DOCUMENT_NOT_FOUND,
+ "Resource '" + id + "' does not exist in '" + getCanonicalName() + "'");
+ }
- boolean res = putBinary(createNewKey(docKey), bytes, ACTION_STORE);
- if (res) {
- updateCollectionMeta();
- }
+ MetaSystemCollection metacol = getMetaSystemCollection();
+ MetaData meta = metacol.getDocumentMeta(this, id);
- return res;
+ /*
+ FIXME It is more efficient to store (and retrieve) created/modified timestamps
+ from the Record itself instead of storing them in the separate MetaData
+ object. Storing in the Record avoids writing two documents on each update
+ (Document itself and its MetaData).
+ Retrieval of the timestamps from Record can be implemented via TimeRecord.
+
+ 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 now = System.currentTimeMillis();
+ if (meta == null) {
+ meta = new MetaData(MetaData.DOCUMENT, getCanonicalDocumentName(id), now, now);
+ metacol.setDocumentMeta(this, id, meta);
+ } else if (!meta.hasContext()) {
+ meta.setContext(now, now);
+ }
+
+ return meta;
+ }
}
/**
@@ -1746,22 +1649,6 @@
}
/**
- * 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
- * @throws DBException if operation failed
- */
- public final void setObject(Object key, XMLSerializable obj) throws DBException {
- if (log.isInfoEnabled()) {
- log.info(debugHeader() + "Set object " + key);
- }
- putObject(createNewKey(key), obj, ACTION_STORE);
- }
-
- /**
* update the modified time of this collection when appropriate
*/
protected void updateCollectionMeta() {
@@ -1843,5 +1730,127 @@
}
metacol.setDocumentMeta(this, id, meta);
+ }
+
+
+ // ----------------------------------------------------------------------
+
+ /**
+ * 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
+ * @throws DBException if operation failed
+ */
+ public final Container getContainer(Object docKey) throws DBException {
+ Key key = createNewKey(docKey);
+ Document doc = getDocument(key);
+ return doc != null ? new ColContainer(key, doc) : null;
+ }
+
+ /**
+ * getDocumentCount returns the count of Documents being maintained
+ * by this Collection.
+ *
+ * @return The Document count
+ * @throws DBException if operation failed
+ */
+ 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();
+ }
+
+ /**
+ * getDocumentSet returns the set of Documents being maintained
+ * by this Collection.
+ *
+ * @return The DocumentSet
+ * @throws DBException if operation failed
+ */
+ 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 entry keys stored by this
+ * collection.
+ *
+ * @return the list of entry keys
+ * @throws DBException if operation failed
+ */
+ 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 {
+ // TODO: ArrayList length is limited to the int, while filer record count is long
+
+ // give a hint to the size of the record set, saves on arraylist array copies.
+ ArrayList temp = new ArrayList((int) filer.getRecordCount());
+
+ RecordSet set = filer.getRecordSet();
+ while (set.hasMoreRecords()) {
+ Key key = set.getNextKey();
+ temp.add(key.toString());
+ }
+
+ return (String[]) temp.toArray(new String[temp.size()]);
+ }
+ }
+
+ /**
+ * 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
+ * @throws DBException if operation failed
+ */
+ public final NodeSet queryCollection(String style, String query, NamespaceMap nsMap) throws DBException {
+ if (log.isDebugEnabled()) {
+ log.debug(debugHeader() + "Query collection, query " + query);
+ }
+
+ // 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
+ * @throws DBException if operation failed
+ */
+ public final NodeSet queryDocument(String style, String query, NamespaceMap nsMap, Object key) throws DBException {
+ if (log.isInfoEnabled()) {
+ log.info(debugHeader() + "Query document " + key + ", query: " + query);
+ }
+
+ checkFiler(FaultCodes.QRY_STYLE_NOT_FOUND);
+ Key[] k;
+ if (key instanceof Key[]) {
+ k = (Key[]) key;
+ } else {
+ k = new Key[]{createNewKey(key)};
+ }
+ return getQueryEngine().query(this, style, query, nsMap, k);
}
}
lmpx.com only provides a reader for public news (NNTP) servers. It is not
affiliated with the servers or forums shown here and is not responsible for
the content of articles, which is written by their respective authors.