Java tutorial
/* * $Header: /var/chroot/cvs/cvs/factsheetDesigner/extern/jakarta-slide-server-src-2.1-iPlus Edit/src/stores/org/apache/slide/store/txfile/TxXMLFileDescriptorsStore.java,v 1.2 2006-01-22 22:49:06 peter-cvs Exp $ * $Revision: 1.2 $ * $Date: 2006-01-22 22:49:06 $ * * ==================================================================== * * 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.txfile; import org.apache.commons.transaction.file.ResourceManager; import org.apache.commons.transaction.file.ResourceManagerException; import org.apache.slide.common.*; import org.apache.slide.store.*; import org.apache.slide.structure.*; import org.apache.slide.security.*; import org.apache.slide.util.logger.Logger; import org.apache.slide.lock.*; import org.apache.slide.content.*; import java.util.Collection; import java.util.Enumeration; import java.util.HashMap; import java.util.Hashtable; import java.util.Iterator; import java.util.Map; import javax.transaction.xa.XAException; import javax.transaction.xa.Xid; /** * Transactional descriptors file store. * Represents descriptor data as XML using {@link XMLResourceDescriptor}. * * <br><br> * <em>Note</em>: To achieve search performance on properties comparable to a RDBMS some sort of index will be needed. * * @see XMLResourceDescriptor */ public class TxXMLFileDescriptorsStore extends AbstractTxFileStoreService implements NodeStore, LockStore, RevisionDescriptorsStore, RevisionDescriptorStore, SecurityStore { protected static final String LOG_CHANNEL = "file-meta-store"; protected static final int DEBUG_LEVEL = Logger.DEBUG; protected static final String ENCODING_PARAMETER = "encoding"; protected static final String DEFER_SAVING_PARAMETER = "defer-saving"; protected String characterEncoding = "UTF-8"; // a save choice protected boolean deferSaving = false; // the save choice protected Map suspendedContexts = new HashMap(); protected Map activeContexts = new HashMap(); public void setParameters(Hashtable parameters) throws ServiceParameterErrorException, ServiceParameterMissingException { super.setParameters(parameters); String encoding = (String) parameters.get(ENCODING_PARAMETER); if (encoding != null) { characterEncoding = encoding; } String deferSavingString = (String) parameters.get(DEFER_SAVING_PARAMETER); if (deferSavingString != null) { deferSaving = Boolean.valueOf(deferSavingString).booleanValue(); if (deferSaving) { getLogger().log("Enabling deferred saving", LOG_CHANNEL, Logger.INFO); } } } /* * --- public methods of interface NodeStore --- * * */ public ObjectNode retrieveObject(Uri uri) throws ServiceAccessException, ObjectNotFoundException { XMLResourceDescriptor xfd = getFileDescriptor(uri); ObjectNode object = xfd.retrieveObject(); return object; } public void storeObject(Uri uri, ObjectNode object) throws ServiceAccessException, ObjectNotFoundException { XMLResourceDescriptor xfd = getFileDescriptor(uri); xfd.storeObject(object); if (deferSaving) { xfd.registerForSaving(); } else { xfd.save(); } } public void createObject(Uri uri, ObjectNode object) throws ServiceAccessException, ObjectAlreadyExistsException { try { XMLResourceDescriptor xfd = getFileDescriptor(uri); xfd.create(); xfd.storeObject(object); if (deferSaving) { xfd.registerForSaving(); TxContext txContext = getActiveTxContext(); if (txContext != null) { txContext.register(uri, xfd); } } else { xfd.save(); } } catch (ObjectNotFoundException e) { // should not happen, if it does, it is an error inside this store: throwInternalError("Newly created file vanished"); } } public void removeObject(Uri uri, ObjectNode object) throws ServiceAccessException, ObjectNotFoundException { XMLResourceDescriptor xfd = getFileDescriptor(uri); xfd.delete(); if (deferSaving) { TxContext txContext = getActiveTxContext(); if (txContext != null) { txContext.deregister(uri); } } } /* * --- public methods of interface SecurityStore --- * * */ public void grantPermission(Uri uri, NodePermission permission) throws ServiceAccessException { try { XMLResourceDescriptor xfd = getFileDescriptor(uri); xfd.grantPermission(permission); if (deferSaving) { xfd.registerForSaving(); } else { xfd.save(); } } catch (ObjectNotFoundException e) { throwInternalError(e); } } public void revokePermission(Uri uri, NodePermission permission) throws ServiceAccessException { try { XMLResourceDescriptor xfd = getFileDescriptor(uri); xfd.revokePermission(permission); if (deferSaving) { xfd.registerForSaving(); } else { xfd.save(); } } catch (ObjectNotFoundException e) { throwInternalError(e); } } public void revokePermissions(Uri uri) throws ServiceAccessException { try { XMLResourceDescriptor xfd = getFileDescriptor(uri); xfd.revokePermissions(); if (deferSaving) { xfd.registerForSaving(); } else { xfd.save(); } } catch (ObjectNotFoundException e) { throwInternalError(e); } } public Enumeration enumeratePermissions(Uri uri) throws ServiceAccessException { try { XMLResourceDescriptor xfd = getFileDescriptor(uri); return xfd.enumeratePermissions(); } catch (ObjectNotFoundException e) { throwInternalError(e); return null; // XXX fake (is never called) } } /* * --- public methods of interface LockStore --- * * */ public void putLock(Uri uri, NodeLock lock) throws ServiceAccessException { try { XMLResourceDescriptor xfd = getFileDescriptor(uri); xfd.putLock(lock); if (deferSaving) { xfd.registerForSaving(); } else { xfd.save(); } } catch (ObjectNotFoundException e) { throwInternalError(e); } } public void renewLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException { try { XMLResourceDescriptor xfd = getFileDescriptor(uri); xfd.renewLock(lock); if (deferSaving) { xfd.registerForSaving(); } else { xfd.save(); } } catch (ObjectNotFoundException e) { throwInternalError(e); } } public void removeLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException { try { XMLResourceDescriptor xfd = getFileDescriptor(uri); xfd.removeLock(lock); if (deferSaving) { xfd.registerForSaving(); } else { xfd.save(); } } catch (ObjectNotFoundException e) { throw new LockTokenNotFoundException(lock); } } public void killLock(Uri uri, NodeLock lock) throws ServiceAccessException, LockTokenNotFoundException { removeLock(uri, lock); } public Enumeration enumerateLocks(Uri uri) throws ServiceAccessException { try { XMLResourceDescriptor xfd = getFileDescriptor(uri); return xfd.enumerateLocks(); } catch (ObjectNotFoundException e) { throwInternalError(e); return null; // XXX fake (is never called) } } /* * --- public methods of interface RevisionDescriptorsStore --- * * */ public NodeRevisionDescriptors retrieveRevisionDescriptors(Uri uri) throws ServiceAccessException, RevisionDescriptorNotFoundException { try { XMLResourceDescriptor xfd = getFileDescriptor(uri); return xfd.retrieveRevisionDescriptors(); } catch (ObjectNotFoundException e) { throw new RevisionDescriptorNotFoundException(uri.toString()); } } public void createRevisionDescriptors(Uri uri, NodeRevisionDescriptors revisionDescriptors) throws ServiceAccessException { try { XMLResourceDescriptor xfd = getFileDescriptor(uri); xfd.createRevisionDescriptors(revisionDescriptors); if (deferSaving) { xfd.registerForSaving(); } else { xfd.save(); } } catch (ObjectNotFoundException e) { throwInternalError(e); } } public void storeRevisionDescriptors(Uri uri, NodeRevisionDescriptors revisionDescriptors) throws ServiceAccessException, RevisionDescriptorNotFoundException { try { XMLResourceDescriptor xfd = getFileDescriptor(uri); xfd.storeRevisionDescriptors(revisionDescriptors); if (deferSaving) { xfd.registerForSaving(); } else { xfd.save(); } } catch (ObjectNotFoundException e) { throw new RevisionDescriptorNotFoundException(uri.toString()); } } public void removeRevisionDescriptors(Uri uri) throws ServiceAccessException { try { XMLResourceDescriptor xfd = getFileDescriptor(uri); xfd.removeRevisionDescriptors(); if (deferSaving) { xfd.registerForSaving(); } else { xfd.save(); } } catch (ObjectNotFoundException e) { throwInternalError(e); } } /* * --- public methods of interface RevisionDescriptorStore --- * * */ public NodeRevisionDescriptor retrieveRevisionDescriptor(Uri uri, NodeRevisionNumber revisionNumber) throws ServiceAccessException, RevisionDescriptorNotFoundException { try { XMLResourceDescriptor xfd = getFileDescriptor(uri); return xfd.retrieveRevisionDescriptor(revisionNumber); } catch (ObjectNotFoundException e) { throw new RevisionDescriptorNotFoundException(uri.toString()); } } public void createRevisionDescriptor(Uri uri, NodeRevisionDescriptor revisionDescriptor) throws ServiceAccessException { try { XMLResourceDescriptor xfd = getFileDescriptor(uri); xfd.createRevisionDescriptor(revisionDescriptor); if (deferSaving) { xfd.registerForSaving(); } else { xfd.save(); } } catch (ObjectNotFoundException e) { throwInternalError(e); } } public void storeRevisionDescriptor(Uri uri, NodeRevisionDescriptor revisionDescriptor) throws ServiceAccessException, RevisionDescriptorNotFoundException { try { XMLResourceDescriptor xfd = getFileDescriptor(uri); xfd.storeRevisionDescriptor(revisionDescriptor); if (deferSaving) { xfd.registerForSaving(); } else { xfd.save(); } } catch (ObjectNotFoundException e) { throw new RevisionDescriptorNotFoundException(uri.toString()); } } public void removeRevisionDescriptor(Uri uri, NodeRevisionNumber number) throws ServiceAccessException { try { XMLResourceDescriptor xfd = getFileDescriptor(uri); xfd.removeRevisionDescriptor(number); if (deferSaving) { xfd.registerForSaving(); } else { xfd.save(); } } catch (ObjectNotFoundException e) { throwInternalError(e); } } public String toString() { return "TxXMLFileDescriptorsStore at " + storeDir + " working on " + workDir; } public synchronized void commit(Xid xid, boolean onePhase) throws XAException { try { super.commit(xid, onePhase); } finally { Object txId = wrap(xid); activeContexts.remove(txId); suspendedContexts.remove(txId); activeTransactionBranch.set(null); } } public synchronized void rollback(Xid xid) throws XAException { try { super.rollback(xid); } finally { Object txId = wrap(xid); activeContexts.remove(txId); suspendedContexts.remove(txId); activeTransactionBranch.set(null); } } public synchronized int prepare(Xid xid) throws XAException { Object txId = wrap(xid); getLogger().log("Thread " + Thread.currentThread() + " prepares transaction branch " + txId, LOG_CHANNEL, Logger.DEBUG); try { if (deferSaving) { // save all descriptors registered for saving TxContext txContext = (TxContext) activeContexts.get(txId); if (txContext == null) txContext = (TxContext) suspendedContexts.get(txId); // really should not, but only to be sure... if (txContext != null) { try { txContext.saveDescriptors(); } catch (ObjectNotFoundException onfe) { getLogger().log("Thread " + Thread.currentThread() + " failed to prepare transaction branch " + txId, onfe, LOG_CHANNEL, Logger.CRITICAL); throw new XAException(onfe.toString()); } catch (ServiceAccessException sae) { getLogger().log("Thread " + Thread.currentThread() + " failed to prepare transaction branch " + txId, sae, LOG_CHANNEL, Logger.CRITICAL); throw new XAException(sae.toString()); } } else { getLogger().log("Thread " + Thread.currentThread() + " could prepare *unknown* transaction branch " + txId, LOG_CHANNEL, Logger.WARNING); } } int status = rm.prepareTransaction(txId); switch (status) { case ResourceManager.PREPARE_SUCCESS_READONLY: return XA_RDONLY; case ResourceManager.PREPARE_SUCCESS: return XA_OK; default: throw new XAException(XAException.XA_RBROLLBACK); } } catch (ResourceManagerException e) { getLogger().log("Thread " + Thread.currentThread() + " failed to prepare transaction branch " + txId, e, LOG_CHANNEL, Logger.CRITICAL); throw createXAException(e); } } public synchronized void end(Xid xid, int flags) throws XAException { if (getActiveTxId() == null) { throw new XAException(XAException.XAER_INVAL); } Object txId = wrap(xid); Thread currentThread = Thread.currentThread(); getLogger().log("Thread " + currentThread + (flags == TMSUSPEND ? " suspends" : flags == TMFAIL ? " fails" : " ends") + " work on behalf of transaction branch " + txId, LOG_CHANNEL, DEBUG_LEVEL); switch (flags) { case TMSUSPEND: suspendedContexts.put(txId, getActiveTxContext()); activeContexts.remove(txId); activeTransactionBranch.set(null); break; case TMFAIL: try { rm.markTransactionForRollback(wrap(xid)); } catch (ResourceManagerException e) { throw createXAException(e); } activeTransactionBranch.set(null); break; case TMSUCCESS: activeTransactionBranch.set(null); break; } } public synchronized void start(Xid xid, int flags) throws XAException { Object txId = wrap(xid); Thread currentThread = Thread.currentThread(); getLogger().log("Thread " + currentThread + (flags == TMNOFLAGS ? " starts" : flags == TMJOIN ? " joins" : " resumes") + " work on behalf of transaction branch " + txId, LOG_CHANNEL, DEBUG_LEVEL); switch (flags) { // a new transaction case TMNOFLAGS: if (getActiveTxId() != null) { throw new XAException(XAException.XAER_INVAL); } try { rm.startTransaction(txId); TxContext txContext = new TxContext(txId); activeTransactionBranch.set(txContext); activeContexts.put(txId, txContext); } catch (ResourceManagerException e) { throw createXAException(e); } break; case TMJOIN: if (getActiveTxId() != null) { throw new XAException(XAException.XAER_INVAL); } try { if (rm.getTransactionState(txId) == STATUS_NO_TRANSACTION) { throw new XAException(XAException.XAER_INVAL); } } catch (ResourceManagerException e) { throw createXAException(e); } TxContext txContext = new TxContext(txId); activeTransactionBranch.set(txContext); activeContexts.put(txId, txContext); break; case TMRESUME: if (getActiveTxId() != null) { throw new XAException(XAException.XAER_INVAL); } txContext = (TxContext) suspendedContexts.remove(txId); if (txContext == null) { throw new XAException(XAException.XAER_NOTA); } activeTransactionBranch.set(txContext); break; } } /* * --- XMLFileDescriptor access and caching methods --- * * */ /** * Either returns a cached file descriptor or loads it from DB */ protected XMLResourceDescriptor getFileDescriptor(Uri uri) throws ServiceAccessException, ObjectNotFoundException { TxContext txContext = getActiveTxContext(); XMLResourceDescriptor xfd; if (txContext != null) { xfd = txContext.lookup(uri); if (xfd == null) { Object txId = txContext.xid; xfd = new XMLResourceDescriptor(uri, this, rm, txId, characterEncoding); xfd.load(); if (txId != null) { txContext.register(uri, xfd); } } } else { xfd = new XMLResourceDescriptor(uri, this, rm, null, characterEncoding); xfd.load(); } if (!xfd.getUri().equals(uri.toString())) { // this may happen with files systems that don't operate case sensitive // e.g. requested uri /files/test.doc but found /files/TEST.DOC throw new ObjectNotFoundException(uri); } return xfd; } protected TxContext getActiveTxContext() { TxContext context = (TxContext) activeTransactionBranch.get(); return context; } protected Object getActiveTxId() { TxContext context = (TxContext) activeTransactionBranch.get(); return (context == null ? null : context.xid); } protected String getLogChannel() { return LOG_CHANNEL; } private static class TxContext { public Object xid; public Map descriptors = new HashMap(); public TxContext(Object xid) { this.xid = xid; } public void register(Uri uri, XMLResourceDescriptor xfd) { descriptors.put(uri.toString(), xfd); } public void deregister(Uri uri) { descriptors.remove(uri.toString()); } public XMLResourceDescriptor lookup(Uri uri) { return (XMLResourceDescriptor) descriptors.get(uri.toString()); } public Collection list() { return descriptors.values(); } public void saveDescriptors() throws ObjectNotFoundException, ServiceAccessException { for (Iterator it = list().iterator(); it.hasNext();) { XMLResourceDescriptor xfd = (XMLResourceDescriptor) it.next(); if (xfd.isRegisteredForSaving()) xfd.save(); } } } }