FELIX-2642 Adapt to implementation to R4.3 draft3 specification
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1067008 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/coordinator/src/main/java/org/apache/felix/coordination/impl/Activator.java b/coordinator/src/main/java/org/apache/felix/coordination/impl/Activator.java
index ca37fd9..7196ec4 100644
--- a/coordinator/src/main/java/org/apache/felix/coordination/impl/Activator.java
+++ b/coordinator/src/main/java/org/apache/felix/coordination/impl/Activator.java
@@ -24,8 +24,8 @@
import javax.management.MalformedObjectNameException;
import javax.management.ObjectName;
-import org.apache.felix.jmx.service.coordination.CoordinatorMBean;
-import org.apache.felix.service.coordination.Coordinator;
+import org.apache.felix.jmx.service.coordinator.CoordinatorMBean;
+import org.apache.felix.service.coordinator.Coordinator;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
diff --git a/coordinator/src/main/java/org/apache/felix/coordination/impl/CoordinationImpl.java b/coordinator/src/main/java/org/apache/felix/coordination/impl/CoordinationImpl.java
index 590ab9e..4e2010b 100644
--- a/coordinator/src/main/java/org/apache/felix/coordination/impl/CoordinationImpl.java
+++ b/coordinator/src/main/java/org/apache/felix/coordination/impl/CoordinationImpl.java
@@ -25,8 +25,9 @@
import java.util.Map;
import java.util.TimerTask;
-import org.apache.felix.service.coordination.Coordination;
-import org.apache.felix.service.coordination.Participant;
+import org.apache.felix.service.coordinator.Coordination;
+import org.apache.felix.service.coordinator.CoordinationException;
+import org.apache.felix.service.coordinator.Participant;
@SuppressWarnings("deprecation")
public class CoordinationImpl implements Coordination
@@ -41,9 +42,6 @@
/** Coordination completed */
private static final int TERMINATED = 3;
- /** Coordination failed */
- private static final int FAILED = 4;
-
private final CoordinatorImpl owner;
private final long id;
@@ -51,7 +49,7 @@
private final String name;
// TODO: timeout must be enforced
- private long timeOutInMs;
+ private long deadLine;
/**
* Access to this field must be synchronized as long as the expected state
@@ -61,8 +59,6 @@
*/
private volatile int state;
- private int mustFail;
-
private Throwable failReason;
private ArrayList<Participant> participants;
@@ -73,19 +69,25 @@
private Thread initiatorThread;
- public CoordinationImpl(final CoordinatorImpl owner, final long id, final String name, final long defaultTimeOutInMs)
+ public CoordinationImpl(final CoordinatorImpl owner, final long id, final String name, final int timeOutInMs)
{
+ // TODO: validate name against Bundle Symbolic Name pattern
+
this.owner = owner;
this.id = id;
this.name = name;
- this.mustFail = 0;
this.state = ACTIVE;
this.participants = new ArrayList<Participant>();
this.variables = new HashMap<Class<?>, Object>();
- this.timeOutInMs = -defaultTimeOutInMs;
+ this.deadLine = (timeOutInMs > 0) ? System.currentTimeMillis() + timeOutInMs : 0;
this.initiatorThread = Thread.currentThread();
- scheduleTimeout(defaultTimeOutInMs);
+ scheduleTimeout(deadLine);
+ }
+
+ public long getId()
+ {
+ return this.id;
}
public String getName()
@@ -93,154 +95,83 @@
return name;
}
- long getId()
- {
- return this.id;
- }
-
- void mustFail(final Throwable reason)
- {
- this.mustFail = FAILED;
- this.failReason = reason;
- }
-
- /**
- * Initiates a coordination timeout. Called from the timer task scheduled by
- * the {@link #scheduleTimeout(long)} method.
- * <p>
- * This method is inteded to only be called from the scheduled timer task.
- */
- void timeout()
- {
- // If a timeout happens, the coordination thread is set to always fail
- this.mustFail = TIMEOUT;
-
- // Fail the Coordination upon timeout
- fail(null);
- }
-
- long getTimeOut()
- {
- return this.timeOutInMs;
- }
-
- public int end() throws IllegalStateException
- {
- if (startTermination())
- {
- if (mustFail != 0)
- {
- failInternal();
- return mustFail;
- }
- return endInternal();
- }
-
- // already terminated
- throw new IllegalStateException();
- }
-
public boolean fail(Throwable reason)
{
if (startTermination())
{
this.failReason = reason;
- failInternal();
+
+ // consider failure reason (if not null)
+ for (Participant part : participants)
+ {
+ try
+ {
+ part.failed(this);
+ }
+ catch (Exception e)
+ {
+ // TODO: log
+ }
+
+ // release the participant for other coordinations
+ owner.releaseParticipant(part);
+ }
+
+ state = TERMINATED;
+
+ synchronized (this)
+ {
+ this.notifyAll();
+ }
+
return true;
}
return false;
}
- public boolean terminate()
+ public void end()
{
- if (state == ACTIVE)
+ if (startTermination())
{
- try
+ boolean partialFailure = false;
+ for (Participant part : participants)
{
- end();
- return true;
- }
- catch (IllegalStateException ise)
- {
- // another thread might have started the termination just
- // after the current thread checked the state but before the
- // end() method called on this thread was able to change the
- // state. Just ignore this exception and continue.
- }
- }
- return false;
- }
-
- /**
- * Returns whether the coordination has ended in failure.
- * <p>
- * The return value of <code>false</code> may be a transient situation if
- * the coordination is in the process of terminating due to a failure.
- */
- public boolean isFailed()
- {
- return state == FAILED;
- }
-
- /**
- * Returns whether the coordination has ended.
- * <p>
- * The return value of <code>false</code> may be a transient situation if
- * the coordination is in the process of terminating.
- */
- public boolean isTerminated()
- {
- return state == TERMINATED || state == FAILED;
- }
-
- public void addTimeout(long timeOutInMs)
- {
- if (this.timeOutInMs > 0)
- {
- // already set, ignore
- }
-
- this.timeOutInMs = timeOutInMs;
- scheduleTimeout(timeOutInMs);
- }
-
- /**
- * Adds the participant to the end of the list of participants of this
- * coordination.
- * <p>
- * This method blocks if the given participant is currently participating in
- * another coordination.
- * <p>
- * Participants can only be added to a coordination if it is active.
- *
- * @throws org.apache.felix.service.coordination.CoordinationException if
- * the participant cannot currently participate in this
- * coordination
- */
- public boolean participate(Participant p)
- {
-
- // ensure participant only pariticipates on a single coordination
- // this blocks until the participant can participate or until
- // a timeout occurrs (or a deadlock is detected)
- owner.lockParticipant(p, this);
-
- // synchronize access to the state to prevent it from being changed
- // while adding the participant
- synchronized (this)
- {
- if (state == ACTIVE)
- {
- if (!participants.contains(p))
+ try
{
- participants.add(p);
+ part.ended(this);
}
- return true;
+ catch (Exception e)
+ {
+ // TODO: log
+ partialFailure = true;
+ }
+
+ // release the participant for other coordinations
+ owner.releaseParticipant(part);
}
- return false;
+
+ state = TERMINATED;
+
+ synchronized (this)
+ {
+ this.notifyAll();
+ }
+
+ if (partialFailure)
+ {
+ throw new CoordinationException("One or more participants threw while ending the coordination", this,
+ CoordinationException.PARTIALLY_ENDED);
+ }
+ }
+ else
+ {
+ // already terminated
+ throw new CoordinationException("Coordination " + id + "/" + name + " has already terminated", this,
+ CoordinationException.ALREADY_ENDED);
}
}
+
public Collection<Participant> getParticipants()
{
// synchronize access to the state to prevent it from being changed
@@ -256,11 +187,131 @@
return Collections.<Participant> emptyList();
}
+ public Throwable getFailure()
+ {
+ return failReason;
+ }
+
+
+ /**
+ * Adds the participant to the end of the list of participants of this
+ * coordination.
+ * <p>
+ * This method blocks if the given participant is currently participating in
+ * another coordination.
+ * <p>
+ * Participants can only be added to a coordination if it is active.
+ *
+ * @throws org.apache.felix.service.coordination.CoordinationException if
+ * the participant cannot currently participate in this
+ * coordination
+ */
+ public void addParticipant(Participant p)
+ {
+
+ // ensure participant only pariticipates on a single coordination
+ // this blocks until the participant can participate or until
+ // a timeout occurrs (or a deadlock is detected)
+ owner.lockParticipant(p, this);
+
+ // synchronize access to the state to prevent it from being changed
+ // while adding the participant
+ synchronized (this)
+ {
+ if (isTerminated())
+ {
+ owner.releaseParticipant(p);
+
+ throw new CoordinationException("Cannot add Participant " + p + " to terminated Coordination", this,
+ (getFailure() != null) ? CoordinationException.FAILED : CoordinationException.ALREADY_ENDED);
+ }
+
+ if (!participants.contains(p))
+ {
+ participants.add(p);
+ }
+ }
+ }
+
public Map<Class<?>, ?> getVariables()
{
return variables;
}
+ public long extendTimeout(long timeOutInMs)
+ {
+ synchronized (this)
+ {
+ if (isTerminated())
+ {
+ throw new CoordinationException("Cannot extend timeout on terminated Coordination", this,
+ (getFailure() != null) ? CoordinationException.FAILED : CoordinationException.ALREADY_ENDED);
+ }
+
+ if (timeOutInMs > 0)
+ {
+ this.deadLine += timeOutInMs;
+ scheduleTimeout(this.deadLine);
+ }
+
+ return this.deadLine;
+ }
+ }
+
+ /**
+ * Returns whether the coordination has ended.
+ * <p>
+ * The return value of <code>false</code> may be a transient situation if
+ * the coordination is in the process of terminating.
+ */
+ public boolean isTerminated()
+ {
+ return state != ACTIVE;
+ }
+
+ public Thread getThread()
+ {
+ return initiatorThread;
+ }
+
+ public void join(long timeoutInMillis) throws InterruptedException
+ {
+ synchronized (this)
+ {
+ if (!isTerminated())
+ {
+ this.wait(timeoutInMillis);
+ }
+ }
+ }
+
+ public Coordination push()
+ {
+ // TODO: Check whether this has already been pushed !
+ // throw new CoordinationException("Coordination already pushed", this, CoordinationException.ALREADY_PUSHED);
+
+ return owner.push(this);
+ }
+
+ //-------
+
+ /**
+ * Initiates a coordination timeout. Called from the timer task scheduled by
+ * the {@link #scheduleTimeout(long)} method.
+ * <p>
+ * This method is inteded to only be called from the scheduled timer task.
+ */
+ void timeout()
+ {
+ // Fail the Coordination upon timeout
+ fail(TIMEOUT);
+ }
+
+ long getDeadLine()
+ {
+ return this.deadLine;
+ }
+
/**
* If this coordination is still active, this method initiates the
* termination of the coordination by setting the state to
@@ -288,72 +339,13 @@
}
/**
- * Internal implemenation of successful termination of the coordination.
- * <p>
- * This method must only be called after the {@link #state} field has been
- * set to {@link State#TERMINATING} and only be the method successfully
- * setting this state.
- *
- * @return OK or PARTIALLY_ENDED depending on whether all participants
- * succeeded or some of them failed ending the coordination.
- */
- private int endInternal()
- {
- int reason = OK;
- for (Participant part : participants)
- {
- try
- {
- part.ended(this);
- }
- catch (Exception e)
- {
- // TODO: log
- reason = PARTIALLY_ENDED;
- }
-
- // release the participant for other coordinations
- owner.releaseParticipant(part);
- }
- state = TERMINATED;
- return reason;
- }
-
- /**
- * Internal implemenation of coordination failure.
- * <p>
- * This method must only be called after the {@link #state} field has been
- * set to {@link State#TERMINATING} and only be the method successfully
- * setting this state.
- */
- private void failInternal()
- {
- // consider failure reason (if not null)
- for (Participant part : participants)
- {
- try
- {
- part.failed(this);
- }
- catch (Exception e)
- {
- // TODO: log
- }
-
- // release the participant for other coordinations
- owner.releaseParticipant(part);
- }
- state = FAILED;
- }
-
- /**
* Helper method for timeout scheduling. If a timer is currently scheduled
* it is canceled. If the new timeout value is a positive value a new timer
- * is scheduled to fire of so many milliseconds from now.
+ * is scheduled to fire at the desired time (in the future)
*
- * @param timeout The new timeout value
+ * @param deadline The at which to schedule the timer
*/
- private void scheduleTimeout(final long timeout)
+ private void scheduleTimeout(final long deadLine)
{
if (timeoutTask != null)
{
@@ -361,7 +353,7 @@
timeoutTask = null;
}
- if (timeout > 0)
+ if (deadLine > System.currentTimeMillis())
{
timeoutTask = new TimerTask()
{
@@ -372,7 +364,7 @@
}
};
- owner.schedule(timeoutTask, timeout);
+ owner.schedule(timeoutTask, deadLine);
}
}
}
diff --git a/coordinator/src/main/java/org/apache/felix/coordination/impl/CoordinationMgr.java b/coordinator/src/main/java/org/apache/felix/coordination/impl/CoordinationMgr.java
index 07aaaf6..b696205 100644
--- a/coordinator/src/main/java/org/apache/felix/coordination/impl/CoordinationMgr.java
+++ b/coordinator/src/main/java/org/apache/felix/coordination/impl/CoordinationMgr.java
@@ -21,6 +21,7 @@
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
+import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Stack;
@@ -35,10 +36,10 @@
import javax.management.openmbean.TabularData;
import javax.management.openmbean.TabularDataSupport;
-import org.apache.felix.jmx.service.coordination.CoordinatorMBean;
-import org.apache.felix.service.coordination.Coordination;
-import org.apache.felix.service.coordination.CoordinationException;
-import org.apache.felix.service.coordination.Participant;
+import org.apache.felix.jmx.service.coordinator.CoordinatorMBean;
+import org.apache.felix.service.coordinator.Coordination;
+import org.apache.felix.service.coordinator.CoordinationException;
+import org.apache.felix.service.coordinator.Participant;
/**
* The <code>CoordinationMgr</code> is the actual backend manager of all
@@ -117,15 +118,15 @@
this.participationTimeOut = participationTimeout;
}
- void schedule(final TimerTask task, final long delay)
+ void schedule(final TimerTask task, final long deadLine)
{
- if (delay < 0)
+ if (deadLine < 0)
{
task.cancel();
}
else
{
- coordinationTimer.schedule(task, delay);
+ coordinationTimer.schedule(task, new Date(deadLine));
}
}
@@ -139,20 +140,29 @@
CoordinationImpl current = participants.get(p);
while (current != null && current != c)
{
+ if (current.getThread() == c.getThread())
+ {
+ throw new CoordinationException("Participant " + p + " already participating in Coordination "
+ + current.getId() + "/" + current.getName() + " in this thread", c,
+ CoordinationException.DEADLOCK_DETECTED);
+ }
+
try
{
participants.wait(waitTime);
}
catch (InterruptedException ie)
{
- // don't worry, just keep on waiting
+ throw new CoordinationException("Interrupted waiting to add Participant " + p
+ + " currently participating in Coordination " + current.getId() + "/" + current.getName()
+ + " in this thread", c, CoordinationException.LOCK_INTERRUPTED);
}
// timeout waiting for participation
if (System.currentTimeMillis() > cutOff)
{
- throw new CoordinationException("Timed out waiting to join coordinaton", c.getName(),
- CoordinationException.TIMEOUT);
+ throw new CoordinationException("Timed out waiting to join coordinaton", c,
+ CoordinationException.UNKNOWN);
}
// check again
@@ -175,10 +185,10 @@
// ---------- Coordinator back end implementation
- Coordination create(final CoordinatorImpl owner, final String name)
+ Coordination create(final CoordinatorImpl owner, final String name, final int timeout)
{
long id = ctr.incrementAndGet();
- CoordinationImpl c = new CoordinationImpl(owner, id, name, defaultTimeOut);
+ CoordinationImpl c = new CoordinationImpl(owner, id, name, timeout);
coordinations.put(id, c);
return c;
}
@@ -214,7 +224,7 @@
return null;
}
- Coordination getCurrentCoordination()
+ Coordination peek()
{
Stack<Coordination> stack = threadStacks.get();
if (stack != null && !stack.isEmpty())
@@ -235,6 +245,12 @@
return result;
}
+ Coordination getCoordinationById(final long id)
+ {
+ CoordinationImpl c = coordinations.get(id);
+ return (c == null || c.isTerminated()) ? null : c;
+ }
+
// ---------- CoordinatorMBean interface
public TabularData listCoordinations(String regexFilter)
@@ -260,12 +276,12 @@
public CompositeData getCoordination(long id) throws IOException
{
- CoordinationImpl c = coordinations.get(id);
+ Coordination c = getCoordinationById(id);
if (c != null)
{
try
{
- return fromCoordination(c);
+ return fromCoordination((CoordinationImpl) c);
}
catch (OpenDataException e)
{
@@ -277,7 +293,7 @@
public boolean fail(long id, String reason)
{
- Coordination c = coordinations.get(id);
+ Coordination c = getCoordinationById(id);
if (c != null)
{
return c.fail(new Exception(reason));
@@ -287,10 +303,10 @@
public void addTimeout(long id, long timeout)
{
- Coordination c = coordinations.get(id);
+ Coordination c = getCoordinationById(id);
if (c != null)
{
- c.addTimeout(timeout);
+ c.extendTimeout(timeout);
}
}
@@ -298,6 +314,6 @@
{
return new CompositeDataSupport(COORDINATION_TYPE, new String[]
{ ID, NAME, TIMEOUT }, new Object[]
- { c.getId(), c.getName(), c.getTimeOut() });
+ { c.getId(), c.getName(), c.getDeadLine() });
}
}
diff --git a/coordinator/src/main/java/org/apache/felix/coordination/impl/CoordinatorImpl.java b/coordinator/src/main/java/org/apache/felix/coordination/impl/CoordinatorImpl.java
index e28fac2..7ef8c6c 100644
--- a/coordinator/src/main/java/org/apache/felix/coordination/impl/CoordinatorImpl.java
+++ b/coordinator/src/main/java/org/apache/felix/coordination/impl/CoordinatorImpl.java
@@ -6,9 +6,9 @@
* 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
@@ -22,10 +22,10 @@
import java.util.HashSet;
import java.util.TimerTask;
-import org.apache.felix.service.coordination.Coordination;
-import org.apache.felix.service.coordination.CoordinationException;
-import org.apache.felix.service.coordination.Coordinator;
-import org.apache.felix.service.coordination.Participant;
+import org.apache.felix.service.coordinator.Coordination;
+import org.apache.felix.service.coordinator.CoordinationException;
+import org.apache.felix.service.coordinator.Coordinator;
+import org.apache.felix.service.coordinator.Participant;
import org.osgi.framework.Bundle;
@SuppressWarnings("deprecation")
@@ -51,7 +51,7 @@
* <p>
* Called by the Coordinator ServiceFactory when this CoordinatorImpl
* instance is not used any longer by the owner bundle.
- *
+ *
* @see FELIX-2671/OSGi Bug 104
*/
void dispose()
@@ -80,10 +80,10 @@
}
}
- public Coordination create(String name)
+ public Coordination create(final String name, final int timeout)
{
// TODO: check permission
- Coordination c = mgr.create(this, name);
+ Coordination c = mgr.create(this, name, timeout);
synchronized (coordinations)
{
coordinations.add(c);
@@ -91,60 +91,67 @@
return c;
}
- public Coordination begin(String name)
- {
- // TODO: check permission
- return push(create(name));
- }
-
- public Coordination push(Coordination c)
- {
- // TODO: check permission
- return mgr.push(c);
- }
-
- public Coordination pop()
- {
- // TODO: check permission
- return mgr.pop();
- }
-
- public Coordination getCurrentCoordination()
- {
- // TODO: check permission
- return mgr.getCurrentCoordination();
- }
-
- public boolean alwaysFail(Throwable reason)
- {
- // TODO: check permission
- CoordinationImpl current = (CoordinationImpl) getCurrentCoordination();
- if (current != null)
- {
- current.mustFail(reason);
- return true;
- }
- return false;
- }
-
public Collection<Coordination> getCoordinations()
{
// TODO: check permission
return mgr.getCoordinations();
}
- public boolean participate(Participant participant) throws CoordinationException
+ public boolean fail(Throwable reason)
{
// TODO: check permission
- Coordination current = getCurrentCoordination();
+ CoordinationImpl current = (CoordinationImpl) peek();
if (current != null)
{
- current.participate(participant);
+ return current.fail(reason);
+ }
+ return false;
+ }
+
+ public Coordination peek()
+ {
+ // TODO: check permission
+ return mgr.peek();
+ }
+
+ public Coordination begin(final String name, final int timeoutInMillis)
+ {
+ // TODO: check permission
+ return push(create(name, timeoutInMillis));
+ }
+
+ public Coordination pop()
+ {
+ // TODO: check permission
+ return mgr.pop();
+ }
+
+ public boolean addParticipant(Participant participant) throws CoordinationException
+ {
+ // TODO: check permission
+ Coordination current = peek();
+ if (current != null)
+ {
+ current.addParticipant(participant);
return true;
}
return false;
}
+ public Coordination getCoordination(long id)
+ {
+ // TODO: check permission
+ return mgr.getCoordinationById(id);
+ }
+
+ //----------
+
+ Coordination push(Coordination c)
+ {
+ // TODO: check permission
+ return mgr.push(c);
+ }
+
void unregister(final CoordinationImpl c)
{
mgr.unregister(c);
@@ -154,9 +161,9 @@
}
}
- void schedule(final TimerTask task, final long delay)
+ void schedule(final TimerTask task, final long deadLine)
{
- mgr.schedule(task, delay);
+ mgr.schedule(task, deadLine);
}
void lockParticipant(final Participant p, final CoordinationImpl c)
diff --git a/coordinator/src/main/java/org/apache/felix/coordination/impl/CrdCommand.java b/coordinator/src/main/java/org/apache/felix/coordination/impl/CrdCommand.java
index edc981c..c8fd5fd 100644
--- a/coordinator/src/main/java/org/apache/felix/coordination/impl/CrdCommand.java
+++ b/coordinator/src/main/java/org/apache/felix/coordination/impl/CrdCommand.java
@@ -21,8 +21,8 @@
import java.util.Collection;
import java.util.Hashtable;
-import org.apache.felix.service.coordination.Coordination;
-import org.apache.felix.service.coordination.Participant;
+import org.apache.felix.service.coordinator.Coordination;
+import org.apache.felix.service.coordinator.Participant;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
diff --git a/coordinator/src/main/java/org/apache/felix/jmx/service/coordination/CoordinatorMBean.java b/coordinator/src/main/java/org/apache/felix/jmx/service/coordinator/CoordinatorMBean.java
similarity index 98%
rename from coordinator/src/main/java/org/apache/felix/jmx/service/coordination/CoordinatorMBean.java
rename to coordinator/src/main/java/org/apache/felix/jmx/service/coordinator/CoordinatorMBean.java
index 8ce307c..0bb069b 100644
--- a/coordinator/src/main/java/org/apache/felix/jmx/service/coordination/CoordinatorMBean.java
+++ b/coordinator/src/main/java/org/apache/felix/jmx/service/coordinator/CoordinatorMBean.java
@@ -13,7 +13,7 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.felix.jmx.service.coordination;
+package org.apache.felix.jmx.service.coordinator;
import java.io.IOException;
diff --git a/coordinator/src/main/java/org/apache/felix/jmx/service/coordination/package-info.java b/coordinator/src/main/java/org/apache/felix/jmx/service/coordinator/package-info.java
similarity index 96%
rename from coordinator/src/main/java/org/apache/felix/jmx/service/coordination/package-info.java
rename to coordinator/src/main/java/org/apache/felix/jmx/service/coordinator/package-info.java
index 1fbc826..2c3417e 100644
--- a/coordinator/src/main/java/org/apache/felix/jmx/service/coordination/package-info.java
+++ b/coordinator/src/main/java/org/apache/felix/jmx/service/coordinator/package-info.java
@@ -34,5 +34,5 @@
* @Provisional
*/
@Deprecated
-package org.apache.felix.jmx.service.coordination;
+package org.apache.felix.jmx.service.coordinator;
diff --git a/coordinator/src/main/java/org/apache/felix/service/coordination/Coordination.java b/coordinator/src/main/java/org/apache/felix/service/coordination/Coordination.java
deleted file mode 100644
index 2686d8f..0000000
--- a/coordinator/src/main/java/org/apache/felix/service/coordination/Coordination.java
+++ /dev/null
@@ -1,210 +0,0 @@
-/*
- * Copyright (c) OSGi Alliance (2004, 2010). All Rights Reserved.
- *
- * 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.felix.service.coordination;
-
-import java.util.Collection;
-import java.util.Map;
-
-/**
- * A Coordination object is used to coordinate a number of independent
- * participants. Once a Coordination is created, it can be used to add
- * Participant objects. When the Coordination is ended, the participants are
- * called back. A Coordination can also fail for various reasons, in that case
- * the participants are informed of this failure.
- *
- * @ThreadSafe
- * @Provisional
- */
-@Deprecated
-public interface Coordination
-{
- /**
- * Return value of end(). The Coordination ended normally, no participant
- * threw an exception.
- */
- public static final int OK = 0;
-
- /**
- * Return value of end(). The Coordination did not end normally, a
- * participant threw an exception making the outcome unclear.
- */
- public static final int PARTIALLY_ENDED = 1;
-
- /**
- * Return value of end(). The Coordination was set to always fail
- * (fail(Throwable)).
- */
- public static final int FAILED = 2;
-
- /**
- * Return value of end(). The Coordination failed because it had timed out.
- */
- public static final int TIMEOUT = 3;
-
- /**
- * Return the name of this Coordination. The name is given in the
- * Coordinator.begin(String) or Coordinator.create(String) method.
- *
- * @return the name of this Coordination
- */
- String getName();
-
- /**
- * Fail and then end this Coordination while returning the outcome. Any
- * participants will be called on their Participant.failed(Coordination)
- * method. Participants must assume that the Coordination failed and should
- * discard and cleanup any work that was processed during this Coordination.
- * The fail method must terminate the current Coordination before any of the
- * failed methods are called. That is, the Participant.failed(Coordination)
- * methods must be running outside the current coordination, no participants
- * can be added during the termination phase. A fail method must return
- * silently when the Coordination has already finished.
- *
- * @param reasonThrowable describing the reason of the failure for
- * documentation
- * @return true if the Coordination was still active, otherwise false
- */
- boolean fail(Throwable reason);
-
- /**
- * If the Coordination is terminated then return, otherwise set the
- * Coordination to fail. This method enables the following fail-safe pattern
- * to ensure Coordinations are properly terminated.
- *
- * <pre>
- * Coordination c = coordinator.begin("show_fail");
- * try {
- * work1();
- * work2();
- * if ( end() != OK )
- * log("...");
- * } catch( SomeException e) {
- * ...
- * } finally {
- * c.terminate();
- * }
- * </pre>
- * <p>
- * With this pattern, it is easy to ensure that the coordination is always
- * terminated.
- *
- * @return true if this method actually terminated the coordination (that
- * is, it was not properly ended). false if the Coordination was
- * already properly terminate by an end() or fail(Throwable) method.
- */
- boolean terminate();
-
- /**
- * End the current Coordination. Any participants will be called on their
- * Participant.ended(Coordination) method. This end() method indicates that
- * the Coordination has properly terminated and any participants should The
- * end method must terminate the current Coordination before any of the
- * Participant.ended(Coordination) methods is called. That is, the
- * Participant.ended(Coordination) methods must be running outside the
- * current coordination, no participants can be added during the termination
- * phase. This method returns the outcome of the Coordination:
- * <ol>
- * <li>OK - Correct outcome, no exceptions thrown</li>
- * <li>PARTIALLY_ENDED - One of the participants threw an exception</li>
- * <li>FAILED - The Coordination was set to always fail</li>
- * </ol>
- *
- * @return OK, PARTIALLY_ENDED, FAILED
- * @throws IllegalStateException when the Coordination is already
- * terminated.
- */
- int end() throws IllegalStateException;
-
- /**
- * Return the current list of participants that joined the Coordination.
- * This list is only valid as long as the Coordination has not been
- * terminated. That is, after end() or fail(Throwable) is called this method
- * will return an empty list.
- *
- * @return list of participants.
- * @throws SecurityException This method requires the action for the
- * CoordinationPermission.
- */
- Collection<Participant> getParticipants();
-
- /**
- * @return true if this Coordination has failed, false otherwise.
- */
- boolean isFailed();
-
- /**
- * @return true if this Coordination has terminated, false otherwise.
- */
- boolean isTerminated();
-
- /**
- * Add a minimum timeout for this Coordination. If this timeout expires,
- * then the Coordination will fail and the initiating thread will be
- * interrupted. This method must only be called on an active Coordination,
- * that is, before end() or fail(Throwable) is called. If the current
- * deadline is arriving later than the given timeout then the timeout is
- * ignored.
- *
- * @param timeOutInMsNumber of ms to wait, zero means forever.
- * @throws SecurityException This method requires the or action for the
- * CoordinationPermission. participate
- */
- void addTimeout(long timeOutInMs);
-
- /**
- * Add a Participant to this Coordination. If this method returns true then
- * there was a current Coordination and the participant has successfully
- * joined it. If there was no current Coordination then false is returned.
- * Once a Participant is participating it is guaranteed to receive a call
- * back on either the Participant.ended(Coordination) or
- * Participant.failed(Coordination) method when the Coordination is
- * terminated. A participant can be added to the Coordination multiple times
- * but it must only be called back once when the Coordination is terminated.
- * A Participant can only participate at a single Coordination, if it
- * attempts to block at another Coordination, then it will block until prior
- * Coordinations are finished. Notice that in edge cases the call back can
- * happen before this method returns. The ordering of the call-backs must
- * follow the order of participation. If participant is participating
- * multiple times the first time it participates defines this order.
- *
- * @return true if the Coordination was active, otherwise false.
- * @throws CoordinationException - This exception should normally not be
- * caught by the caller but allowed to bubble up to the
- * initiator of the coordination, it is therefore a
- * RuntimeException. It signals that this participant could not
- * participate the current coordination. This can be cause by
- * the following reasons:
- * <ol>
- * <li>CoordinationException.DEADLOCK_DETECTED</li>
- * <li>CoordinationException.TIMEOUT</li>
- * <li>CoordinationException.UNKNOWN</li>
- * </ol>
- * @throws SecurityException This method requires the action for the current
- * Coordination, if any.
- */
- boolean participate(Participant p);
-
- /**
- * A utility map associated with the current Coordination. Each coordination
- * carries a map that can be used for communicating between different
- * participants. To namespace of the map is a class, allowing for private
- * date to be stored in the map by using implementation classes or shared
- * data by interfaces.
- *
- * @return The map
- */
- Map<Class<?>, ?> getVariables();
-}
diff --git a/coordinator/src/main/java/org/apache/felix/service/coordination/CoordinationException.java b/coordinator/src/main/java/org/apache/felix/service/coordination/CoordinationException.java
deleted file mode 100644
index 8221fe0..0000000
--- a/coordinator/src/main/java/org/apache/felix/service/coordination/CoordinationException.java
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (c) OSGi Alliance (2004, 2010). All Rights Reserved.
- *
- * 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.felix.service.coordination;
-
-/**
- * Thrown when an implementation detects a potential deadlock situation that it
- * cannot solve. The name of the current coordination is given as argument.
- *
- * @Provisional
- */
-@Deprecated
-public class CoordinationException extends RuntimeException
-{
-
- private static final long serialVersionUID = -4466063711012717361L;
-
- /**
- * Unknown reason fot this exception.
- */
- public static final int UNKNOWN = 0;
-
- /**
- * Adding a participant caused a deadlock.
- */
- public static final int DEADLOCK_DETECTED = 1;
-
- /**
- * The Coordination took too long to finish.
- */
- public static final int TIMEOUT = 2;
-
- private final String name;
-
- private final int reason;
-
- /**
- * Create a new Coordination Exception.
- *
- * @param message The message
- * @param name The name of the Coordination
- * @param reason The reason for the exception.
- */
- public CoordinationException(String message, String name, int reason)
- {
- super(message);
- this.name = name;
- this.reason = reason;
- }
-
- /**
- * Answer the name of the Coordination associated with this exception.
- *
- * @return the Coordination name
- */
- public String getName()
- {
- return name;
- }
-
- /**
- * Answer the reason.
- *
- * @return the reason
- */
- public int getReason()
- {
- return reason;
- }
-}
diff --git a/coordinator/src/main/java/org/apache/felix/service/coordination/Coordinator.java b/coordinator/src/main/java/org/apache/felix/service/coordination/Coordinator.java
deleted file mode 100644
index 4b49591..0000000
--- a/coordinator/src/main/java/org/apache/felix/service/coordination/Coordinator.java
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (c) OSGi Alliance (2004, 2010). All Rights Reserved.
- *
- * 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.felix.service.coordination;
-
-import java.util.Collection;
-
-/**
- * A Coordinator service provides a facility to coordinate activities between
- * different parties. The Coordinator is a factory of Coordination objects.
- * Coordination objects can be created. Once created, they can be pushed on a
- * thread local stack push(Coordination) as an implicit parameter for calls to
- * other parties, or they can be passed as an argument. The current top of the
- * thread local stack can be obtained with getCurrentCoordination(). The
- * participate(Participant) method on this service or the
- * Coordination.participate(Participant) method can be used to participate in a
- * Coordination. Participants can only participate in a single Coordination, if
- * a Participant object is added to two different Coordinations it will block
- * until any prior Coordination has been ended. A Coordination can end correctly
- * when the Coordination.end() method is called or when it fails. If the
- * Coordination ends correctly, all its participants are called on the
- * Participant.ended(Coordination) method, otherwise the
- * Participant.failed(Coordination) is called. A Coordination can fail because
- * it times out or it is explicitly failed. A Coordination will timeout after an
- * implementation defined amount of time that must be higher than 30 seconds
- * unless overridden with configuration. This time can be set on a per
- * Coordination basis with the Coordination.addTimeout(long) method. The typical
- * usage of the Coordinator service is as follows:
- *
- * <pre>
- * Coordination coordination = coordinator.begin("mycoordination");
- * try
- * {
- * doWork();
- * if (coordination.end() != Coordination.OK)
- * log("failed");
- * }
- * finally
- * {
- * coordination.terminate();
- * }
- * </pre>
- * <p>
- * In the doWork() method, code can be called that requires a callback at the
- * end of the Coordination. This code is for a Participant.
- *
- * <pre>
- * void doWork()
- * {
- * if (coordinator.participate(this))
- * {
- * beginWork();
- * }
- * else
- * {
- * beginWork();
- * finishWork();
- * }
- * }
- *
- * void ended()
- * {
- * finishWork();
- * }
- *
- * void failed()
- * {
- * undoWork();
- * }
- * </pre>
- * <p>
- * Life cycle. All Coordinations that are begun through this service must
- * automatically fail before this service is ungotten.
- *
- * @ThreadSafe
- * @Provisional
- */
-@Deprecated
-public interface Coordinator
-{
-
- /**
- * Create a new Coordination that is not associated with the current thread.
- * Parameters:
- *
- * @param name The name of this coordination, a name does not have to be
- * unique.
- * @return The new Coordination object or null
- * @throws SecurityException This method requires the action, no bundle
- * check is done.
- */
- Coordination create(String name);
-
- /**
- * Begin a new Coordination and push it on the thread local stack with
- * push(Coordination). Parameters:
- *
- * @param name The name of this coordination, a name does not have to be
- * unique.
- * @return A new Coordination object
- * @throws SecurityException This method requires the action, no bundle
- * check is done.
- */
- Coordination begin(String name);
-
- /**
- * Associate the given Coordination object with a thread local stack. The
- * top of the thread local stack is returned with the
- * getCurrentCoordination() method. To remove the Coordination from the top
- * call pop().
- *
- * @param c The Coordination to push
- * @return c (for the builder pattern purpose)
- */
- Coordination push(Coordination c);
-
- /**
- * Pop the top of the thread local stack of Coordinations. If no current
- * Coordination is present, return null.
- *
- * @return The top of the stack or null
- */
- Coordination pop();
-
- /**
- * Participate in the current Coordination or return false if there is none.
- * This method calls getCurrentCoordination(), if it is null, it will return
- * false. Otherwise it will call Coordination.participate(Participant) and
- * return the result of that method.
- *
- * @param participant The participant of the Coordination
- * @return true if there was a current Coordination that could be
- * successfully used to participate, otherwise false.
- * @throws CoordinationException This exception should normally not be
- * caught by the caller but allowed to bubble up to the
- * initiator of the coordination, it is therefore a
- * RuntimeException. It signals that this participant could not
- * participate the current coordination. This can be cause by
- * the following reasons:
- * <ol>
- * <li>CoordinationException.DEADLOCK_DETECTED</li>
- * <li>CoordinationException.TIMEOUT</li>
- * <li>CoordinationException.UNKNOWN</li>
- * </ol>
- * @throws SecurityException This method requires the action for the current
- * Coordination, if any.
- */
- boolean participate(Participant participant) throws CoordinationException;
-
- /**
- * Always fail the current Coordination, if exists. Must fail the current
- * Coordination and return true or return false if there is no current
- * Coordination.
- *
- * @param reason Throwable describing why the collaboration must always fail
- * for debugging or null.
- * @return true if there was a current Coordination and false if not.
- */
- boolean alwaysFail(Throwable reason);
-
- /**
- * Return the current Coordination. The current Coordination is the top of
- * the thread local stack of Coordinations. If the stack is empty, there is
- * no current Coordination.
- *
- * @return null when the thread local stack is empty, otherwise the top of
- * the thread local stack of Coordinations.
- */
- Coordination getCurrentCoordination();
-
- /**
- * Provide a list of all Coordination objects. Answer a read only list of
- * active Coordination. This list must be a mutable snapshot of the current
- * situation. Changes to the list must not affect the original. Coordination
- * objects are capabilities and designed to be used only on the Coordination
- * thread. The returned list must only contain the Coordinations for which
- * the caller has , without this permission an empty list must be returned.
- *
- * @return a list of Coordination objects
- */
- Collection<Coordination> getCoordinations();
-}
diff --git a/coordinator/src/main/java/org/apache/felix/service/coordination/Participant.java b/coordinator/src/main/java/org/apache/felix/service/coordination/Participant.java
deleted file mode 100644
index 4a40c66..0000000
--- a/coordinator/src/main/java/org/apache/felix/service/coordination/Participant.java
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (c) OSGi Alliance (2004, 2010). All Rights Reserved.
- *
- * 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.felix.service.coordination;
-
-/**
- * A Participant participates in a Coordination. A Participant can participate
- * in a Coordination by calling Coordinator.participate(Participant) or
- * Coordinator.participateOrBegin(Participant). After successfully initiating
- * the participation, the Participant is called back when the Coordination is
- * terminated. If a Coordination ends with the Coordination.end() method, then
- * all the participants are called back on their ended(Coordination) method. If
- * the initiator decides to fail the Coordination (or another party has called
- * Coordinator.alwaysFail(Throwable)) then the failed(Coordination) method is
- * called back. Participants are required to be thread safe for the
- * ended(Coordination) method and the failed(Coordination) method. Both methods
- * can be called on another thread. A Coordinator service must block a
- * Participant when it tries to participate in multiple Coordinations.
- *
- * @ThreadSafe
- * @Provisional
- */
-@Deprecated
-public interface Participant
-{
-
- /**
- * The Coordination has failed and the participant is informed. A
- * participant should properly discard any work it has done during the
- * active coordination.
- *
- * @param c The Coordination that does the callback
- * @throws Exception Any exception thrown should be logged but is further
- * ignored and does not influence the outcome of the
- * Coordination.
- */
- void failed(Coordination c) throws Exception;
-
- /**
- * The Coordination is being ended.
- *
- * @param c The Coordination that does the callback
- * @throws Exception If an exception is thrown it should be logged and the
- * return of the Coordination.end() method must be
- * Coordination.PARTIALLY_ENDED.
- */
- void ended(Coordination c) throws Exception;
-}
diff --git a/coordinator/src/main/java/org/apache/felix/service/coordinator/Coordination.java b/coordinator/src/main/java/org/apache/felix/service/coordinator/Coordination.java
new file mode 100644
index 0000000..0857feb
--- /dev/null
+++ b/coordinator/src/main/java/org/apache/felix/service/coordinator/Coordination.java
@@ -0,0 +1,257 @@
+/*
+ * Copyright (c) OSGi Alliance (2004, 2010). All Rights Reserved.
+ *
+ * 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.felix.service.coordinator;
+
+import java.util.Collection;
+import java.util.Map;
+
+/**
+ * A Coordination object is used to coordinate a number of independent
+ * participants. Once a Coordination is created, it can be used to add
+ * Participant objects. When the Coordination is ended, the participants are
+ * called back. A Coordination can also fail for various reasons, in that case
+ * the participants are informed of this failure.
+ *
+ * @ThreadSafe
+ * @Provisional
+ */
+@Deprecated
+public interface Coordination
+{
+
+ /**
+ * The TIMEOUT exception is a singleton exception that will the reason for
+ * the failure when the Coordination times out.
+ */
+ public static final Exception TIMEOUT = new Exception();
+
+ /**
+ * A system assigned ID unique for a specific registered Coordinator. This
+ * id must not be reused as long as the Coordinator is registered and must
+ * be monotonically increasing for each Coordination and always be positive.
+ *
+ * @return an id
+ */
+ long getId();
+
+ /**
+ * Return the name of this Coordination. The name is given in the
+ * {@link Coordinator#begin(String, int)} or
+ * {@link Coordinator#create(String, int)} method. The name should follow
+ * the same naming pattern as a Bundle Symbolc Name.
+ *
+ * @return the name of this Coordination
+ */
+ String getName();
+
+ /**
+ * Fail this Coordination. If this Coordination is not terminated, fail it
+ * and call the {@link Participant#failed(Coordination)} method on all
+ * participant on the current thread. Participants must assume that the
+ * Coordination failed and should discard and cleanup any work that was
+ * processed during this Coordination. The {@link #fail(Throwable)} method
+ * will return <code>true</code> if it caused the termination. A fail method
+ * must return silently when the Coordination has already finished and
+ * return <code>false</code>. The fail method must terminate the current
+ * Coordination before any of the failed methods are called. That is, the
+ * {@link Participant#failed(Coordination)} methods must be running outside
+ * the current coordination, adding participants during this phase will
+ * cause a Configuration Exception to be thrown. If the Coordination is
+ * pushed on the Coordinator stack it is associated with a specific thread.
+ *
+ * @param reason The reason of the failure, must not be <code>null</code>
+ * @return true if the Coordination was active and this coordination was
+ * terminated due to this call, otherwise false
+ */
+ boolean fail(Throwable reason);
+
+ /**
+ * End the current Coordination.
+ *
+ * <pre>
+ * void foo() throws CoordinationException
+ * {
+ * Coordination c = coordinator.begin("work", 0);
+ * try
+ * {
+ * doWork();
+ * }
+ * catch (Exception e)
+ * {
+ * c.fail(e);
+ * }
+ * finally
+ * {
+ * c.end();
+ * }
+ * }
+ * </pre>
+ *
+ * If the coordination was terminated this method throws a Configuration
+ * Exception. Otherwise, any participants will be called on their
+ * {@link Participant#ended(Coordination)} method. A successful return of
+ * this {@link #end()} method indicates that the Coordination has properly
+ * terminated and any participants have been informed of the positive
+ * outcome. It is possible that one of the participants throws an exception
+ * during the callback. If this happens, the coordination fails partially
+ * and this is reported with an exception. This method must terminate the
+ * current Coordination before any of the
+ * {@link Participant#ended(Coordination)} methods are called. That is, the
+ * {@link Participant#ended(Coordination)} methods must be running outside
+ * the current coordination, no participants can be added during the
+ * termination phase. If the Coordination is on a thread local stack then it
+ * must be removed from this stack during termination.
+ *
+ * @throws CoordinationException when the Coordination has (partially)
+ * failed or timed out.
+ * <ol>
+ * <li>{@link CoordinationException#PARTIALLY_ENDED}</li>
+ * <li>{@link CoordinationException#ALREADY_ENDED}</li>
+ * <li>{@link CoordinationException#FAILED}</li>
+ * <li>{@link CoordinationException#UNKNOWN}</li>
+ * </ol>
+ */
+ void end() throws CoordinationException;
+
+ /**
+ * Return a mutable snapshot of the participants that joined the
+ * Coordination. Each unique Participant object as defined by its identity
+ * occurs only once in this list.
+ *
+ * @return list of participants.
+ * @throws SecurityException This method requires the
+ * {@link CoordinationPermission#ADMIN} action for the
+ * {@link CoordinationPermission}.
+ */
+ Collection<Participant> getParticipants();
+
+ /**
+ * If the coordination has failed because {@link #fail(Throwable)} was
+ * called then this method can provide the Throwable that was given as
+ * argument to the {@link #fail(Throwable)} method. A timeout on this
+ * Coordination will set the failure to a TimeoutException.
+ *
+ * @return a Throwable if this Coordination has failed, otherwise
+ * <code>null</code> if no failure occurred.
+ */
+ Throwable getFailure();
+
+ /**
+ * Add a Participant to this Coordination. Once a Participant is
+ * participating it is guaranteed to receive a call back on either the
+ * {@link Participant#ended(Coordination)} or
+ * {@link Participant#failed(Coordination)} method when the Coordination is
+ * terminated. A participant can be added to the Coordination multiple times
+ * but it must only be called back once when the Coordination is terminated.
+ * A Participant can only participate at a single Coordination, if it
+ * attempts to block at another Coordination, then it will block until prior
+ * Coordinations are finished. Notice that in edge cases the call back can
+ * happen before this method returns. The ordering of the call-backs must
+ * follow the order of participation. If participant is participating
+ * multiple times the first time it participates defines this order.
+ * *@param participant The participant of the Coordination
+ *
+ * @throws CoordinationException This exception should normally not be
+ * caught by the caller but allowed to bubble up to the
+ * initiator of the coordination, it is therefore a
+ * <code>RuntimeException</code>. It signals that this
+ * participant could not
+ * participate the current coordination. This can be cause by
+ * the following reasons:
+ * <ol>
+ * <li>{@link CoordinationException#DEADLOCK_DETECTED}</li>
+ * <li>{@link CoordinationException#ALREADY_ENDED}</li>
+ * <li>{@link CoordinationException#LOCK_INTERRUPTED}</li>
+ * <li>{@link CoordinationException#FAILED}</li>
+ * <li>{@link CoordinationException#UNKNOWN}</li>
+ * </ol>
+ * @throws SecurityException This method requires the
+ * {@link CoordinationPermission#PARTICIPATE} action for the
+ * current Coordination, if any.
+ */
+ void addParticipant(Participant participant);
+
+ /**
+ * A utility map associated with the current Coordination. Each coordination
+ * carries a map that can be used for communicating between different
+ * participants. To namespace of the map is a class, allowing for private
+ * date to be stored in the map by using implementation classes or shared
+ * data by interfaces. The returned map is does not have to not
+ * synchronized. Users of this map must synchronize on the Map object while
+ * making changes.
+ *
+ * @return The map
+ */
+ Map<Class<?>, ?> getVariables();
+
+ /**
+ * Extend the time out. Allows participants to extend the timeout of the
+ * coordination with at least the given amount. This can be done by
+ * participants when they know a task will take more than normal time. This
+ * method returns the new deadline. Passing 0 will return the existing
+ * deadline.
+ *
+ * @param timeInMillis Add this timeout to the current timeout. If the
+ * current timeout was set to 0, no extension must take place. A
+ * zero or negative value must have no effect.
+ * @return the new deadline in the format of
+ * <code>System.currentTimeMillis()</code> or 0 if no timeout was
+ * set.
+ * @throws CoordinationException Can throw
+ * <ol>
+ * <li>{@link CoordinationException#ALREADY_ENDED}</li>
+ * <li>{@link CoordinationException#FAILED}</li>
+ * <li>{@link CoordinationException#UNKNOWN}</li>
+ * </ol>
+ */
+ long extendTimeout(long timeInMs) throws CoordinationException;
+
+ /**
+ * @return true if this Coordination has terminated otherwise false.
+ */
+ boolean isTerminated();
+
+ /**
+ * Answer the associated thread or null.
+ *
+ * @return Associated thread or null
+ */
+ Thread getThread();
+
+ /**
+ * Wait until the Coordination is terminated and all Participant objects
+ * have been called.
+ *
+ * @param timeoutInMillis Maximum time to wait, 0 is forever
+ * @throws InterruptedException If the wait is interrupted
+ */
+ void join(long timeoutInMillis) throws InterruptedException;
+
+ /**
+ * Associate the given Coordination object with a thread local stack of its
+ * Coordinator. The top of the thread local stack is returned with the
+ * {@link Coordinator#peek()} method. To remove the Coordination from the
+ * top call {@link Coordinator#pop()}.
+ *
+ * @return this (for the builder pattern purpose)
+ * @throws CoordinationException Can throw the
+ * <ol>
+ * <li>{@link CoordinationException#ALREADY_PUSHED}</li>
+ * <li>{@link CoordinationException#UNKNOWN}</li>
+ * </ol>
+ */
+ Coordination push() throws CoordinationException;
+}
diff --git a/coordinator/src/main/java/org/apache/felix/service/coordinator/CoordinationException.java b/coordinator/src/main/java/org/apache/felix/service/coordinator/CoordinationException.java
new file mode 100644
index 0000000..663ace4
--- /dev/null
+++ b/coordinator/src/main/java/org/apache/felix/service/coordinator/CoordinationException.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) OSGi Alliance (2004, 2010). All Rights Reserved.
+ *
+ * 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.felix.service.coordinator;
+
+/**
+ * Thrown when an implementation detects a potential deadlock situation that it
+ * cannot solve. The name of the current coordination is given as argument.
+ *
+ * @Provisional
+ */
+@Deprecated
+public class CoordinationException extends RuntimeException
+{
+
+ private static final long serialVersionUID = -4466063711012717361L;
+
+ /**
+ * Unknown reason fot this exception.
+ */
+ public static final int UNKNOWN = 0;
+
+ /**
+ * Adding a participant caused a deadlock.
+ */
+ public static final int DEADLOCK_DETECTED = 1;
+
+ /**
+ * The Coordination was failed with {@link Coordination#fail(Throwable)}.
+ * When this exception type is used, the {@link Coordination#getFailure()}
+ * method must return a non-null value.
+ */
+ public static final int FAILED = 3;
+
+ /**
+ * The Coordination was partially ended.
+ */
+ public static final int PARTIALLY_ENDED = 4;
+
+ /**
+ * The Coordination was already ended.
+ */
+ public static final int ALREADY_ENDED = 5;
+
+ /**
+ * A Coordination was pushed on the stack that was already pushed.
+ */
+ public static final int ALREADY_PUSHED = 6;
+
+ /**
+ * Interrupted while trying to lock the participant.
+ */
+ public static final int LOCK_INTERRUPTED = 7;
+
+ /**
+ * The Coordination timed out.
+ */
+ public static final int TIMEOUT = 9;
+
+ private final Coordination coordination;
+
+ private final int type;
+
+ /**
+ * Create a new Coordination Exception.
+ *
+ * @param message The message
+ * @param coordination The coordination that failed
+ * @param type The reason for the exception
+ * @param exception The exception
+ */
+ public CoordinationException(String message, Coordination coordination, int type, Throwable exception)
+ {
+ super(message, exception);
+ this.coordination = coordination;
+ this.type = type;
+ }
+
+ /**
+ * Create a new Coordination Exception.
+ *
+ * @param message The message
+ * @param coordination The coordination that failed
+ * @param type The reason for the exception
+ */
+ public CoordinationException(String message, Coordination coordination, int type)
+ {
+ super(message);
+ this.coordination = coordination;
+ this.type = type;
+ }
+
+ /**
+ * Answer the name of the Coordination associated with this exception.
+ *
+ * @return the Coordination name
+ */
+ public String getName()
+ {
+ return coordination.getName();
+ }
+
+ /**
+ * Answer the reason.
+ *
+ * @return the reason
+ */
+ public int getType()
+ {
+ return type;
+ }
+
+ /**
+ * Must be set if to the exception type is {@link #FAILED}
+ *
+ * @return If exception is {@link #FAILED} a Throwable
+ */
+ public Throwable getFailure()
+ {
+ return getCause();
+ }
+
+ /**
+ * @return Answer the id
+ */
+ public long getId()
+ {
+ return coordination.getId();
+ }
+}
diff --git a/coordinator/src/main/java/org/apache/felix/service/coordination/CoordinationPermission.java b/coordinator/src/main/java/org/apache/felix/service/coordinator/CoordinationPermission.java
similarity index 88%
rename from coordinator/src/main/java/org/apache/felix/service/coordination/CoordinationPermission.java
rename to coordinator/src/main/java/org/apache/felix/service/coordinator/CoordinationPermission.java
index f0cedb7..a65966d 100644
--- a/coordinator/src/main/java/org/apache/felix/service/coordination/CoordinationPermission.java
+++ b/coordinator/src/main/java/org/apache/felix/service/coordinator/CoordinationPermission.java
@@ -1,19 +1,19 @@
/*
* Copyright (c) OSGi Alliance (2004, 2010). All Rights Reserved.
- *
+ *
* 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.felix.service.coordination;
+package org.apache.felix.service.coordinator;
import java.security.BasicPermission;
@@ -82,7 +82,7 @@
* </table>
* </li>
* </ol>
- *
+ *
* @Provisional
*/
@Deprecated
@@ -110,12 +110,12 @@
/**
* The name parameter specifies a filter condition. The filter asserts the
* bundle that initiated the Coordination. An implicit grant is made for a
- * bundle's own coordinations. Parameters:
- *
+ * bundle's own coordinations.
+ *
* @param filterExpression A filter expression asserting the bundle
* associated with the coordination.
- * @param actions A comma separated combination of INITIATE, ADMIN,
- * PARTICIPATE.
+ * @param actions A comma separated combination of {@link #INITIATE},
+ * {@link #ADMIN}, {@link #PARTICIPATE}.
*/
public CoordinationPermission(String filterExpression, String actions)
{
@@ -124,12 +124,12 @@
/**
* The verification permission
- *
+ *
* @param bundle The bundle that will be the target of the filter
* expression.
- * @param coordinationName The name of the coordination or null
+ * @param coordinationName The name of the coordination or <code>null</code>
* @param actions The set of actions required, which is a combination of
- * INITIATE, ADMIN, PARTICIPATE.
+ * {@link #INITIATE}, {@link #ADMIN}, {@link #PARTICIPATE}.
*/
public CoordinationPermission(org.osgi.framework.Bundle bundle, String coordinationName, String actions)
{
diff --git a/coordinator/src/main/java/org/apache/felix/service/coordinator/Coordinator.java b/coordinator/src/main/java/org/apache/felix/service/coordinator/Coordinator.java
new file mode 100644
index 0000000..d91b2dd
--- /dev/null
+++ b/coordinator/src/main/java/org/apache/felix/service/coordinator/Coordinator.java
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) OSGi Alliance (2004, 2010). All Rights Reserved.
+ *
+ * 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.felix.service.coordinator;
+
+import java.util.Collection;
+
+/**
+A Coordinator service coordinates activities between different parties. The Coordinator can create Coordination
+objects. Once a Coordination object is created, it can be pushed on a thread local stack {@link Coordination#push()} as
+an implicit parameter for calls to other parties, or it can be passed as an argument. The current top of the thread
+local stack can be obtained with #peek(). The addParticipant(Participant) method on this service or the
+Coordination.addParticipant(Participant) method can be used to participate in a Coordination. Participants
+participate only in a single Coordination, if a Participant object is added to a second Coordination the
+Coordination.addParticipant(Participant) method is blocked until the first Coordination is terminated. A
+Coordination ends correctly when the Coordination.end() method is called before termination or when the
+Coordination fails due to a timeout or a failure. If the Coordination ends correctly, all its participants are called on
+the Participant.ended(Coordination) method, in all other cases the Participant.failed(Coordination) is
+called. The typical usage of the Coordinator service is as follows:
+<pre>
+Coordination coordination = coordinator.begin("mycoordination",0);
+try {
+doWork();
+}
+finally {
+coordination.end();
+}
+</pre>
+In the doWork() method, code can be called that requires a callback at the end of the Coordination. The doWork
+method can then add a Participant to the coordination. This code is for a Participant.
+<pre>
+void doWork() {
+if (coordinator.addParticipant(this)) {
+beginWork();
+}
+else {
+beginWork();
+finishWork();
+}
+}
+void ended() {
+finishWork();
+}
+void failed() {
+undoWork();
+}
+</pre>
+Life cycle. All Coordinations that are begun through this service must automatically fail before this service is
+ungotten.
+ *
+ * @ThreadSafe
+ * @Provisional
+ */
+@Deprecated
+public interface Coordinator
+{
+
+ /**
+ * Create a new Coordination that is not associated with the current thread.
+ * Parameters:
+ *
+ * @param name The name of this coordination, a name does not have to be
+ * unique.
+ * @param timeout Timeout in milliseconds, less or equal than 0 means no
+ * timeout
+ * @return The new Coordination object, never <code>null</code>
+ * @throws SecurityException This method requires the
+ * {@link CoordinationPermission#INITIATE} action, no bundle
+ * check is done.
+ * @throws IllegalArgumentException when the name does not match the Bundle
+ * Symbolic Name pattern
+ */
+ Coordination create(String name, int timeout);
+
+ /**
+ * Provide a mutable snapshot collection of all Coordination objects
+ * currently not terminated. Coordinations in
+ * this list can have terminated before this list is returned or any time
+ * thereafter. The returned collection must
+ * only contain the Coordinations for which the caller has
+ * {@link CoordinationPermission#ADMIN}, without this
+ * permission an empty list must be returned.
+ *
+ * @return a list of Coordination objects filtered by
+ * {@link CoordinationPermission#ADMIN}
+ */
+ Collection<Coordination> getCoordinations();
+
+ /**
+ * Always fail the current Coordination, if it exists. If this is no current
+ * Coordination return <code>false</code>. Otherwise return the result of
+ * {@link Coordination#fail(Throwable)}, which is <code>true</code> in the
+ * case this call terminates the Coordination and <code>false</code>
+ * otherwise.
+ *
+ * <pre>
+ * false - No current Coordination
+ * false - Current Coordination was already terminated
+ * true - Current Coordination got terminated due to this call
+ * </pre>
+ *
+ * @param reason The reason for failure, must not be <code>null</code>.
+ * @return <code>true</code> if there was a current Coordination and it was
+ * terminated, otherwise <code>false</code>.
+ */
+ boolean fail(Throwable reason);
+
+ /**
+ * Return the current Coordination or <code>null</code>. The current
+ * Coordination is the top of the thread local stack of Coordinations. If
+ * the stack is empty, there is no current Coordination.
+ *
+ * @return <code>null</code> when the thread local stack is empty, otherwise
+ * the top of the thread local stack of
+ * Coordinations.
+ */
+ Coordination peek();
+
+ /**
+ * Begin a new Coordination and push it on the thread local stack with
+ * {@link Coordination#push()}.
+ *
+ * @param name The name of this coordination, a name does not have to be
+ * unique.
+ * @param timeoutInMillis Timeout in milliseconds, less or equal than 0
+ * means no timeout
+ * @return A new Coordination object
+ * @throws SecurityException This method requires the
+ * {@link CoordinationPermission#INITIATE} action, no bundle
+ * check is done.
+ * @throws IllegalArgumentException when the name does not match the Bundle
+ * Symbolic Name pattern
+ */
+ Coordination begin(String name, int timeoutInMillis);
+
+ /**
+ * Pop the top of the thread local stack of Coordinations. If no current
+ * Coordination is present, return <code>null</code>.
+ *
+ * @return The top of the stack or <code>null</code>
+ */
+ Coordination pop();
+
+ /**
+ * Participate in the current Coordination and return <code>true</code> or
+ * return <code>false</code> if there is none. This method calls
+ * {@link #peek()}, if it is <code>null</code>, it will return
+ * <code>false</code>. Otherwise it will call
+ * {@link Coordination#addParticipant(Participant)}.
+ *
+ * @param participant The participant of the Coordination
+ * @return <code>true</code> if there was a current Coordination that could
+ * be successfully used to participate, otherwise <code>false</code>
+ * .
+ * @throws CoordinationException This exception should normally not be
+ * caught by the caller but allowed to bubble up to the
+ * initiator of the coordination, it is therefore a
+ * <code>RuntimeException</code>. It signals that this
+ * participant could not participate the current coordination.
+ * This can be cause by the following reasons:
+ * <ol>
+ * <li>{@link CoordinationException#DEADLOCK_DETECTED}</li>
+ * <li>{@link CoordinationException#ALREADY_ENDED}</li>
+ * <li>{@link CoordinationException#TIMEOUT}</li>
+ * <li>{@link CoordinationException#UNKNOWN}</li>
+ * </ol>
+ * @throws SecurityException This method requires the
+ * {@link CoordinationPermission#PARTICIPATE} action for the
+ * current
+ * Coordination, if any.
+ */
+ boolean addParticipant(Participant participant) throws CoordinationException;
+
+ /**
+ * Answer the coordination associated with the given id if it exists.
+ *
+ * @param id The id of the requested Coordination
+ * @return a Coordination with the given ID or <code>null</code> when
+ * Coordination cannot be found because it never existed or had
+ * terminated before this call.
+ * @throws SecurityException if the caller has no
+ * {@link CoordinationPermission#ADMIN} for the requested
+ * Coordination.
+ */
+ Coordination getCoordination(long id);
+}
diff --git a/coordinator/src/main/java/org/apache/felix/service/coordinator/Participant.java b/coordinator/src/main/java/org/apache/felix/service/coordinator/Participant.java
new file mode 100644
index 0000000..f83138c
--- /dev/null
+++ b/coordinator/src/main/java/org/apache/felix/service/coordinator/Participant.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) OSGi Alliance (2004, 2010). All Rights Reserved.
+ *
+ * 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.felix.service.coordinator;
+
+/**
+ * A Participant participates in a Coordination. A Participant can participate
+ * in a Coordination by calling {@link Coordinator#addParticipant(Participant)}.
+ * After successfully initiating the participation, the Participant is called
+ * back when the Coordination is terminated. If a Coordination ends with the
+ * {@link Coordination#end()} method, then all the participants are called back
+ * on their {@link #ended(Coordination)} method. If the Coordination is failed
+ * (someone has called {@link Coordination#fail(Throwable)} then the
+ * {@link #failed(Coordination)} method is called back. Participants are
+ * required to be thread safe for the {@link #ended(Coordination)} method and
+ * the {@link #failed(Coordination)} method. Both methods can be called on
+ * another thread.
+ *
+ * @ThreadSafe
+ * @Provisional
+ */
+@Deprecated
+public interface Participant
+{
+
+ /**
+ * The Coordination has failed and the participant is informed. A
+ * participant should properly discard any work it has done during the
+ * active coordination.
+ *
+ * @param c The Coordination that does the callback
+ * @throws Exception Any exception thrown should be logged but is further
+ * ignored and does not influence the outcome of the
+ * Coordination.
+ */
+ void failed(Coordination c) throws Exception;
+
+ /**
+ * The Coordination is being ended.
+ *
+ * @param c The Coordination that does the callback
+ * @throws Exception If an exception is thrown it should be logged and the
+ * return of the {@link Coordination#end()} method must throw
+ * {@link CoordinationException#PARTIALLY_ENDED}.
+ */
+ void ended(Coordination c) throws Exception;
+}
diff --git a/coordinator/src/main/java/org/apache/felix/service/coordination/package-info.java b/coordinator/src/main/java/org/apache/felix/service/coordinator/package-info.java
similarity index 77%
rename from coordinator/src/main/java/org/apache/felix/service/coordination/package-info.java
rename to coordinator/src/main/java/org/apache/felix/service/coordinator/package-info.java
index fe64004..a7c33ec 100644
--- a/coordinator/src/main/java/org/apache/felix/service/coordination/package-info.java
+++ b/coordinator/src/main/java/org/apache/felix/service/coordinator/package-info.java
@@ -1,12 +1,12 @@
/*
* Copyright (c) OSGi Alliance (2004, 2010). All Rights Reserved.
- *
+ *
* 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.
@@ -14,7 +14,7 @@
* limitations under the License.
*/
/**
- * Coordination Package Version 1.0.
+ * Coordinator Package Version 1.0.
* <p>
* Bundles wishing to use this package must list the package in the
* Import-Package header of the bundle's manifest.
@@ -23,15 +23,15 @@
* package and the providers that implement the API in this package.
* <p>
* Example import for consumers using the API in this package: <blockquote>
- * <code>Import-Package: org.apache.felix.service.coordination; version="[1.0,2.0)"; status="provisional"</code>
+ * <code>Import-Package: org.apache.felix.service.coordinator; version="[1.0,2.0)"; status="provisional"</code>
* </blockquote>
* <p>
* Example import for providers implementing the API in this package:
* <blockquote>
- * <code>Import-Package: org.apache.felix.service.coordination; version="[1.0,1.1)"; status="provisional"</code>
+ * <code>Import-Package: org.apache.felix.service.coordinator; version="[1.0,1.1)"; status="provisional"</code>
* </blockquote>
- *
+ *
* @Provisional
*/
@Deprecated
-package org.apache.felix.service.coordination;
\ No newline at end of file
+package org.apache.felix.service.coordinator;
\ No newline at end of file
diff --git a/coordinator/src/test/java/org/apache/felix/coordination/impl/CoordinatorImplTest.java b/coordinator/src/test/java/org/apache/felix/coordination/impl/CoordinatorImplTest.java
index a605fbe..f6dfe88 100644
--- a/coordinator/src/test/java/org/apache/felix/coordination/impl/CoordinatorImplTest.java
+++ b/coordinator/src/test/java/org/apache/felix/coordination/impl/CoordinatorImplTest.java
@@ -18,9 +18,9 @@
*/
package org.apache.felix.coordination.impl;
-import org.apache.felix.service.coordination.Coordination;
-import org.apache.felix.service.coordination.CoordinationException;
-import org.apache.felix.service.coordination.Participant;
+import org.apache.felix.service.coordinator.Coordination;
+import org.apache.felix.service.coordinator.CoordinationException;
+import org.apache.felix.service.coordinator.Participant;
import junit.framework.TestCase;
@@ -43,129 +43,132 @@
public void test_createCoordination()
{
final String name = "test";
- final Coordination c1 = coordinator.create(name);
+ final Coordination c1 = coordinator.create(name, 0);
assertNotNull(c1);
assertEquals(name, c1.getName());
- assertNull(coordinator.getCurrentCoordination());
- assertFalse(c1.isFailed());
+ assertNull(coordinator.peek());
+ assertNull(c1.getFailure());
assertFalse(c1.isTerminated());
assertTrue(c1.getParticipants().isEmpty());
- assertTrue(c1.fail(new Exception()));
- assertTrue(c1.isFailed());
+ Exception cause = new Exception();
+ assertTrue(c1.fail(cause));
+ assertSame(cause, c1.getFailure());
assertTrue(c1.isTerminated());
- assertNull(coordinator.getCurrentCoordination());
+ assertNull(coordinator.peek());
assertFalse(c1.fail(new Exception()));
try
{
c1.end();
- fail("Expected IllegalStateException on end() after fail()");
+ fail("Expected CoordinationException.ALREADY_ENDED on end() after fail()");
}
- catch (IllegalStateException ise)
+ catch (CoordinationException ce)
{
- // expected
+ // expected already terminated
+ assertEquals(CoordinationException.ALREADY_ENDED, ce.getType());
}
- final Coordination c2 = coordinator.create(name);
+ final Coordination c2 = coordinator.create(name, 0);
assertNotNull(c2);
assertEquals(name, c2.getName());
- assertNull(coordinator.getCurrentCoordination());
- assertFalse(c2.isFailed());
+ assertNull(coordinator.peek());
+ assertNull(c2.getFailure());
assertFalse(c2.isTerminated());
assertTrue(c2.getParticipants().isEmpty());
- assertEquals(Coordination.OK, c2.end());
- assertFalse(c2.isFailed());
+ c2.end();
+ assertNull(c2.getFailure());
assertTrue(c2.isTerminated());
- assertNull(coordinator.getCurrentCoordination());
+ assertNull(coordinator.peek());
assertFalse(c2.fail(new Exception()));
try
{
c2.end();
- fail("Expected IllegalStateException on second end()");
+ fail("Expected CoordinationException.ALREADY_ENDED on second end()");
}
- catch (IllegalStateException ise)
+ catch (CoordinationException ce)
{
- // expected
+ // expected already terminated
+ assertEquals(CoordinationException.ALREADY_ENDED, ce.getType());
}
}
public void test_beginCoordination()
{
final String name = "test";
- final Coordination c1 = coordinator.begin(name);
+ final Coordination c1 = coordinator.begin(name, 0);
assertNotNull(c1);
assertEquals(name, c1.getName());
- assertEquals(c1, coordinator.getCurrentCoordination());
+ assertEquals(c1, coordinator.peek());
assertEquals(c1, coordinator.pop());
- assertNull(coordinator.getCurrentCoordination());
+ assertNull(coordinator.peek());
coordinator.push(c1);
- assertEquals(c1, coordinator.getCurrentCoordination());
+ assertEquals(c1, coordinator.peek());
c1.end();
- assertNull(coordinator.getCurrentCoordination());
+ assertNull(coordinator.peek());
- final Coordination c2 = coordinator.begin(name);
+ final Coordination c2 = coordinator.begin(name, 0);
assertNotNull(c2);
assertEquals(name, c2.getName());
- assertEquals(c2, coordinator.getCurrentCoordination());
+ assertEquals(c2, coordinator.peek());
c2.fail(null);
- assertNull(coordinator.getCurrentCoordination());
+ assertNull(coordinator.peek());
}
public void test_beginCoordination_stack()
{
final String name = "test";
- final Coordination c1 = coordinator.begin(name);
+ final Coordination c1 = coordinator.begin(name, 0);
assertNotNull(c1);
assertEquals(name, c1.getName());
- assertEquals(c1, coordinator.getCurrentCoordination());
+ assertEquals(c1, coordinator.peek());
- final Coordination c2 = coordinator.begin(name);
+ final Coordination c2 = coordinator.begin(name, 0);
assertNotNull(c2);
assertEquals(name, c2.getName());
- assertEquals(c2, coordinator.getCurrentCoordination());
+ assertEquals(c2, coordinator.peek());
c2.end();
- assertEquals(c1, coordinator.getCurrentCoordination());
+ assertEquals(c1, coordinator.peek());
c1.end();
- assertNull(coordinator.getCurrentCoordination());
+ assertNull(coordinator.peek());
}
public void test_beginCoordination_stack2()
{
final String name = "test";
- final Coordination c1 = coordinator.begin(name);
+ final Coordination c1 = coordinator.begin(name, 0);
assertNotNull(c1);
assertEquals(name, c1.getName());
- assertEquals(c1, coordinator.getCurrentCoordination());
+ assertEquals(c1, coordinator.peek());
- final Coordination c2 = coordinator.begin(name);
+ final Coordination c2 = coordinator.begin(name, 0);
assertNotNull(c2);
assertEquals(name, c2.getName());
- assertEquals(c2, coordinator.getCurrentCoordination());
+ assertEquals(c2, coordinator.peek());
c1.end();
- assertEquals(c2, coordinator.getCurrentCoordination());
+ assertEquals(c2, coordinator.peek());
c2.end();
- assertNull(coordinator.getCurrentCoordination());
+ assertNull(coordinator.peek());
}
- public void test_participate_with_ended()
+ public void test_addParticipant_with_ended()
{
final String name = "test";
- final Coordination c1 = coordinator.create(name);
+ final Coordination c1 = coordinator.create(name, 0);
final MockParticipant p1 = new MockParticipant();
- c1.participate(p1);
+ c1.addParticipant(p1);
assertTrue(c1.getParticipants().contains(p1));
assertEquals(1, c1.getParticipants().size());
@@ -175,11 +178,11 @@
assertEquals(c1, p1.c);
// assert order of call
- final Coordination c2 = coordinator.create(name);
+ final Coordination c2 = coordinator.create(name, 0);
final MockParticipant p21 = new MockParticipant();
final MockParticipant p22 = new MockParticipant();
- c2.participate(p21);
- c2.participate(p22);
+ c2.addParticipant(p21);
+ c2.addParticipant(p22);
assertTrue(c2.getParticipants().contains(p21));
assertTrue(c2.getParticipants().contains(p22));
assertEquals(2, c2.getParticipants().size());
@@ -192,12 +195,12 @@
assertTrue("p21 must be called before p22", p21.time < p22.time);
// assert order of call with two registrations
- final Coordination c3 = coordinator.create(name);
+ final Coordination c3 = coordinator.create(name, 0);
final MockParticipant p31 = new MockParticipant();
final MockParticipant p32 = new MockParticipant();
- c3.participate(p31);
- c3.participate(p32);
- c3.participate(p31); // should be "ignored"
+ c3.addParticipant(p31);
+ c3.addParticipant(p32);
+ c3.addParticipant(p31); // should be "ignored"
assertTrue(c3.getParticipants().contains(p31));
assertTrue(c3.getParticipants().contains(p32));
assertEquals(2, c3.getParticipants().size());
@@ -210,13 +213,13 @@
assertTrue("p21 must be called before p22", p31.time < p32.time);
}
- public void test_participate_with_failed()
+ public void test_addParticipant_with_failed()
{
final String name = "test";
- final Coordination c1 = coordinator.create(name);
+ final Coordination c1 = coordinator.create(name, 0);
final MockParticipant p1 = new MockParticipant();
- c1.participate(p1);
+ c1.addParticipant(p1);
assertTrue(c1.getParticipants().contains(p1));
assertEquals(1, c1.getParticipants().size());
@@ -226,11 +229,11 @@
assertEquals(c1, p1.c);
// assert order of call
- final Coordination c2 = coordinator.create(name);
+ final Coordination c2 = coordinator.create(name, 0);
final MockParticipant p21 = new MockParticipant();
final MockParticipant p22 = new MockParticipant();
- c2.participate(p21);
- c2.participate(p22);
+ c2.addParticipant(p21);
+ c2.addParticipant(p22);
assertTrue(c2.getParticipants().contains(p21));
assertTrue(c2.getParticipants().contains(p22));
assertEquals(2, c2.getParticipants().size());
@@ -243,12 +246,12 @@
assertTrue("p21 must be called before p22", p21.time < p22.time);
// assert order of call with two registrations
- final Coordination c3 = coordinator.create(name);
+ final Coordination c3 = coordinator.create(name, 0);
final MockParticipant p31 = new MockParticipant();
final MockParticipant p32 = new MockParticipant();
- c3.participate(p31);
- c3.participate(p32);
- c3.participate(p31); // should be "ignored"
+ c3.addParticipant(p31);
+ c3.addParticipant(p32);
+ c3.addParticipant(p31); // should be "ignored"
assertTrue(c3.getParticipants().contains(p31));
assertTrue(c3.getParticipants().contains(p32));
assertEquals(2, c3.getParticipants().size());
@@ -264,26 +267,25 @@
public void test_Coordination_timeout() throws InterruptedException
{
final String name = "test";
- final Coordination c1 = coordinator.create(name);
+ final Coordination c1 = coordinator.create(name, 200);
final MockParticipant p1 = new MockParticipant();
- c1.participate(p1);
+ c1.addParticipant(p1);
assertTrue(c1.getParticipants().contains(p1));
assertEquals(1, c1.getParticipants().size());
- // set a short timeout and wait for it to pass
- c1.addTimeout(100);
- Thread.sleep(150);
+ // wait for the coordination to time out
+ Thread.sleep(250);
// expect coordination to have terminated
assertTrue(c1.isTerminated());
- assertTrue(c1.isFailed());
+ assertSame(Coordination.TIMEOUT, c1.getFailure());
// expect Participant.failed() being called
assertTrue(p1.failed);
assertEquals(c1, p1.c);
}
- public void test_Coordination_participate_timeout() throws InterruptedException
+ public void test_Coordination_addParticipant_timeout() throws InterruptedException
{
final String name1 = "test1";
final String name2 = "test2";
@@ -292,31 +294,31 @@
// ensure short timeout for participation
mgr.configure(60000, 200);
- final Coordination c1 = coordinator.create(name1);
- c1.participate(p1);
+ final Coordination c1 = coordinator.create(name1, 0);
+ c1.addParticipant(p1);
assertTrue(c1.getParticipants().contains(p1));
assertEquals(1, c1.getParticipants().size());
// preset p1PartFailure to be be sure the participation actually starts
- p1.participateFailure(new Exception("Not Started yet"));
+ p1.addParticipantFailure(new Exception("Not Started yet"));
Thread c2Thread = new Thread()
{
public void run()
{
- final Coordination c2 = coordinator.create(name2);
+ final Coordination c2 = coordinator.create(name2, 0);
try
{
- p1.participateFailure(null);
- c2.participate(p1);
+ p1.addParticipantFailure(null);
+ c2.addParticipant(p1);
}
catch (Throwable t)
{
- p1.participateFailure(t);
+ p1.addParticipantFailure(t);
}
finally
{
- c2.terminate();
+ c2.end();
}
}
};
@@ -327,21 +329,21 @@
c2Thread.join(2000);
assertFalse("Thread for second Coordination did not terminate....", c2Thread.isAlive());
- Throwable p1PartFailure = p1.participateFailure;
+ Throwable p1PartFailure = p1.addParticipantFailure;
if (p1PartFailure == null)
{
- fail("Expecting CoordinationException/TIMEOUT for second participation");
+ fail("Expecting CoordinationException/UNKNOWN for second participation");
}
else if (p1PartFailure instanceof CoordinationException)
{
- assertEquals(CoordinationException.TIMEOUT, ((CoordinationException) p1PartFailure).getReason());
+ assertEquals(CoordinationException.UNKNOWN, ((CoordinationException) p1PartFailure).getType());
}
else
{
- fail("Unexpected Throwable while trying to participate: " + p1PartFailure);
+ fail("Unexpected Throwable while trying to addParticipant: " + p1PartFailure);
}
- c1.terminate();
+ c1.end();
// make sure c2Thread has terminated
if (c2Thread.isAlive())
@@ -363,7 +365,7 @@
boolean ended;
- Throwable participateFailure;
+ Throwable addParticipantFailure;
public void failed(Coordination c) throws Exception
{
@@ -379,9 +381,9 @@
this.time = System.nanoTime();
}
- void participateFailure(Throwable t)
+ void addParticipantFailure(Throwable t)
{
- this.participateFailure = t;
+ this.addParticipantFailure = t;
}
}
}