/*
* $Header: /home/cvs/jakarta-slide/src/share/org/apache/slide/store/AbstractStore.java,v 1.36.2.2 2004/02/05 16:05:12 mholz Exp $
* $Revision: 1.36.2.2 $
* $Date: 2004/02/05 16:05:12 $
*
* ====================================================================
*
* Copyright 1999-2002 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package org.apache.slide.store;
import java.util.Enumeration;
import java.util.Hashtable;
import javax.transaction.Transaction;
import javax.transaction.xa.XAException;
import javax.transaction.xa.Xid;
import org.apache.slide.authenticate.CredentialsToken;
import org.apache.slide.common.AbstractSimpleService;
import org.apache.slide.common.Namespace;
import org.apache.slide.common.NamespaceAccessToken;
import org.apache.slide.common.Scope;
import org.apache.slide.common.Service;
import org.apache.slide.common.ServiceAccessException;
import org.apache.slide.common.ServiceConnectionFailedException;
import org.apache.slide.common.ServiceDisconnectionFailedException;
import org.apache.slide.common.ServiceInitializationFailedException;
import org.apache.slide.common.ServiceParameterErrorException;
import org.apache.slide.common.ServiceParameterMissingException;
import org.apache.slide.common.ServiceResetFailedException;
import org.apache.slide.common.SlideToken;
import org.apache.slide.common.Uri;
import org.apache.slide.content.NodeRevisionContent;
import org.apache.slide.content.NodeRevisionDescriptor;
import org.apache.slide.content.NodeRevisionDescriptors;
import org.apache.slide.content.NodeRevisionNumber;
import org.apache.slide.content.RevisionAlreadyExistException;
import org.apache.slide.content.RevisionDescriptorNotFoundException;
import org.apache.slide.content.RevisionNotFoundException;
import org.apache.slide.lock.LockTokenNotFoundException;
import org.apache.slide.lock.NodeLock;
import org.apache.slide.security.NodePermission;
import org.apache.slide.structure.ObjectAlreadyExistsException;
import org.apache.slide.structure.ObjectNode;
import org.apache.slide.structure.ObjectNotFoundException;
import org.apache.slide.util.Messages;
import org.apache.slide.util.logger.Logger;
/**
* Abstract implementation of a store. Handles all caching operations.
*
* @author <a href="mailto:remm@apache.org">Remy Maucherat</a>
* @version $Revision: 1.36.2.2 $
*/
public abstract class AbstractStore extends AbstractSimpleService
implements Store {
// ----------------------------------------------------------- Constructors
// ----------------------------------------------------- Instance Variables
/**
* Node store.
*/
protected NodeStore nodeStore;
/**
* Security store.
*/
protected SecurityStore securityStore;
/**
* Lock store.
*/
protected LockStore lockStore;
/**
* Revision descriptors store.
*/
protected RevisionDescriptorsStore revisionDescriptorsStore;
/**
* Revision descriptor store.
*/
protected RevisionDescriptorStore revisionDescriptorStore;
/**
* Content store.
*/
protected ContentStore contentStore;
/**
* Active resource manager list.
*/
protected Service resourceManagers[] = new Service[0];
// the name of this store as specified in domain.xml
private String name;
/**
* Set the name of the store as specified in domain.xml.
*/
public void setName(String name) {
this.name = name;
}
/**
* Return the name of the store as specified in domain.xml.
*/
public String getName() {
return this.name;
}
/**
* Set the scope of the store as specified in domain.xml.
*/
public void setScope(Scope scope) {
super.setScope(scope);
for (int i = 0; i < resourceManagers.length; i++) {
resourceManagers[i].setScope(scope);
}
}
// ---------------------------------------------------- ServiceImpl Methods
/**
* Namespace setter.
*/
public void setNamespace(Namespace namespace) {
super.setNamespace(namespace);
for (int i = 0; i < resourceManagers.length; i++) {
resourceManagers[i].setNamespace(namespace);
}
}
protected Hashtable parameters = null;
/**
* Remeber the store parameters to initialise the default child stores on request
*
* @param parameters Hashtable containing the parameters' name
* and associated value
* @exception ServiceParameterErrorException Incorrect service parameter
* @exception ServiceParameterMissingException Service parameter missing
*/
public void setParameters(Hashtable parameters)
throws ServiceParameterErrorException,
ServiceParameterMissingException {
this.parameters = parameters;
}
public Object getParameter (Object key) {
return parameters.get (key);
}
/**
* Connects to descriptors store.
*
* @exception DataException
*/
public void connect(CredentialsToken crdtoken)
throws ServiceConnectionFailedException {
for (int i = 0; i < resourceManagers.length; i++) {
resourceManagers[i].connect(crdtoken);
}
}
/**
* Connects to descriptors store.
*
* @exception DataException
*/
public void connect()
throws ServiceConnectionFailedException {
for (int i = 0; i < resourceManagers.length; i++) {
resourceManagers[i].connect();
}
}
/**
* Disconnects from descriptors store.
*
* @exception ServiceDisconnectionFailedException
*/
public void disconnect()
throws ServiceDisconnectionFailedException {
for (int i = 0; i < resourceManagers.length; i++) {
resourceManagers[i].disconnect();
}
}
/**
* Initializes descriptors store.
*
* @exception ServiceInitializationFailedException Throws an exception
* if the descriptors store has already been initialized before
*/
public void initialize(NamespaceAccessToken token)
throws ServiceInitializationFailedException {
super.initialize(token);
for (int i = 0; i < resourceManagers.length; i++) {
resourceManagers[i].initialize(token);
}
}
/**
* Deletes descriptors store. Should remove stored data if possible.
*
* @exception ServiceResetFailedException Reset failed
*/
public void reset()
throws ServiceResetFailedException {
for (int i = 0; i < resourceManagers.length; i++) {
resourceManagers[i].reset();
}
}
/**
* This function tells whether or not the descriptors store is connected.
*
* @return boolean true if we are connected
* @exception ServiceAccessException Service access error
*/
public boolean isConnected()
throws ServiceAccessException {
for (int i = 0; i < resourceManagers.length; i++) {
if (!resourceManagers[i].isConnected())
return false;
}
return true;
}
// ----------------------------------------------------- XAResource Methods
/**
* Commit the global transaction specified by xid.
*
* @param xid A global transaction identifier
* @param onePhase If true, the resource manager should use a one-phase
* commit protocol to commit the work done on behalf of xid.
* @exception XAException An error has occurred. Possible XAExceptions
* are XA_HEURHAZ, XA_HEURCOM, XA_HEURRB, XA_HEURMIX, XAER_RMERR,
* XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or XAER_PROTO. If the resource
* manager did not commit the transaction and the paramether onePhase is
* set to true, the resource manager may throw one of the XA_RB*
* exceptions. Upon return, the resource manager has rolled back the
* branch's work and has released all held resources.
*/
public void commit(Xid xid, boolean onePhase)
throws XAException {
super.commit(xid, onePhase);
}
/**
* Ends the work performed on behalf of a transaction branch.
*
* @param xid A global transaction identifier that is the same as what
* was used previously in the start method.
* @param flags One of TMSUCCESS, TMFAIL, or TMSUSPEND
* @exception XAException An error has occurred. Possible XAException
* values are XAER_RMERR, XAER_RMFAILED, XAER_NOTA, XAER_INVAL,
* XAER_PROTO, or XA_RB*.
*/
public void end(Xid xid, int flags)
throws XAException {
super.end(xid, flags);
}
/**
* Tell the resource manager to forget about a heuristically completed
* transaction branch.
*
* @param xid A global transaction identifier
* @exception XAException An error has occurred. Possible exception values
* are XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL, or XAER_PROTO.
*/
public void forget(Xid xid)
throws XAException {
super.forget(xid);
}
/**
* Ask the resource manager to prepare for a transaction commit of the
* transaction specified in xid.
*
* @param xid A global transaction identifier
* @return A value indicating the resource manager's vote on the outcome
* of the transaction. The possible values are: XA_RDONLY or XA_OK. If
* the resource manager wants to roll back the transaction, it should do
* so by raising an appropriate XAException in the prepare method.
* @exception XAException An error has occurred. Possible exception
* values are: XA_RB*, XAER_RMERR, XAER_RMFAIL, XAER_NOTA, XAER_INVAL,
* or XAER_PROTO.
*/
public int prepare(Xid xid)
throws XAException {
return super.prepare(xid);
}
/**
* Inform the resource manager to roll back work done on behalf of a
* transaction branch.
*
* @param xid A global transaction identifier
* @exception XAException An error has occurred
*/
public void rollback(Xid xid)
throws XAException {
super.rollback(xid);
}
/**
* Start work on behalf of a transaction branch specified in xid.
*
* @param xid A global transaction identifier to be associated with the
* resource
* @param flags One of TMNOFLAGS, TMJOIN, or TMRESUME
* @exception XAException An error has occurred. Possible exceptions are
* XA_RB*, XAER_RMERR, XAER_RMFAIL, XAER_DUPID, XAER_OUTSIDE, XAER_NOTA,
* XAER_INVAL, or XAER_PROTO.
*/
public void start(Xid xid, int flags)
throws XAException {
super.start(xid, flags);
}
// ---------------------------------------------------------- Store Methods
/**
* Set the node store associated with this store.
*/
public void setNodeStore(NodeStore nodeStore) {
if (nodeStore == null) {
throw new IllegalArgumentException("Nodestore must not be null");
}
this.nodeStore = nodeStore;
addResourceManager(this.nodeStore);
}
/**
* Set the security store associated with this store.
*/
public void setSecurityStore(SecurityStore securityStore) {
if (securityStore == null) {
throw new IllegalArgumentException("Securitystore must not be null");
}
this.securityStore = securityStore;
addResourceManager(this.securityStore);
}
/**
* Set the lock store associated with this store.
*/
public void setLockStore(LockStore lockStore) {
if (lockStore == null) {
throw new IllegalArgumentException("Lockstore must not be null");
}
this.lockStore = lockStore;
addResourceManager(this.lockStore);
}
/**
* Set the revision descriptors store associated with this store.
*/
public void setRevisionDescriptorsStore
(RevisionDescriptorsStore revisionDescriptorsStore) {
if (revisionDescriptorsStore == null) {
throw new IllegalArgumentException("Revisiondescriptorsstore must not be null");
}
this.revisionDescriptorsStore = revisionDescriptorsStore;
addResourceManager(this.revisionDescriptorsStore);
}
/**
* Set the revision descriptor store associated with this store.
*/
public void setRevisionDescriptorStore
(RevisionDescriptorStore revisionDescriptorStore) {
if (revisionDescriptorStore == null) {
throw new IllegalArgumentException("Revisiondescriptorstore must not be null");
}
this.revisionDescriptorStore = revisionDescriptorStore;
addResourceManager(this.revisionDescriptorStore);
}
/**
* Set the content store associated with this store.
*/
public void setContentStore(ContentStore contentStore) {
if (contentStore == null) {
throw new IllegalArgumentException("Contentstore must not be null");
}
this.contentStore = contentStore;
addResourceManager(this.contentStore);
}
/**
* Retrive an object from the Descriptors Store.
*
* @param uri Uri of the object we want to retrieve
* @exception ServiceAccessException Error accessing the Descriptors Store
* @exception ObjectNotFoundException The object to retrieve was not found
*/
public ObjectNode retrieveObject(Uri uri)
throws ServiceAccessException, ObjectNotFoundException {
ObjectNode objectNode = null;
if (isForceStoreEnlistment(uri)) {
enlist(nodeStore);
try {
objectNode = nodeStore.retrieveObject(uri);
} catch (ServiceAccessException e) {
delist(nodeStore, false);
throw e;
} catch (ObjectNotFoundException e) {
// Note : Failed reads aren't considered fatal (ie, the
// transaction won't be always rolledback when committed)
delist(nodeStore);
throw e;
} catch (Throwable t) {
delist(nodeStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException(nodeStore, t);
}
delist(nodeStore);
} else {
try {
objectNode = nodeStore.retrieveObject(uri);
} catch (ServiceAccessException e) {
throw e;
} catch (ObjectNotFoundException e) {
throw e;
} catch (Throwable t) {
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException(nodeStore, t);
}
}
objectNode.validate(uri.toString());
return objectNode;
}
/**
* Store an object in the Descriptors Store.
*
* @param object Object to update
* @exception ServiceAccessException Error accessing the Descriptors Store
* @exception ObjectNotFoundException The object to update was not found
*/
public void storeObject(Uri uri, ObjectNode object)
throws ServiceAccessException, ObjectNotFoundException {
ObjectNode tempObject = object.cloneObject();
tempObject.validate(uri.toString());
enlist(nodeStore);
try {
nodeStore.storeObject(uri, tempObject);
} catch (ServiceAccessException e) {
delist(nodeStore, false);
throw e;
} catch (ObjectNotFoundException e) {
delist(nodeStore);
throw e;
} catch (Throwable t) {
delist(nodeStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException(contentStore, t);
}
delist(nodeStore);
}
/**
* Create a new object in the Descriptors Store.
*
* @param object SlideObject
* @param uri Uri of the object we want to create
* @exception ServiceAccessException Error accessing the Descriptors Store
* @exception ObjectAlreadyExistsException An object already exists
* at this Uri
*/
public void createObject(Uri uri, ObjectNode object)
throws ServiceAccessException, ObjectAlreadyExistsException {
ObjectNode tempObject = object.cloneObject();
tempObject.validate(uri.toString());
enlist(nodeStore);
try {
nodeStore.createObject(uri, tempObject);
if (useBinding()) {
String uuri = tempObject.getUuri();
if (uuri == null) {
throw new IllegalStateException();
}
object.setUuri(uuri);
} else {
object.setUuri(tempObject.getUri());
}
} catch (ServiceAccessException e) {
delist(nodeStore, false);
throw e;
} catch (ObjectAlreadyExistsException e) {
delist(nodeStore);
throw e;
} catch (Throwable t) {
delist(nodeStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException(nodeStore, t);
}
delist(nodeStore);
}
/**
* Remove an object from the Descriptors Store.
*
* @param object Object to remove
* @exception ServiceAccessException Error accessing the Descriptors Store
* @exception ObjectNotFoundException The object to remove was not found
*/
public void removeObject(Uri uri, ObjectNode object)
throws ServiceAccessException, ObjectNotFoundException {
object.validate(uri.toString());
enlist(nodeStore);
try {
nodeStore.removeObject(uri, object);
} catch (ServiceAccessException e) {
delist(nodeStore, false);
throw e;
} catch (ObjectNotFoundException e) {
delist(nodeStore);
throw e;
} catch (Throwable t) {
delist(nodeStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException(nodeStore, t);
}
delist(nodeStore);
}
/**
* Store an object permissions in the Descriptors Store.
*
* @param permission Permission we want to create
* @exception ServiceAccessException Error accessing the Descriptors Store
*/
public void grantPermission(Uri uri, NodePermission permission)
throws ServiceAccessException {
NodePermission tempPermission = permission.cloneObject();
tempPermission.validate(uri.toString());
enlist(securityStore);
try {
securityStore.grantPermission(uri, tempPermission);
} catch (ServiceAccessException e) {
delist(securityStore, false);
throw e;
} catch (Throwable t) {
delist(securityStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException(securityStore, t);
}
delist(securityStore);
}
/**
* Store an object permissions in the Descriptors Store.
*
* @param permission Permission we want to create
* @exception ServiceAccessException Error accessing the Descriptors Store
*/
public void revokePermission(Uri uri, NodePermission permission)
throws ServiceAccessException {
permission.validate(uri.toString());
enlist(securityStore);
try {
securityStore.revokePermission(uri, permission);
} catch (ServiceAccessException e) {
delist(securityStore, false);
throw e;
} catch (Throwable t) {
delist(securityStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException(securityStore, t);
}
delist(securityStore);
}
/**
* Revoke all the permissions on the object.
*
* @param uri Uri of the object
* @exception ServiceAccessException Error accessing the Descriptors Store
*/
public void revokePermissions(Uri uri)
throws ServiceAccessException {
enlist(securityStore);
try {
securityStore.revokePermissions(uri);
} catch (ServiceAccessException e) {
delist(securityStore, false);
throw e;
} catch (Throwable t) {
delist(securityStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException(securityStore, t);
}
delist(securityStore);
}
/**
* Enumerate locks on an object.
*
* @param uri Uri of the subject
* @return Enumeration List of {@link org.apache.slide.lock.NodeLock locks}
* which have been put on the subject
* @exception ServiceAccessException Service access error
*/
public Enumeration enumeratePermissions(Uri uri)
throws ServiceAccessException {
// TODO : The vectors elements MUST be cloned
if (isForceStoreEnlistment(uri)) {
enlist(securityStore);
Enumeration permissions = null;
try {
permissions = securityStore.enumeratePermissions(uri);
} catch (ServiceAccessException e) {
delist(securityStore, false);
throw e;
} catch (Throwable t) {
delist(securityStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException
(securityStore, t);
}
delist(securityStore);
return permissions;
} else {
try {
return securityStore.enumeratePermissions(uri);
} catch (ServiceAccessException e) {
throw e;
} catch (Throwable t) {
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException
(securityStore, t);
}
}
}
/**
* Puts a lock on a subject.
*
* @param lock Lock token
* @exception ServiceAccessException Service access error
*/
public void putLock(Uri uri, NodeLock lock)
throws ServiceAccessException {
lock.validate(uri.toString());
enlist(lockStore);
try {
lockStore.putLock(uri, lock);
} catch (ServiceAccessException e) {
delist(lockStore, false);
throw e;
} catch (Throwable t) {
delist(lockStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException(lockStore, t);
}
delist(lockStore);
}
/**
* Renews a lock.
*
* @param lock Token to renew
* @exception ServiceAccessException Service access error
* @exception LockTokenNotFoundException Lock token was not found
*/
public void renewLock(Uri uri, NodeLock lock)
throws ServiceAccessException, LockTokenNotFoundException {
lock.validate(uri.toString());
enlist(lockStore);
try {
lockStore.renewLock(uri, lock);
} catch (ServiceAccessException e) {
delist(lockStore, false);
throw e;
} catch (LockTokenNotFoundException e) {
delist(lockStore);
throw e;
} catch (Throwable t) {
delist(lockStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException(lockStore, t);
}
delist(lockStore);
}
/**
* Removes (cancels) a lock.
*
* @param lock Token to remove
* @exception ServiceAccessException Service access error
* @exception LockTokenNotFoundException Lock token was not found
*/
public void removeLock(Uri uri, NodeLock lock)
throws ServiceAccessException, LockTokenNotFoundException {
lock.validate(uri.toString());
enlist(lockStore);
try {
lockStore.removeLock(uri, lock);
} catch (ServiceAccessException e) {
delist(lockStore, false);
throw e;
} catch (LockTokenNotFoundException e) {
delist(lockStore);
throw e;
} catch (Throwable t) {
delist(lockStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException(lockStore, t);
}
delist(lockStore);
}
/**
* Kills a lock.
*
* @param lock Token to remove
* @exception ServiceAccessException Service access error
* @exception LockTokenNotFoundException Lock token was not found
*/
public void killLock(Uri uri, NodeLock lock)
throws ServiceAccessException, LockTokenNotFoundException {
lock.validate(uri.toString());
enlist(lockStore);
try {
lockStore.killLock(uri, lock);
} catch (ServiceAccessException e) {
delist(lockStore, false);
throw e;
} catch (LockTokenNotFoundException e) {
delist(lockStore);
throw e;
} catch (Throwable t) {
delist(lockStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException(lockStore, t);
}
delist(lockStore);
}
/**
* Enumerate locks on an object.
*
* @param uri Uri of the subject
* @return Enumeration List of {@link org.apache.slide.lock.NodeLock locks}
* which have been put on the subject
* @exception ServiceAccessException Service access error
*/
public Enumeration enumerateLocks(Uri uri)
throws ServiceAccessException {
if (isForceStoreEnlistment(uri)) {
enlist(lockStore);
Enumeration locks = null;
try {
locks = lockStore.enumerateLocks(uri);
} catch (ServiceAccessException e) {
delist(lockStore, false);
throw e;
} catch (Throwable t) {
delist(lockStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException(lockStore, t);
}
delist(lockStore);
return locks;
} else {
try {
return lockStore.enumerateLocks(uri);
} catch (ServiceAccessException e) {
throw e;
} catch (Throwable t) {
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException(lockStore, t);
}
}
}
/**
* Retrieve a revision descriptors.
*
* @param uri Uri
* @exception ServiceAccessException Service access error
* @exception RevisionDescriptorNotFoundException Revision descriptor
* was not found
*/
public NodeRevisionDescriptors retrieveRevisionDescriptors(Uri uri)
throws ServiceAccessException, RevisionDescriptorNotFoundException {
NodeRevisionDescriptors revisionDescriptors = null;
if (isForceStoreEnlistment(uri)) {
enlist(revisionDescriptorsStore);
try {
revisionDescriptors =
revisionDescriptorsStore.retrieveRevisionDescriptors(uri);
} catch (ServiceAccessException e) {
delist(revisionDescriptorsStore, false);
throw e;
} catch (RevisionDescriptorNotFoundException e) {
// Normal read failures aren't considered fatal
delist(revisionDescriptorsStore);
throw e;
} catch (Throwable t) {
delist(revisionDescriptorsStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException
(revisionDescriptorsStore, t);
}
delist(revisionDescriptorsStore);
} else {
try {
revisionDescriptors =
revisionDescriptorsStore.retrieveRevisionDescriptors(uri);
} catch (ServiceAccessException e) {
throw e;
} catch (RevisionDescriptorNotFoundException e) {
throw e;
} catch (Throwable t) {
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException
(revisionDescriptorsStore, t);
}
}
revisionDescriptors.validate(uri.toString());
return revisionDescriptors;
}
/**
* Create new revision descriptors.
*
* @param uri Uri
* @param revisionDescriptors Node revision descriptors
* @exception ServiceAccessException Service access error
*/
public void createRevisionDescriptors
(Uri uri, NodeRevisionDescriptors revisionDescriptors)
throws ServiceAccessException {
revisionDescriptors.validate(uri.toString());
enlist(revisionDescriptorsStore);
try {
revisionDescriptorsStore.createRevisionDescriptors
(uri, revisionDescriptors);
} catch (ServiceAccessException e) {
delist(revisionDescriptorsStore, false);
throw e;
} catch (Throwable t) {
delist(revisionDescriptorsStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException
(revisionDescriptorsStore, t);
}
delist(revisionDescriptorsStore);
}
/**
* Update revision descriptors.
*
* @param uri Uri
* @param revisionDescriptors Node revision descriptors
* @exception ServiceAccessException Service access error
* @exception RevisionDescriptorNotFoundException Revision descriptor
* was not found
*/
public void storeRevisionDescriptors
(Uri uri, NodeRevisionDescriptors revisionDescriptors)
throws ServiceAccessException, RevisionDescriptorNotFoundException {
revisionDescriptors.validate(uri.toString());
enlist(revisionDescriptorsStore);
try {
revisionDescriptorsStore.storeRevisionDescriptors
(uri, revisionDescriptors);
} catch (ServiceAccessException e) {
delist(revisionDescriptorsStore, false);
throw e;
} catch (RevisionDescriptorNotFoundException e) {
delist(revisionDescriptorsStore);
throw e;
} catch (Throwable t) {
delist(revisionDescriptorsStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException
(revisionDescriptorsStore, t);
}
delist(revisionDescriptorsStore);
}
/**
* Remove revision descriptors.
*
* @param uri Uri
* @exception ServiceAccessException Service access error
*/
public void removeRevisionDescriptors(Uri uri)
throws ServiceAccessException {
enlist(revisionDescriptorsStore);
try {
revisionDescriptorsStore.removeRevisionDescriptors(uri);
} catch (ServiceAccessException e) {
delist(revisionDescriptorsStore, false);
throw e;
} catch (Throwable t) {
delist(revisionDescriptorsStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException
(revisionDescriptorsStore, t);
}
delist(revisionDescriptorsStore);
}
/**
* Retrieve revision descriptor.
*
* @param uri uri
* @param revisionNumber Node revision number
*/
public NodeRevisionDescriptor retrieveRevisionDescriptor
(Uri uri, NodeRevisionNumber revisionNumber)
throws ServiceAccessException, RevisionDescriptorNotFoundException {
NodeRevisionDescriptor revisionDescriptor = null;
if (isForceStoreEnlistment(uri)) {
enlist(revisionDescriptorStore);
try {
revisionDescriptor =
revisionDescriptorStore.retrieveRevisionDescriptor
(uri, revisionNumber);
} catch (ServiceAccessException e) {
delist(revisionDescriptorStore, false);
throw e;
} catch (RevisionDescriptorNotFoundException e) {
// Normal read failures aren't considered fatal
delist(revisionDescriptorStore);
throw e;
} catch (Throwable t) {
delist(revisionDescriptorStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException
(revisionDescriptorStore, t);
}
delist(revisionDescriptorStore);
} else {
try {
revisionDescriptor =
revisionDescriptorStore.retrieveRevisionDescriptor
(uri, revisionNumber);
} catch (ServiceAccessException e) {
throw e;
} catch (RevisionDescriptorNotFoundException e) {
throw e;
} catch (Throwable t) {
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException
(revisionDescriptorStore, t);
}
}
revisionDescriptor.validate();
return revisionDescriptor;
}
/**
* Create new revision descriptor.
*
* @param uri Uri
* @param revisionDescriptor Node revision descriptor
* @exception ServiceAccessException Service access error
*/
public void createRevisionDescriptor
(Uri uri, NodeRevisionDescriptor revisionDescriptor)
throws ServiceAccessException {
revisionDescriptor.validate();
enlist(revisionDescriptorStore);
try {
revisionDescriptorStore.createRevisionDescriptor
(uri, revisionDescriptor);
} catch (ServiceAccessException e) {
delist(revisionDescriptorStore, false);
throw e;
} catch (Throwable t) {
delist(revisionDescriptorStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException
(revisionDescriptorStore, t);
}
delist(revisionDescriptorStore);
}
/**
* Update revision descriptor.
*
* @param uri Uri
* @param revisionDescriptor Node revision descriptor
* @exception ServiceAccessException Service access error
* @exception RevisionDescriptorNotFoundException Revision descriptor
* was not found
*/
public void storeRevisionDescriptor
(Uri uri, NodeRevisionDescriptor revisionDescriptor)
throws ServiceAccessException, RevisionDescriptorNotFoundException {
revisionDescriptor.validate();
enlist(revisionDescriptorStore);
try {
revisionDescriptorStore.storeRevisionDescriptor
(uri, revisionDescriptor);
} catch (ServiceAccessException e) {
delist(revisionDescriptorStore, false);
throw e;
} catch (RevisionDescriptorNotFoundException e) {
delist(revisionDescriptorStore);
throw e;
} catch (Throwable t) {
delist(revisionDescriptorStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException
(revisionDescriptorStore, t);
}
delist(revisionDescriptorStore);
}
/**
* Remove revision descriptor.
*
* @param uri Uri
* @param revisionNumber Revision number
* @exception ServiceAccessException Service access error
*/
public void removeRevisionDescriptor(Uri uri, NodeRevisionNumber revisionNumber)
throws ServiceAccessException {
revisionNumber.validate();
enlist(revisionDescriptorStore);
try {
revisionDescriptorStore.removeRevisionDescriptor(uri, revisionNumber);
} catch (ServiceAccessException e) {
delist(revisionDescriptorStore, false);
throw e;
} catch (Throwable t) {
delist(revisionDescriptorStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException
(revisionDescriptorStore, t);
}
delist(revisionDescriptorStore);
}
/**
* Retrive revision content.
*
* @param uri Uri
* @param revisionDescriptor Node revision descriptor
*/
public NodeRevisionContent retrieveRevisionContent
(Uri uri, NodeRevisionDescriptor revisionDescriptor)
throws ServiceAccessException, RevisionNotFoundException {
NodeRevisionContent revisionContent = null;
if (isForceStoreEnlistment(uri)) {
enlist(contentStore);
try {
revisionContent =
contentStore.retrieveRevisionContent
(uri, revisionDescriptor);
} catch (ServiceAccessException e) {
delist(contentStore, false);
throw e;
} catch (RevisionNotFoundException e) {
// Normal read failures aren't considered fatal
delist(contentStore);
throw e;
} catch (Throwable t) {
delist(contentStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException
(contentStore, t);
}
delist(contentStore);
} else {
try {
revisionContent =
contentStore.retrieveRevisionContent
(uri, revisionDescriptor);
} catch (ServiceAccessException e) {
throw e;
} catch (RevisionNotFoundException e) {
throw e;
} catch (Throwable t) {
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException
(contentStore, t);
}
}
revisionContent.validate();
return revisionContent;
}
/**
* Create a new revision
*
* @param uri Uri
* @param revisionDescriptor Node revision descriptor
* @param revisionContent Node revision content
*/
public void createRevisionContent
(Uri uri, NodeRevisionDescriptor revisionDescriptor,
NodeRevisionContent revisionContent)
throws ServiceAccessException, RevisionAlreadyExistException {
revisionDescriptor.validate();
revisionContent.validate();
enlist(contentStore);
try {
contentStore.createRevisionContent(uri, revisionDescriptor,
revisionContent);
} catch (ServiceAccessException e) {
delist(contentStore, false);
throw e;
} catch (RevisionAlreadyExistException e) {
delist(contentStore);
throw e;
} catch (Throwable t) {
delist(contentStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException(contentStore, t);
}
delist(contentStore);
}
/**
* Modify the latest revision of an object.
*
* @param uri Uri
* @param revisionDescriptor Node revision descriptor
* @param revisionContent Node revision content
*/
public void storeRevisionContent
(Uri uri, NodeRevisionDescriptor revisionDescriptor,
NodeRevisionContent revisionContent)
throws ServiceAccessException, RevisionNotFoundException {
revisionDescriptor.validate();
revisionContent.validate();
enlist(contentStore);
try {
contentStore.storeRevisionContent(uri, revisionDescriptor,
revisionContent);
} catch (ServiceAccessException e) {
delist(contentStore, false);
throw e;
} catch (RevisionNotFoundException e) {
delist(contentStore);
throw e;
} catch (Throwable t) {
delist(contentStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException(contentStore, t);
}
delist(contentStore);
}
/**
* Remove revision.
*
* @param uri Uri
* @param revisionDescriptor Node revision descriptor
*/
public void removeRevisionContent
(Uri uri, NodeRevisionDescriptor revisionDescriptor)
throws ServiceAccessException {
revisionDescriptor.validate();
enlist(contentStore);
try {
contentStore.removeRevisionContent(uri, revisionDescriptor);
} catch (ServiceAccessException e) {
delist(contentStore, false);
throw e;
} catch (Throwable t) {
delist(contentStore, false);
// Wrap everything else in a ServiceAccessException
throw new ServiceAccessException(contentStore, t);
}
delist(contentStore);
}
// ------------------------------------------------------ Protected Methods
/**
* Return true if the store should also be enlisted for a read operation.
*/
protected boolean isForceStoreEnlistment(Uri uri) {
SlideToken token = uri.getToken();
if (token == null)
return false;
return token.isForceStoreEnlistment();
}
/**
* Add a new resource manager.
*
* @param service New resource manager
*/
protected void addResourceManager(Service service) {
if (service == null)
return;
// First check if the new store isn't already in the array
for (int i = 0; i < resourceManagers.length; i++) {
try {
if (resourceManagers[i].isSameRM(service))
return;
} catch (XAException e) {
}
}
Service results[] = new Service[resourceManagers.length + 1];
System.arraycopy(resourceManagers, 0, results, 0,
resourceManagers.length);
results[resourceManagers.length] = service;
resourceManagers = results;
}
/**
* Enlist the resource manager in the current transaction.
*/
protected void enlist()
throws ServiceAccessException {
enlist(this);
}
/**
* Enlist the resource manager in the current transaction.
*/
protected void enlist(Service service)
throws ServiceAccessException {
// Note: No exception is thrown
boolean enlisted = false;
// FIXME : Enhance retries.
int nbTry = 0;
while ((!enlisted) && (nbTry++ < 20)) {
Transaction transaction = null;
try {
transaction =
namespace.getTransactionManager().getTransaction();
} catch (Exception e) {
}
if (transaction == null) {
getLogger().log("WARNING: No active transaction", Logger.WARNING);
return;
}
try {
enlisted = transaction.enlistResource(service);
} catch (Exception e) {
// Something went wrong.
setRollbackOnly();
throw new ServiceAccessException(this, e);
}
if (!enlisted) {
try {
Thread.sleep(200);
} catch (InterruptedException e) {
// Then go on.
}
}
}
if (!enlisted) {
String exMessage = Messages.format
(AbstractStore.class.getName() + ".enlistFail", service);
setRollbackOnly();
throw new ServiceAccessException(this, exMessage);
}
if (getLogger().isEnabled(LOG_CHANNEL, Logger.DEBUG)) {
String logMessage = Messages.format
(AbstractStore.class.getName() + ".enlist", service);
getLogger().log(logMessage, LOG_CHANNEL, Logger.DEBUG);
}
}
/**
* Delist (suspend) the resource manager in the current transaction.
*/
protected void delist(boolean success)
throws ServiceAccessException {
delist(this, success);
}
/**
* Delist (suspend) the resource manager in the current transaction.
*/
protected void delist(Service service)
throws ServiceAccessException {
delist(service, true);
}
/**
* Delist (suspend) the resource manager in the current transaction.
*/
protected void delist(Service service, boolean success)
throws ServiceAccessException {
try {
Transaction transaction =
namespace.getTransactionManager().getTransaction();
if (transaction == null)
return;
if (success) {
transaction.delistResource(service, TMSUSPEND);
if (getLogger().isEnabled(LOG_CHANNEL, Logger.DEBUG)) {
String logMessage = Messages.format
(AbstractStore.class.getName() + ".delist", service);
getLogger().log(logMessage, LOG_CHANNEL, Logger.DEBUG);
}
} else {
transaction.delistResource(service, TMFAIL);
String logMessage = Messages.format
(AbstractStore.class.getName() + ".delistFail", service);
getLogger().log(logMessage, LOG_CHANNEL, Logger.DEBUG);
}
} catch (Exception e) {
// Something went wrong.
throw new ServiceAccessException(this, e.getMessage());
}
}
/**
* Mark transaction as rollback in case of enlistment failure.
*/
protected void setRollbackOnly() {
try {
Transaction transaction =
namespace.getTransactionManager().getTransaction();
if (transaction == null)
return;
transaction.setRollbackOnly();
} catch (Exception e) {
}
}
/**
* Always returns false. Default implementation for this method
* Stores that support binding should override this method.
*/
public boolean useBinding() {
return false;
}
}