You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@jackrabbit.apache.org by mr...@apache.org on 2006/12/05 13:46:16 UTC
svn commit: r482627 - in /jackrabbit/trunk:
jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/
jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/transaction/
jackrabbit-webapp/ jackrabbit-webapp/src/mai...
Author: mreutegg
Date: Tue Dec 5 04:46:14 2006
New Revision: 482627
URL: http://svn.apache.org/viewvc?view=rev&rev=482627
Log:
Work in progress
- Removed is-local flag from event bundle response and added transaction id which is equal to the lock token that was used to save changes.
- Added TransactionListener. SubscriptionManagerImpl now listens on the TxLockManagerImpl for transaction commits and registers special EventListeners for a short period of time to associate the lockToken / transactionId with an event bundle.
- Remove SubscriptionImpl as event listener when subscription expires
- Update currentVersion to 1.2-SNAPSHOT
Added:
jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/transaction/TransactionListener.java (with props)
Modified:
jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionImpl.java
jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionManagerImpl.java
jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/transaction/TxLockManagerImpl.java
jackrabbit/trunk/jackrabbit-webapp/project.xml
jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/JCRWebdavServerServlet.java
jackrabbit/trunk/jackrabbit-webdav/project.xml
jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/ObservationConstants.java
Modified: jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionImpl.java?view=diff&rev=482627&r1=482626&r2=482627
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionImpl.java Tue Dec 5 04:46:14 2006
@@ -20,6 +20,10 @@
import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.DavResourceLocator;
import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.transaction.TransactionResource;
+import org.apache.jackrabbit.webdav.jcr.transaction.TransactionListener;
+import org.apache.jackrabbit.webdav.jcr.JcrDavSession;
+import org.apache.jackrabbit.webdav.jcr.JcrDavException;
import org.apache.jackrabbit.webdav.observation.EventBundle;
import org.apache.jackrabbit.webdav.observation.EventDiscovery;
import org.apache.jackrabbit.webdav.observation.EventType;
@@ -36,9 +40,11 @@
import org.w3c.dom.Element;
import javax.jcr.RepositoryException;
+import javax.jcr.Session;
import javax.jcr.observation.Event;
import javax.jcr.observation.EventIterator;
import javax.jcr.observation.EventListener;
+import javax.jcr.observation.ObservationManager;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
@@ -92,6 +98,7 @@
private final DavResourceLocator locator;
private final String subscriptionId = UUID.randomUUID().toString();
private final List eventBundles = new ArrayList();
+ private final ObservationManager obsMgr;
/**
* Create a new <code>Subscription</code> with the given {@link SubscriptionInfo}
@@ -99,10 +106,19 @@
*
* @param info
* @param resource
+ * @throws DavException if resource is not based on a JCR repository or
+ * the repository does not support observation.
*/
- public SubscriptionImpl(SubscriptionInfo info, ObservationResource resource) {
+ public SubscriptionImpl(SubscriptionInfo info, ObservationResource resource)
+ throws DavException {
setInfo(info);
locator = resource.getLocator();
+ Session s = JcrDavSession.getRepositorySession(resource.getSession());
+ try {
+ obsMgr = s.getWorkspace().getObservationManager();
+ } catch (RepositoryException e) {
+ throw new DavException(DavServletResponse.SC_INTERNAL_SERVER_ERROR, e);
+ }
}
//-------------------------------------------------------< Subscription >---
@@ -261,19 +277,82 @@
return ed;
}
+ /**
+ * Creates a new transaction listener for the scope of a transaction
+ * commit (save call).
+ * @return a transaction listener for this subscription.
+ */
+ TransactionListener createTransactionListener() {
+ if (info.isNoLocal()) {
+ // a subscription which is not interested in local changes does
+ // not need the transaction id
+ return new TransactionEvent() {
+ public void onEvent(EventIterator events) {
+ // ignore
+ }
+
+ public void beforeCommit(TransactionResource resource, String lockToken) {
+ // ignore
+ }
+
+ public void afterCommit(TransactionResource resource,
+ String lockToken,
+ boolean success) {
+ // ignore
+ }
+ };
+ } else {
+ return new TransactionEvent();
+ }
+ }
+
+ /**
+ * Suspend this subscription. This call will remove this subscription as
+ * event listener from the observation manager.
+ */
+ void suspend() throws DavException {
+ try {
+ obsMgr.removeEventListener(this);
+ } catch (RepositoryException e) {
+ throw new JcrDavException(e);
+ }
+ }
+
+ /**
+ * Resumes this subscription. This call will register this subscription
+ * again as event listener to the observation manager.
+ */
+ void resume() throws DavException {
+ try {
+ obsMgr.addEventListener(this, getJcrEventTypes(),
+ getLocator().getRepositoryPath(), isDeep(), getUuidFilters(),
+ getNodetypeNameFilters(), isNoLocal());
+ } catch (RepositoryException e) {
+ throw new JcrDavException(e);
+ }
+ }
+
//--------------------------------------------< EventListener interface >---
/**
* Records the events passed as a new event bundle in order to make them
- * available with the next {@link #discoverEvents()} request.
+ * available with the next {@link #discoverEvents()} request. If this
+ * subscription is expired it will remove itself as listener from the
+ * observation manager.
*
* @param events to be recorded.
* @see EventListener#onEvent(EventIterator)
* @see #discoverEvents()
*/
public synchronized void onEvent(EventIterator events) {
- // TODO: correct not to accept events after expiration? without unsubscribing?
if (!isExpired()) {
eventBundles.add(new EventBundleImpl(events));
+ } else {
+ // expired -> unsubscribe
+ try {
+ obsMgr.removeEventListener(this);
+ } catch (RepositoryException e) {
+ log.warn("Exception while unsubscribing: " + e);
+ }
}
}
@@ -372,13 +451,22 @@
private final EventIterator events;
+ private final String transactionId;
+
private EventBundleImpl(EventIterator events) {
+ this(events, null);
+ }
+
+ private EventBundleImpl(EventIterator events, String transactionId) {
this.events = events;
+ this.transactionId = transactionId;
}
public Element toXml(Document document) {
Element bundle = DomUtil.createElement(document, XML_EVENTBUNDLE, NAMESPACE);
- DomUtil.setAttribute(bundle, XML_EVENT_IS_LOCAL, NAMESPACE, Boolean.toString(!info.isNoLocal()));
+ if (transactionId != null) {
+ DomUtil.setAttribute(bundle, XML_EVENT_TRANSACTION_ID, NAMESPACE, transactionId);
+ }
while (events.hasNext()) {
Event event = events.nextEvent();
Element eventElem = DomUtil.addChildElement(bundle, XML_EVENT, NAMESPACE);
@@ -399,6 +487,66 @@
DomUtil.addChildElement(eventElem, XML_EVENTUSERID, NAMESPACE, event.getUserID());
}
return bundle;
+ }
+ }
+
+ //----------------------------< TransactionEvent >------------------------
+
+ /**
+ * Implements a transaction event which listenes for events during a save
+ * call on the repository.
+ */
+ private class TransactionEvent implements EventListener, TransactionListener {
+
+ private String transactionId;
+
+ /**
+ * {@inheritDoc}
+ */
+ public void onEvent(EventIterator events) {
+ String tId = transactionId;
+ if (tId == null) {
+ tId = UUID.randomUUID().toString();
+ }
+ eventBundles.add(new EventBundleImpl(events, tId));
+ }
+
+ //-----------------------------< TransactionListener >------------------
+
+ /**
+ * {@inheritDoc}
+ */
+ public void beforeCommit(TransactionResource resource, String lockToken) {
+ try {
+ transactionId = lockToken;
+ obsMgr.addEventListener(this, getJcrEventTypes(),
+ getLocator().getRepositoryPath(), isDeep(), getUuidFilters(),
+ getNodetypeNameFilters(), isNoLocal());
+ // suspend the subscription
+ suspend();
+ } catch (RepositoryException e) {
+ log.warn("Unable to register TransactionListener: " + e);
+ } catch (DavException e) {
+ log.warn("Unable to register TransactionListener: " + e);
+ }
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void afterCommit(TransactionResource resource,
+ String lockToken,
+ boolean success) {
+ try {
+ // resume the subscription
+ resume();
+ // remove this transaction event
+ obsMgr.removeEventListener(this);
+ } catch (RepositoryException e) {
+ log.warn("Unable to remove listener: " + e);
+ } catch (DavException e) {
+ log.warn("Unable to resume Subscription: " + e);
+ }
}
}
}
Modified: jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionManagerImpl.java?view=diff&rev=482627&r1=482626&r2=482627
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionManagerImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/observation/SubscriptionManagerImpl.java Tue Dec 5 04:46:14 2006
@@ -19,8 +19,10 @@
import org.apache.jackrabbit.webdav.DavException;
import org.apache.jackrabbit.webdav.DavResourceLocator;
import org.apache.jackrabbit.webdav.DavServletResponse;
+import org.apache.jackrabbit.webdav.transaction.TransactionResource;
import org.apache.jackrabbit.webdav.jcr.JcrDavException;
import org.apache.jackrabbit.webdav.jcr.JcrDavSession;
+import org.apache.jackrabbit.webdav.jcr.transaction.TransactionListener;
import org.apache.jackrabbit.webdav.observation.EventDiscovery;
import org.apache.jackrabbit.webdav.observation.ObservationResource;
import org.apache.jackrabbit.webdav.observation.Subscription;
@@ -39,6 +41,9 @@
import java.util.HashSet;
import java.util.Iterator;
import java.util.Set;
+import java.util.Map;
+import java.util.List;
+import java.util.ArrayList;
/**
* <code>SubscriptionManager</code> collects all subscriptions requested, handles
@@ -46,7 +51,7 @@
* present on a given resource as well as events for an specific subscription.
*/
// todo: make sure all expired subscriptions are removed!
-public class SubscriptionManagerImpl implements SubscriptionManager {
+public class SubscriptionManagerImpl implements SubscriptionManager, TransactionListener {
private static Logger log = LoggerFactory.getLogger(SubscriptionManager.class);
@@ -55,6 +60,8 @@
*/
private final SubscriptionMap subscriptions = new SubscriptionMap();
+ private final Map transactionListenerById = new HashMap();
+
/**
* Retrieve the {@link org.apache.jackrabbit.webdav.observation.SubscriptionDiscovery}
* object for the given resource. Note, that the discovery object will be empty
@@ -227,6 +234,37 @@
return JcrDavSession.getRepositorySession(resource.getSession());
}
+ //---------------------------< TransactionListener >------------------------
+
+ /**
+ * {@inheritDoc}
+ */
+ public synchronized void beforeCommit(TransactionResource resource,
+ String lockToken) {
+ // suspend regular subscriptions during a commit
+ List transactionListeners = new ArrayList();
+ for (Iterator it = subscriptions.iterator(); it.hasNext(); ) {
+ SubscriptionImpl sub = (SubscriptionImpl) it.next();
+ TransactionListener tl = sub.createTransactionListener();
+ tl.beforeCommit(resource, lockToken);
+ transactionListeners.add(tl);
+ }
+ transactionListenerById.put(lockToken, transactionListeners);
+ }
+
+ /**
+ * {@inheritDoc}
+ */
+ public void afterCommit(TransactionResource resource, String lockToken, boolean success) {
+ List transactionListeners = (List) transactionListenerById.remove(lockToken);
+ if (transactionListeners != null) {
+ for (Iterator it = transactionListeners.iterator(); it.hasNext(); ) {
+ TransactionListener txListener = (TransactionListener) it.next();
+ txListener.afterCommit(resource, lockToken, success);
+ }
+ }
+ }
+
//----------------------------------------------< private inner classes >---
/**
* Private inner class wrapping around an <code>Subscription</code> as
@@ -269,6 +307,10 @@
return (Subscription) subscriptions.get(subscriptionId);
}
+ private Iterator iterator() {
+ return subscriptions.values().iterator();
+ }
+
private void put(String subscriptionId, SubscriptionImpl subscription) {
subscriptions.put(subscriptionId, subscription);
DavResourceLocator key = subscription.getLocator();
@@ -305,4 +347,4 @@
}
}
}
-}
\ No newline at end of file
+}
Added: jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/transaction/TransactionListener.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/transaction/TransactionListener.java?view=auto&rev=482627
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/transaction/TransactionListener.java (added)
+++ jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/transaction/TransactionListener.java Tue Dec 5 04:46:14 2006
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You 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.jackrabbit.webdav.jcr.transaction;
+
+import org.apache.jackrabbit.webdav.transaction.TransactionResource;
+
+/**
+ * <code>TransactionListener</code> provides callbacks when a transaction
+ * is committed.
+ */
+public interface TransactionListener {
+
+ /**
+ * This method is called right before a transaction is committed.
+ *
+ * @param resource the transaction resource which will be committed.
+ * @param lockToken the lock token
+ */
+ public void beforeCommit(TransactionResource resource, String lockToken);
+
+ /**
+ * This method is called after the commit has been executed.
+ *
+ * @param resource the transaction resource which had been committed.
+ * @param lockToken the lock token.
+ * @param success if the commit was successful.
+ */
+ public void afterCommit(TransactionResource resource, String lockToken, boolean success);
+}
Propchange: jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/transaction/TransactionListener.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/transaction/TxLockManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/transaction/TxLockManagerImpl.java?view=diff&rev=482627&r1=482626&r2=482627
==============================================================================
--- jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/transaction/TxLockManagerImpl.java (original)
+++ jackrabbit/trunk/jackrabbit-jcr-server/src/main/java/org/apache/jackrabbit/webdav/jcr/transaction/TxLockManagerImpl.java Tue Dec 5 04:46:14 2006
@@ -35,6 +35,7 @@
import org.apache.jackrabbit.webdav.transaction.TransactionResource;
import org.apache.jackrabbit.webdav.transaction.TxActiveLock;
import org.apache.jackrabbit.webdav.transaction.TxLockManager;
+import org.apache.commons.collections.set.MapBackedSet;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -47,6 +48,8 @@
import javax.transaction.xa.Xid;
import java.util.HashMap;
import java.util.Iterator;
+import java.util.Set;
+import java.util.IdentityHashMap;
/**
* <code>TxLockManagerImpl</code> manages locks with locktype
@@ -67,6 +70,8 @@
private TransactionMap map = new TransactionMap();
+ private Set listeners = MapBackedSet.decorate(new IdentityHashMap());
+
/**
* Create a new lock.
*
@@ -212,7 +217,25 @@
throw new DavException(DavServletResponse.SC_PRECONDITION_FAILED, "Transaction lock for resource '" + resource.getResourcePath() + "' was already expired.");
} else {
if (lockInfo.isCommit()) {
- tx.commit(resource);
+ TransactionListener[] txListeners;
+ synchronized (listeners) {
+ txListeners = (TransactionListener[]) listeners.toArray(new TransactionListener[0]);
+ }
+ for (int i = 0; i < txListeners.length; i++) {
+ txListeners[i].beforeCommit(resource, lockToken);
+ }
+ DavException ex = null;
+ try {
+ tx.commit(resource);
+ } catch (DavException e) {
+ ex = e;
+ }
+ for (int i = 0; i < txListeners.length; i++) {
+ txListeners[i].afterCommit(resource, lockToken, ex == null);
+ }
+ if (ex != null) {
+ throw ex;
+ }
} else {
tx.rollback(resource);
}
@@ -271,6 +294,28 @@
}
}
return lock;
+ }
+
+ //-----------------------------< listener support >-------------------------
+
+ /**
+ * Adds a transaction listener to this <code>TxLockManager</code>.
+ * @param listener the listener to add.
+ */
+ public void addTransactionListener(TransactionListener listener) {
+ synchronized (listeners) {
+ listeners.add(listener);
+ }
+ }
+
+ /**
+ * Removes a transaction listener from this <code>TxLockManager</code>.
+ * @param listener the listener to remove.
+ */
+ public void removeTransactionListener(TransactionListener listener) {
+ synchronized (listeners) {
+ listeners.remove(listener);
+ }
}
/**
Modified: jackrabbit/trunk/jackrabbit-webapp/project.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webapp/project.xml?view=diff&rev=482627&r1=482626&r2=482627
==============================================================================
--- jackrabbit/trunk/jackrabbit-webapp/project.xml (original)
+++ jackrabbit/trunk/jackrabbit-webapp/project.xml Tue Dec 5 04:46:14 2006
@@ -24,7 +24,7 @@
<artifactId>jackrabbit-webapp</artifactId>
<name>Jackrabbit WebApplication</name>
- <currentVersion>1.1-SNAPSHOT</currentVersion>
+ <currentVersion>1.2-SNAPSHOT</currentVersion>
<inceptionYear>2005</inceptionYear>
<package>org.apache.jackrabbit.*</package>
Modified: jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/JCRWebdavServerServlet.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/JCRWebdavServerServlet.java?view=diff&rev=482627&r1=482626&r2=482627
==============================================================================
--- jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/JCRWebdavServerServlet.java (original)
+++ jackrabbit/trunk/jackrabbit-webapp/src/main/java/org/apache/jackrabbit/j2ee/JCRWebdavServerServlet.java Tue Dec 5 04:46:14 2006
@@ -111,6 +111,7 @@
txMgr = new TxLockManagerImpl();
subscriptionMgr = new SubscriptionManagerImpl();
+ txMgr.addTransactionListener((SubscriptionManagerImpl) subscriptionMgr);
// todo: ev. make configurable
resourceFactory = new DavResourceFactoryImpl(txMgr, subscriptionMgr);
Modified: jackrabbit/trunk/jackrabbit-webdav/project.xml
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webdav/project.xml?view=diff&rev=482627&r1=482626&r2=482627
==============================================================================
--- jackrabbit/trunk/jackrabbit-webdav/project.xml (original)
+++ jackrabbit/trunk/jackrabbit-webdav/project.xml Tue Dec 5 04:46:14 2006
@@ -24,7 +24,7 @@
<artifactId>jackrabbit-webdav</artifactId>
<name>Jackrabbit Webdav Library</name>
- <currentVersion>1.1-SNAPSHOT</currentVersion>
+ <currentVersion>1.2-SNAPSHOT</currentVersion>
<inceptionYear>2005</inceptionYear>
<package>org.apache.jackrabbit.webdav.*</package>
Modified: jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/ObservationConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/ObservationConstants.java?view=diff&rev=482627&r1=482626&r2=482627
==============================================================================
--- jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/ObservationConstants.java (original)
+++ jackrabbit/trunk/jackrabbit-webdav/src/main/java/org/apache/jackrabbit/webdav/observation/ObservationConstants.java Tue Dec 5 04:46:14 2006
@@ -61,7 +61,7 @@
public static final String XML_EVENTDISCOVERY = "eventdiscovery";
public static final String XML_EVENTBUNDLE = "eventbundle";
- public static final String XML_EVENT_IS_LOCAL = "islocal";
+ public static final String XML_EVENT_TRANSACTION_ID = "transactionid";
public static final String XML_EVENT = "event";
public static final String XML_EVENTUSERID = "eventuserid";
@@ -71,4 +71,4 @@
* existing subscriptions present on the specified resource.
*/
public static final DavPropertyName SUBSCRIPTIONDISCOVERY = DavPropertyName.create("subscriptiondiscovery", NAMESPACE);
-}
\ No newline at end of file
+}