aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohn Ross2011-11-03 20:22:53 (EDT)
committerJohn Ross2011-11-04 10:11:02 (EDT)
commit9c2b8346a5d28d5d727273c5c90873e40201f20f (patch)
treedb3e193529f5481ac8119d3612a0a57b010ef8ed
parentee7e9e6d2f851488726c9b7db44e4c1bfcee3df9 (diff)
downloadrt.equinox.bundles-9c2b8346a5d28d5d727273c5c90873e40201f20f.zip
rt.equinox.bundles-9c2b8346a5d28d5d727273c5c90873e40201f20f.tar.gz
rt.equinox.bundles-9c2b8346a5d28d5d727273c5c90873e40201f20f.tar.bz2
Bug 362232 - [coordinator] Add support for the new, mandatory orphaned coordination requirement.
New CoordinationReferent. It is tracked by the CoordinationWeakReference in order to know when an initiator has abandoned all strong references to the coordination without properly ending it. It is also used as a simple proxy when making a coordination available to clients other than the initiator. New CoordinationWeakReference. Maintains a strong reference to the CoordinationImpl. When it is placed on the ReferenceQueue, the CoordinationImpl is retrieved and failed with Coordination.ORPHANED. A CoordinationReferent is returned to callers of Coordinator.create() and begin(). Only instances returned by these methods are tracked by CoordinationWeakReference. Other API methods that receive coordinations as results (e.g., Coordinator.getCoordinations()) or parameters (e.g., Participant.failed()), receive different instances. Note that one of the goals was to minimize the impact of this change on existing code. Consequently, all internal data structures and methods continue to use CoordinationImpl. It is only references to the initiator's instance of CoordinationReferent that must not be strongly referenced by the implementation. When providing coordination instances externally to clients other than the initiator, CoordinationImpl is wrapped with a new CoordinationReferent. Coordinations will remain visible to callers of relevant methods (other than create() or begin()) until the orphaned coordination has been removed by the fail process, even when CoordinationWeakReference.get() would return null. This makes the flow of orphaned coordinations seamless with others. A management agent, for example, might detect that a coordination is obsolete and fail it before the orphan cleanup process executes. CoordinationWeakReference instances are transparently tracked by the CoordinationWeakReference class.
-rw-r--r--bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/Activator.java1
-rw-r--r--bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinationImpl.java15
-rw-r--r--bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinationReferent.java104
-rw-r--r--bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinationWeakReference.java68
-rw-r--r--bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinatorImpl.java68
-rw-r--r--bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/Messages.java1
-rw-r--r--bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/messages.properties1
7 files changed, 211 insertions, 47 deletions
diff --git a/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/Activator.java b/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/Activator.java
index eceb8dc..86ae4b3 100644
--- a/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/Activator.java
+++ b/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/Activator.java
@@ -43,5 +43,6 @@ public class Activator implements BundleActivator {
if (registration != null)
registration.unregister();
factory.shutdown();
+ CoordinationWeakReference.processOrphanedCoordinations();
}
}
diff --git a/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinationImpl.java b/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinationImpl.java
index bfc2839..0523627 100644
--- a/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinationImpl.java
+++ b/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinationImpl.java
@@ -10,7 +10,6 @@
*******************************************************************************/
package org.eclipse.equinox.coordinator;
-import java.lang.ref.Reference;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
@@ -31,7 +30,7 @@ public class CoordinationImpl implements Coordination {
private volatile boolean terminated;
private Date deadline;
- private Reference<CoordinationImpl> enclosingCoordination;
+ private CoordinationImpl enclosingCoordination;
private Thread thread;
private TimerTask timerTask;
@@ -127,7 +126,7 @@ public class CoordinationImpl implements Coordination {
}
// Unwind the stack in case there are other coordinations higher
// up than this one.
- while (coordinator.peek() != this) {
+ while (!coordinator.peek().equals(this)) {
try {
coordinator.peek().end();
} catch (CoordinationException e) {
@@ -146,9 +145,10 @@ public class CoordinationImpl implements Coordination {
Exception exception = null;
// No additional synchronization is needed here because the participant
// list will not be modified post termination.
+ CoordinationReferent referent = new CoordinationReferent(this);
for (Participant participant : participants) {
try {
- participant.ended(this);
+ participant.ended(referent);
} catch (Exception e) {
coordinator.getLogService().log(LogService.LOG_WARNING, Messages.CoordinationImpl_4, e);
// Only the first exception will be propagated.
@@ -232,9 +232,10 @@ public class CoordinationImpl implements Coordination {
// Notify participants this coordination has failed.
// No additional synchronization is needed here because the participant
// list will not be modified post termination.
+ CoordinationReferent referent = new CoordinationReferent(this);
for (Participant participant : participants) {
try {
- participant.failed(this);
+ participant.failed(referent);
} catch (Exception e) {
coordinator.getLogService().log(LogService.LOG_WARNING, Messages.CoordinationImpl_6, e);
}
@@ -254,7 +255,7 @@ public class CoordinationImpl implements Coordination {
public synchronized Coordination getEnclosingCoordination() {
coordinator.checkPermission(CoordinationPermission.ADMIN, name);
- return enclosingCoordination == null ? null : enclosingCoordination.get();
+ return enclosingCoordination;
}
public Throwable getFailure() {
@@ -329,7 +330,7 @@ public class CoordinationImpl implements Coordination {
this.timerTask = timerTask;
}
- synchronized void setThreadAndEnclosingCoordination(Thread t, Reference<CoordinationImpl> c) {
+ synchronized void setThreadAndEnclosingCoordination(Thread t, CoordinationImpl c) {
thread = t;
enclosingCoordination = c;
}
diff --git a/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinationReferent.java b/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinationReferent.java
new file mode 100644
index 0000000..68b807d
--- /dev/null
+++ b/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinationReferent.java
@@ -0,0 +1,104 @@
+/*******************************************************************************
+ * Copyright (c) 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.coordinator;
+
+import java.util.List;
+import java.util.Map;
+
+import org.osgi.framework.Bundle;
+import org.osgi.service.coordinator.Coordination;
+import org.osgi.service.coordinator.Participant;
+
+public class CoordinationReferent implements Coordination {
+ private final CoordinationImpl coordination;
+
+ public CoordinationReferent(CoordinationImpl coordination) {
+ if (coordination == null)
+ throw new NullPointerException();
+ this.coordination = coordination;
+ }
+
+ public long getId() {
+ return coordination.getId();
+ }
+
+ public String getName() {
+ return coordination.getName();
+ }
+
+ public void end() {
+ coordination.end();
+ }
+
+ public boolean fail(Throwable cause) {
+ return coordination.fail(cause);
+ }
+
+ public Throwable getFailure() {
+ return coordination.getFailure();
+ }
+
+ public boolean isTerminated() {
+ return coordination.isTerminated();
+ }
+
+ public void addParticipant(Participant participant) {
+ coordination.addParticipant(participant);
+ }
+
+ public List<Participant> getParticipants() {
+ return coordination.getParticipants();
+ }
+
+ public Map<Class<?>, Object> getVariables() {
+ return coordination.getVariables();
+ }
+
+ public long extendTimeout(long timeMillis) {
+ return coordination.extendTimeout(timeMillis);
+ }
+
+ public void join(long timeMillis) throws InterruptedException {
+ coordination.join(timeMillis);
+ }
+
+ public Coordination push() {
+ return coordination.push();
+ }
+
+ public Thread getThread() {
+ return coordination.getThread();
+ }
+
+ public Bundle getBundle() {
+ return coordination.getBundle();
+ }
+
+ public Coordination getEnclosingCoordination() {
+ return coordination.getEnclosingCoordination();
+ }
+
+ @Override
+ public boolean equals(Object object) {
+ if (object instanceof CoordinationReferent)
+ return coordination.equals(((CoordinationReferent)object).coordination);
+ return coordination.equals(object);
+ }
+
+ @Override
+ public int hashCode() {
+ return coordination.hashCode();
+ }
+
+ CoordinationImpl getDelegate() {
+ return coordination;
+ }
+}
diff --git a/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinationWeakReference.java b/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinationWeakReference.java
new file mode 100644
index 0000000..0442c38
--- /dev/null
+++ b/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinationWeakReference.java
@@ -0,0 +1,68 @@
+/*******************************************************************************
+ * Copyright (c) 2011 IBM Corporation and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v1.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * IBM Corporation - initial API and implementation
+ *******************************************************************************/
+package org.eclipse.equinox.coordinator;
+
+import java.lang.ref.ReferenceQueue;
+import java.lang.ref.WeakReference;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.Set;
+
+import org.eclipse.osgi.util.NLS;
+import org.osgi.service.coordinator.Coordination;
+import org.osgi.service.coordinator.CoordinationException;
+import org.osgi.service.log.LogService;
+
+public class CoordinationWeakReference extends WeakReference<CoordinationReferent> {
+ private static final ReferenceQueue<CoordinationReferent> referenceQueue = new ReferenceQueue<CoordinationReferent>();
+ private static final Set<CoordinationWeakReference> references = Collections.synchronizedSet(new HashSet<CoordinationWeakReference>());
+
+ public static CoordinationWeakReference newInstance(CoordinationReferent referent) {
+ CoordinationWeakReference reference = new CoordinationWeakReference(referent);
+ references.add(reference);
+ return reference;
+ }
+
+ public static void processOrphanedCoordinations() {
+ CoordinationWeakReference r;
+ while ((r = (CoordinationWeakReference)referenceQueue.poll()) != null) {
+ references.remove(r);
+ CoordinationImpl c = r.getCoordination();
+ try {
+ c.fail(Coordination.ORPHANED);
+ }
+ catch (Throwable t) {
+ c.getLogService().log(LogService.LOG_ERROR, NLS.bind(Messages.CoordinatorImpl_5, c.getName(), c.getId()), t);
+ }
+ finally {
+ try {
+ c.end();
+ }
+ catch (CoordinationException e) {
+ // This is expected since we already failed the coordination.
+ }
+ }
+ }
+ }
+
+ private final CoordinationImpl coordination;
+
+ private CoordinationWeakReference(CoordinationReferent referent) {
+ super(referent, referenceQueue);
+ coordination = referent.getDelegate();
+ if (coordination == null)
+ throw new NullPointerException();
+ }
+
+ public CoordinationImpl getCoordination() {
+ return coordination;
+ }
+}
diff --git a/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinatorImpl.java b/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinatorImpl.java
index 4060b66..e143240 100644
--- a/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinatorImpl.java
+++ b/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/CoordinatorImpl.java
@@ -10,9 +10,6 @@
*******************************************************************************/
package org.eclipse.equinox.coordinator;
-import java.lang.ref.Reference;
-import java.lang.ref.ReferenceQueue;
-import java.lang.ref.WeakReference;
import java.security.Permission;
import java.util.ArrayList;
import java.util.Collection;
@@ -57,59 +54,35 @@ public class CoordinatorImpl implements Coordinator {
};
private static class WeakCoordinationStack {
- private final LinkedList<Reference<CoordinationImpl>> coordinations = new LinkedList<Reference<CoordinationImpl>>();
- private final ReferenceQueue<CoordinationImpl> queue = new ReferenceQueue<CoordinationImpl>();
+ private final LinkedList<CoordinationImpl> coordinations = new LinkedList<CoordinationImpl>();
public WeakCoordinationStack() {
}
public boolean contains(CoordinationImpl c) {
- purge();
- for (Reference<CoordinationImpl> r : coordinations) {
- if (c.equals(r.get()))
- return true;
- }
- return false;
+ return coordinations.contains(c);
}
public CoordinationImpl peek() {
- purge();
if (coordinations.isEmpty())
return null;
- return coordinations.getFirst().get();
+ return coordinations.getFirst();
}
public CoordinationImpl pop() {
- purge();
if (coordinations.isEmpty())
return null;
- CoordinationImpl c = coordinations.removeFirst().get();
+ CoordinationImpl c = coordinations.removeFirst();
if (c != null)
c.setThreadAndEnclosingCoordination(null, null);
return c;
}
public void push(CoordinationImpl c) {
- purge();
if (contains(c))
throw new CoordinationException(Messages.CoordinatorImpl_3, c, CoordinationException.ALREADY_PUSHED);
- Reference<CoordinationImpl> r = new WeakReference<CoordinationImpl>(c, queue);
c.setThreadAndEnclosingCoordination(Thread.currentThread(), coordinations.isEmpty() ? null : coordinations.getFirst());
- coordinations.addFirst(r);
- }
-
- private void purge() {
- Reference<? extends CoordinationImpl> r;
- while ((r = queue.poll()) != null) {
- int index = coordinations.indexOf(r);
- coordinations.remove(r);
- if (index > 0) {
- r = coordinations.get(index - 1);
- CoordinationImpl c = r.get();
- if (c != null)
- c.setThreadAndEnclosingCoordination(Thread.currentThread(), coordinations.get(index));
- }
- }
+ coordinations.addFirst(c);
}
}
@@ -128,6 +101,7 @@ public class CoordinatorImpl implements Coordinator {
}
public boolean addParticipant(Participant participant) throws CoordinationException {
+ CoordinationWeakReference.processOrphanedCoordinations();
Coordination coordination = peek();
if (coordination == null)
return false;
@@ -136,19 +110,22 @@ public class CoordinatorImpl implements Coordinator {
}
public Coordination begin(String name, long timeout) {
- CoordinationImpl coordination = (CoordinationImpl) create(name, timeout);
+ Coordination coordination = create(name, timeout);
coordination.push();
return coordination;
}
public Coordination create(String name, long timeout) {
+ CoordinationWeakReference.processOrphanedCoordinations();
// This method requires the INITIATE permission. No bundle check is done.
checkPermission(CoordinationPermission.INITIATE, name);
CoordinationImpl coordination = new CoordinationImpl(getNextId(), name, timeout, this);
+ CoordinationReferent referent = new CoordinationReferent(coordination);
synchronized (this) {
if (shutdown)
throw new IllegalStateException(Messages.CoordinatorImpl_2);
synchronized (CoordinatorImpl.class) {
+ CoordinationWeakReference.newInstance(referent);
coordinations.add(coordination);
idToCoordination.put(new Long(coordination.getId()), coordination);
}
@@ -158,10 +135,11 @@ public class CoordinatorImpl implements Coordinator {
coordination.setTimerTask(timerTask);
schedule(timerTask, coordination.getDeadline());
}
- return coordination;
+ return referent;
}
public boolean fail(Throwable reason) {
+ CoordinationWeakReference.processOrphanedCoordinations();
Coordination coordination = peek();
if (coordination == null)
return false;
@@ -169,9 +147,12 @@ public class CoordinatorImpl implements Coordinator {
}
public Coordination getCoordination(long id) {
- CoordinationImpl result = null;
+ CoordinationWeakReference.processOrphanedCoordinations();
+ CoordinationReferent result = null;
synchronized (CoordinatorImpl.class) {
- result = idToCoordination.get(new Long(id));
+ CoordinationImpl c = idToCoordination.get(new Long(id));
+ if (c != null)
+ result = new CoordinationReferent(c);
}
if (result != null && !result.isTerminated()) {
try {
@@ -185,6 +166,7 @@ public class CoordinatorImpl implements Coordinator {
}
public Collection<Coordination> getCoordinations() {
+ CoordinationWeakReference.processOrphanedCoordinations();
ArrayList<Coordination> result;
synchronized (CoordinatorImpl.class) {
result = new ArrayList<Coordination>(idToCoordination.size());
@@ -195,7 +177,7 @@ public class CoordinatorImpl implements Coordinator {
continue;
try {
checkPermission(CoordinationPermission.ADMIN, coordination.getName());
- result.add(coordination);
+ result.add(new CoordinationReferent(coordination));
} catch (SecurityException e) {
logService.log(LogService.LOG_DEBUG, Messages.CoordinatorImpl_1, e);
}
@@ -206,14 +188,19 @@ public class CoordinatorImpl implements Coordinator {
}
public Coordination peek() {
- return coordinationStack.get().peek();
+ CoordinationWeakReference.processOrphanedCoordinations();
+ CoordinationImpl c = coordinationStack.get().peek();
+ if (c == null)
+ return null;
+ return new CoordinationReferent(c);
}
public Coordination pop() {
- Coordination c = coordinationStack.get().peek();
+ CoordinationWeakReference.processOrphanedCoordinations();
+ CoordinationImpl c = coordinationStack.get().peek();
if (c == null) return null;
checkPermission(CoordinationPermission.INITIATE, c.getName());
- return coordinationStack.get().pop();
+ return new CoordinationReferent(coordinationStack.get().pop());
}
CoordinationImpl addParticipant(Participant participant, CoordinationImpl coordination) {
@@ -264,6 +251,7 @@ public class CoordinatorImpl implements Coordinator {
}
void shutdown() {
+ CoordinationWeakReference.processOrphanedCoordinations();
List<Coordination> coords;
synchronized (this) {
shutdown = true;
diff --git a/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/Messages.java b/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/Messages.java
index bb52058..6603c51 100644
--- a/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/Messages.java
+++ b/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/Messages.java
@@ -35,6 +35,7 @@ public class Messages extends NLS {
public static String CoordinatorImpl_2;
public static String CoordinatorImpl_3;
public static String CoordinatorImpl_4;
+ public static String CoordinatorImpl_5;
static {
// initialize resource bundle
diff --git a/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/messages.properties b/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/messages.properties
index bf1e76e..d3ca681 100644
--- a/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/messages.properties
+++ b/bundles/org.eclipse.equinox.coordinator/src/org/eclipse/equinox/coordinator/messages.properties
@@ -29,3 +29,4 @@ CoordinatorImpl_1=A requestor did not have permission to view a coordination
CoordinatorImpl_2=This coordinator has been shutdown
CoordinatorImpl_3=Coordination already exists
CoordinatorImpl_4=Unable to purge the canceled task
+CoordinatorImpl_5=An error occurred while failing coordination {0} with ID {1}.