FELIX-2647 First checkin of the Apache Felix Coordinator Service implementation
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1006352 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/coordinator/DEPENDENCIES b/coordinator/DEPENDENCIES
new file mode 100644
index 0000000..a29f455
--- /dev/null
+++ b/coordinator/DEPENDENCIES
@@ -0,0 +1,30 @@
+Apache Felix Coordinator Service
+Copyright 2010 The Apache Software Foundation
+
+
+I. Included Software
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2010).
+Licensed under the Apache License 2.0.
+
+
+II. Used Software
+
+This product uses software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product uses software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2010).
+Licensed under the Apache License 2.0.
+
+
+III. License Summary
+- Apache License 2.0
diff --git a/coordinator/LICENSE b/coordinator/LICENSE
new file mode 100644
index 0000000..d645695
--- /dev/null
+++ b/coordinator/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ 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.
diff --git a/coordinator/NOTICE b/coordinator/NOTICE
new file mode 100644
index 0000000..3e0135b
--- /dev/null
+++ b/coordinator/NOTICE
@@ -0,0 +1,11 @@
+Apache Felix Coordinator Service
+Copyright 2010 The Apache Software Foundation
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
+Licensed under the Apache License 2.0.
+
+This product includes software developed at
+The OSGi Alliance (http://www.osgi.org/).
+Copyright (c) OSGi Alliance (2000, 2010).
+Licensed under the Apache License 2.0.
diff --git a/coordinator/pom.xml b/coordinator/pom.xml
new file mode 100644
index 0000000..365daff
--- /dev/null
+++ b/coordinator/pom.xml
@@ -0,0 +1,116 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>felix-parent</artifactId>
+ <version>1.2.0</version>
+ <relativePath>../pom/pom.xml</relativePath>
+ </parent>
+
+ <artifactId>org.apache.felix.coordinator</artifactId>
+ <packaging>bundle</packaging>
+
+ <name>Apache Felix Coordinator Service</name>
+ <description>
+ Implementation of the OSGi Coordinator Service Specification 1.0
+ (Based on OSGi R 4.3 Draft 2 (31 Aug. 2010))
+ </description>
+ <version>0.0.1-SNAPSHOT</version>
+
+ <build>
+ <plugins>
+ <plugin>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>5</source>
+ <target>5</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <tags>
+ <tag>
+ <name>ThreadSafe</name>
+ <placement>a</placement>
+ <head>ThreadSafe</head>
+ </tag>
+ <tag>
+ <name>Provisional</name>
+ <placement>a</placement>
+ <head>
+ This is provisional API derived from OSGi R4.3 DRAFT 2 specification. This API is provided for testing purposes and gaining experience. As such this API is subject to change and will be removed once the OSGi R4.3 specification is finalized.
+ </head>
+ </tag>
+ </tags>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <version>2.0.1</version>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Bundle-Category>osgi</Bundle-Category>
+ <Bundle-SymbolicName>
+ ${artifactId}
+ </Bundle-SymbolicName>
+ <Bundle-DocURL>
+ http://felix.apache.org/site/apache-felix-coordination-service.html
+ </Bundle-DocURL>
+ <Export-Package>
+ org.apache.felix.jmx.service.coordination;
+ org.apache.felix.service.coordination;
+ version=1.0;
+ mandatory:="status"; status="provisional"
+ </Export-Package>
+ <Private-Package>
+ org.apache.felix.coordination.impl.*
+ </Private-Package>
+ <Bundle-Activator>
+ org.apache.felix.coordination.impl.Activator
+ </Bundle-Activator>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <dependencies>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ <version>4.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.2.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.enterprise</artifactId>
+ <version>4.2.0</version>
+ </dependency>
+ </dependencies>
+</project>
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
new file mode 100644
index 0000000..c84721a
--- /dev/null
+++ b/coordinator/src/main/java/org/apache/felix/coordination/impl/Activator.java
@@ -0,0 +1,77 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.coordination.impl;
+
+import java.util.Hashtable;
+
+import org.apache.felix.service.coordination.Coordinator;
+import org.osgi.framework.Bundle;
+import org.osgi.framework.BundleActivator;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.Constants;
+import org.osgi.framework.ServiceFactory;
+import org.osgi.framework.ServiceRegistration;
+
+@SuppressWarnings("deprecation")
+public class Activator implements BundleActivator {
+
+ private CoordinationMgr mgr;
+
+ private ServiceRegistration coordinatorService;
+
+ public void start(BundleContext context) throws Exception {
+ mgr = new CoordinationMgr();
+
+ ServiceFactory factory = new CoordinatorFactory(mgr);
+ Hashtable<String, String> props = new Hashtable<String, String>();
+ props.put(Constants.SERVICE_DESCRIPTION,
+ "Coordinator Service Implementation");
+ props.put(Constants.SERVICE_VENDOR, "The Apache Software Foundation");
+ coordinatorService = context.registerService(
+ Coordinator.class.getName(), factory, props);
+ }
+
+ public void stop(BundleContext context) throws Exception {
+ if (coordinatorService != null) {
+ coordinatorService.unregister();
+ coordinatorService = null;
+ }
+
+ mgr.cleanUp();
+ }
+
+ static final class CoordinatorFactory implements ServiceFactory {
+
+ private final CoordinationMgr mgr;
+
+ CoordinatorFactory(final CoordinationMgr mgr) {
+ this.mgr = mgr;
+ }
+
+ public Object getService(Bundle bundle, ServiceRegistration registration) {
+ return new CoordinatorImpl(bundle, mgr);
+ }
+
+ public void ungetService(Bundle bundle,
+ ServiceRegistration registration, Object service) {
+ // nothing to do
+ }
+
+ }
+}
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
new file mode 100644
index 0000000..f8ac3b0
--- /dev/null
+++ b/coordinator/src/main/java/org/apache/felix/coordination/impl/CoordinationImpl.java
@@ -0,0 +1,166 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.coordination.impl;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+
+import org.apache.felix.service.coordination.Coordination;
+import org.apache.felix.service.coordination.Participant;
+
+@SuppressWarnings("deprecation")
+public class CoordinationImpl implements Coordination {
+
+ private enum State {
+ /** Active */
+ ACTIVE,
+
+ /** Coordination termination started */
+ TERMINATING,
+
+ /** Coordination completed */
+ TERMINATED,
+
+ /** Coordination failed */
+ FAILED;
+ }
+
+ private final long id;
+
+ private final String name;
+
+ // TODO: timeout must be enforced
+ private long timeOutInMs;
+
+ private State state;
+
+ private boolean mustFail;
+
+ private boolean timeout;
+
+ private ArrayList<Participant> participants;
+
+ private HashMap<Class<?>, Object> variables;
+
+ public CoordinationImpl(final long id, final String name) {
+ this.id = id;
+ this.name = name;
+ this.state = State.ACTIVE;
+ this.participants = new ArrayList<Participant>();
+ this.variables = new HashMap<Class<?>, Object>();
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ long getId() {
+ return this.id;
+ }
+
+ void mustFail() {
+ this.mustFail = true;
+ }
+
+ void timeout() {
+ this.timeout = true;
+ }
+
+ long getTimeOut() {
+ return this.timeOutInMs;
+ }
+
+ public int end() throws IllegalStateException {
+ if (state == State.ACTIVE) {
+ int reason = OK;
+ if (mustFail || timeout) {
+ fail(new Exception());
+ reason = mustFail ? FAILED : TIMEOUT;
+ } else {
+ state = State.TERMINATING;
+ for (Participant part : participants) {
+ try {
+ part.ended(this);
+ } catch (Exception e) {
+ // TODO: log
+ reason = PARTIALLY_ENDED;
+ }
+ }
+ state = State.TERMINATED;
+ }
+ return reason;
+ }
+
+ // already terminated
+ throw new IllegalStateException();
+ }
+
+ public boolean fail(Throwable reason) {
+ if (state == State.ACTIVE) {
+ state = State.TERMINATING;
+ for (Participant part : participants) {
+ try {
+ part.failed(this);
+ } catch (Exception e) {
+ // TODO: log
+ }
+ }
+ state = State.FAILED;
+ return true;
+ }
+ return false;
+ }
+
+ public boolean terminate() {
+ if (state == State.ACTIVE) {
+ end();
+ return true;
+ }
+ return false;
+ }
+
+ public boolean isFailed() {
+ return state == State.FAILED;
+ }
+
+ public void addTimeout(long timeOutInMs) {
+ this.timeOutInMs = timeOutInMs;
+ }
+
+ public boolean participate(Participant p) {
+ if (state == State.ACTIVE) {
+ if (!participants.contains(p)) {
+ participants.add(p);
+ }
+ return true;
+ }
+ return false;
+ }
+
+ public Collection<Participant> getParticipants() {
+ return new ArrayList<Participant>(participants);
+ }
+
+ public Map<Class<?>, ?> getVariables() {
+ return variables;
+ }
+
+}
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
new file mode 100644
index 0000000..77f3e90
--- /dev/null
+++ b/coordinator/src/main/java/org/apache/felix/coordination/impl/CoordinationMgr.java
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.coordination.impl;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Stack;
+import java.util.concurrent.atomic.AtomicLong;
+import java.util.regex.Pattern;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeDataSupport;
+import javax.management.openmbean.OpenDataException;
+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;
+
+@SuppressWarnings("deprecation")
+public class CoordinationMgr implements CoordinatorMBean {
+
+ private ThreadLocal<Stack<Coordination>> threadStacks;
+
+ private final AtomicLong ctr;
+
+ private final Map<Long, CoordinationImpl> coordinations;
+
+ CoordinationMgr() {
+ ctr = new AtomicLong(-1);
+ coordinations = new HashMap<Long, CoordinationImpl>();
+ }
+
+ void unregister(final CoordinationImpl c) {
+ coordinations.remove(c.getId());
+ Stack<Coordination> stack = threadStacks.get();
+ if (stack != null) {
+ stack.remove(c);
+ }
+ }
+
+ void cleanUp() {
+ final Exception reason = new Exception();
+ for (Coordination c : coordinations.values()) {
+ c.fail(reason);
+ }
+ coordinations.clear();
+ }
+
+ public Coordination create(String name) {
+ long id = ctr.incrementAndGet();
+ CoordinationImpl c = new CoordinationImpl(id, name);
+ coordinations.put(id, c);
+ return c;
+ }
+
+ public Coordination begin(String name) {
+ return push(create(name));
+ }
+
+ public Coordination push(Coordination c) {
+ Stack<Coordination> stack = threadStacks.get();
+ if (stack == null) {
+ stack = new Stack<Coordination>();
+ threadStacks.set(stack);
+ }
+ return stack.push(c);
+ }
+
+ public Coordination pop() {
+ Stack<Coordination> stack = threadStacks.get();
+ if (stack != null && !stack.isEmpty()) {
+ return stack.pop();
+ }
+ return null;
+ }
+
+ public Coordination getCurrentCoordination() {
+ Stack<Coordination> stack = threadStacks.get();
+ if (stack != null && !stack.isEmpty()) {
+ return stack.peek();
+ }
+ return null;
+ }
+
+ public boolean alwaysFail(Throwable reason) {
+ CoordinationImpl current = (CoordinationImpl) getCurrentCoordination();
+ if (current != null) {
+ current.mustFail();
+ return true;
+ }
+ return false;
+ }
+
+ public Collection<Coordination> getCoordinations() {
+ ArrayList<Coordination> result = new ArrayList<Coordination>();
+ Stack<Coordination> stack = threadStacks.get();
+ if (stack != null) {
+ result.addAll(stack);
+ }
+ return result;
+ }
+
+ public boolean participate(Participant participant)
+ throws CoordinationException {
+ // TODO: check for multi-pariticipation and block
+ Coordination current = getCurrentCoordination();
+ if (current != null) {
+ current.participate(participant);
+ return true;
+ }
+ return false;
+ }
+
+ public Coordination participateOrBegin(Participant ifActive) {
+ // TODO: check for multi-pariticipation and block
+ Coordination current = getCurrentCoordination();
+ if (current == null) {
+ current = begin("implicit");
+ }
+ current.participate(ifActive);
+ return current;
+ }
+
+ // ---------- CoordinatorMBean interface
+
+ public TabularData listCoordinations(String regexFilter) {
+ Pattern p = Pattern.compile(regexFilter);
+ TabularData td = new TabularDataSupport(COORDINATIONS_TYPE);
+ for (CoordinationImpl c : coordinations.values()) {
+ if (p.matcher(c.getName()).matches()) {
+ try {
+ td.put(fromCoordination(c));
+ } catch (OpenDataException e) {
+ // TODO: log
+ }
+ }
+ }
+ return td;
+ }
+
+ public CompositeData getCoordination(long id) throws IOException {
+ CoordinationImpl c = coordinations.get(id);
+ if (c != null) {
+ try {
+ return fromCoordination(c);
+ } catch (OpenDataException e) {
+ throw new IOException(e.toString());
+ }
+ }
+ throw new IOException("No such Coordination " + id);
+ }
+
+ public boolean fail(long id, String reason) {
+ Coordination c = coordinations.get(id);
+ if (c != null) {
+ return c.fail(new Exception(reason));
+ }
+ return false;
+ }
+
+ public void addTimeout(long id, long timeout) {
+ Coordination c = coordinations.get(id);
+ if (c != null) {
+ c.addTimeout(timeout);
+ }
+ }
+
+ private CompositeData fromCoordination(final CoordinationImpl c)
+ throws OpenDataException {
+ return new CompositeDataSupport(COORDINATION_TYPE, new String[] { ID,
+ NAME, TIMEOUT }, new Object[] { c.getId(), c.getName(),
+ c.getTimeOut() });
+ }
+}
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
new file mode 100644
index 0000000..dd5f5c0
--- /dev/null
+++ b/coordinator/src/main/java/org/apache/felix/coordination/impl/CoordinatorImpl.java
@@ -0,0 +1,91 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.felix.coordination.impl;
+
+import java.util.Collection;
+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.osgi.framework.Bundle;
+
+@SuppressWarnings("deprecation")
+public class CoordinatorImpl implements Coordinator {
+
+ private final Bundle owner;
+
+ private final CoordinationMgr mgr;
+
+ CoordinatorImpl(final Bundle owner, final CoordinationMgr mgr) {
+ this.owner = owner;
+ this.mgr = mgr;
+ }
+
+ public Coordination create(String name) {
+ // TODO: check permission
+ return mgr.create(name);
+ }
+
+ void unregister(final CoordinationImpl c) {
+ // TODO: check permission
+ mgr.unregister(c);
+ }
+
+ public Coordination begin(String name) {
+ // TODO: check permission
+ return mgr.begin(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
+ return mgr.alwaysFail(reason);
+ }
+
+ public Collection<Coordination> getCoordinations() {
+ // TODO: check permission
+ return mgr.getCoordinations();
+ }
+
+ public boolean participate(Participant participant)
+ throws CoordinationException {
+ // TODO: check permission
+ return mgr.participate(participant);
+ }
+
+ public Coordination participateOrBegin(Participant ifActive) {
+ // TODO: check permission
+ return mgr.participateOrBegin(ifActive);
+ }
+
+}
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/coordination/CoordinatorMBean.java
new file mode 100644
index 0000000..4b4a616
--- /dev/null
+++ b/coordinator/src/main/java/org/apache/felix/jmx/service/coordination/CoordinatorMBean.java
@@ -0,0 +1,151 @@
+/*
+ * 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.jmx.service.coordination;
+
+import java.io.IOException;
+
+import javax.management.openmbean.CompositeData;
+import javax.management.openmbean.CompositeType;
+import javax.management.openmbean.SimpleType;
+import javax.management.openmbean.TabularData;
+import javax.management.openmbean.TabularType;
+
+import org.osgi.jmx.Item;
+
+/**
+ * This MBean provides the management interface to the OSGi Coordinator Service
+ *
+ * @ThreadSafe
+ * @Provisional
+ */
+@Deprecated
+public interface CoordinatorMBean {
+
+ /**
+ * User Admin MBean object name.
+ */
+ public static final String OBJECTNAME = "osgi.compendium:service=coordinator,version=1.0";
+
+ /**
+ * The key NAME, used in NAME_ITEM.
+ */
+ public static final String NAME = "Name";
+
+ /**
+ * The item for the user name for an authorization object. The key is NAME
+ * and the type is SimpleType.STRING.
+ */
+ public static final org.osgi.jmx.Item NAME_ITEM = new Item(NAME, null,
+ SimpleType.STRING, (String[]) null);
+
+ /**
+ * The key ID, used in ID_ITEM.
+ */
+ public static final String ID = "Id";
+
+ /**
+ * The item for the id of an Coordination object. The key is ID and the type
+ * is SimpleType.LONG. The id must be generated by the Mbean and map to a
+ * unique Coordination (which should no be pinned in memory because of
+ * this).
+ */
+ public static final org.osgi.jmx.Item ID_ITEM = new Item(ID, null,
+ SimpleType.LONG, (String[]) null);
+
+ /**
+ * The key TIMEOUT, used in TIMEOUT_ITEM.
+ */
+ public static final String TIMEOUT = "Timeout";
+
+ /**
+ * The item for the id of an Coordination object. The key is TIMEOUT and the
+ * type is SimpleType.LONG.
+ */
+ public static final org.osgi.jmx.Item TIMEOUT_ITEM = new Item(TIMEOUT,
+ null, SimpleType.LONG, (String[]) null);
+
+ /**
+ * The key COORDINATION, used in COORDINATION_TYPE
+ */
+ public static final String COORDINATION = "Coordination";
+
+ /**
+ * Interface Coordination
+ */
+ public static final CompositeType COORDINATION_TYPE = Item.compositeType(
+ "", null, ID_ITEM, NAME_ITEM, TIMEOUT_ITEM);
+
+ /**
+ * The key COORDINATIONS, used in COORDINATIONS_TYPE
+ * <p>
+ * fmeschbe note: This constant is added because it is needed for the
+ * {@link #COORDINATIONS_TYPE} definition
+ */
+ public static final String COORDINATIONS = "Coordinations";
+
+ /**
+ * Defines a list of COORDINATION_TYPE
+ * <p>
+ * fmeschbe note: The draft 2 spec defines this to be ArrayType but to
+ * use it for {@link #listCoordinations(String)} this constant must
+ * be a <code>TabularType</code>.
+ */
+ public static final TabularType COORDINATIONS_TYPE = Item.tabularType(
+ COORDINATIONS, null, COORDINATION_TYPE, ID, NAME, TIMEOUT);
+
+ /**
+ * List the current coordinations. The Composite Data is typed by
+ * COORDINATIONS_TYPE.
+ *
+ * @param regexFilter a regular expression filter on the coordination name
+ * @return the Coordinations typed by COORDINATIONS_TYPE.
+ * @throws IOException if the operation fails
+ */
+ TabularData listCoordinations(String regexFilter) throws IOException;
+
+ /**
+ * Get a Coordination. The Composite Data is typed by COORDINATION_TYPE.
+ *
+ * @param id The id of a Coordination
+ * @return the Coordinations typed by COORDINATION_TYPE.
+ * @throws IOException if the operation fails
+ */
+ CompositeData getCoordination(long id) throws IOException;
+
+ /**
+ * Fail a Coordination.
+ *
+ * @param id The id of the coordination to be failed.
+ * @param reason The reason the coordination should be failed. The
+ * implementation of the MBean should create a
+ * Throwable/Exception with this reason in order to fail the
+ * specified Coordination
+ * @return true if the coordination was failed by this call, otherwise
+ * false.
+ * @throws IOException
+ * @see Coordination#fail(Throwable)
+ */
+ boolean fail(long id, String reason) throws IOException;
+
+ /**
+ * Set/Change the timeout of a Coordination.
+ *
+ * @param id The id of the Coordination
+ * @param timeout The nr of milliseconds for the next timeout.
+ * @throws IOException
+ */
+ void addTimeout(long id, long timeout) throws 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/coordination/package-info.java
new file mode 100644
index 0000000..5989a55
--- /dev/null
+++ b/coordinator/src/main/java/org/apache/felix/jmx/service/coordination/package-info.java
@@ -0,0 +1,39 @@
+/*
+ * 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.
+ */
+/**
+ * OSGi JMX Coordination 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.
+ * <p>
+ * This package has two types of users: the consumers that use the API in this
+ * 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.jmx.service.coordination; 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.jmx.service.coordination; version="[1.0,1.1)"; status="provisional"</code>
+ * </blockquote>
+ *
+ * @Provisional
+ */
+@Deprecated
+package org.apache.felix.jmx.service.coordination;
+
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
new file mode 100644
index 0000000..6b785d0
--- /dev/null
+++ b/coordinator/src/main/java/org/apache/felix/service/coordination/Coordination.java
@@ -0,0 +1,204 @@
+/*
+ * 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();
+
+ /**
+ * 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
new file mode 100644
index 0000000..3e180cf
--- /dev/null
+++ b/coordinator/src/main/java/org/apache/felix/service/coordination/CoordinationException.java
@@ -0,0 +1,78 @@
+/*
+ * 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/CoordinationPermission.java b/coordinator/src/main/java/org/apache/felix/service/coordination/CoordinationPermission.java
new file mode 100644
index 0000000..5dd765f
--- /dev/null
+++ b/coordinator/src/main/java/org/apache/felix/service/coordination/CoordinationPermission.java
@@ -0,0 +1,136 @@
+/*
+ * 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.security.BasicPermission;
+
+/**
+ * The name parameter of the Permission is a filter expression. It asserts the
+ * bundle that is associated with the coordination. Additionally, the following
+ * attributes can be asserted:
+ * <ol>
+ * <li>coordination.name - The name of the coordination
+ * <table>
+ * <tr>
+ * <td>Coordinator</td>
+ * <td>INITIATE</td>
+ * <td>PARTICIPATE</td>
+ * <td>ADMIN</td>
+ * <td>NONE</td>
+ * </tr>
+ * <tr>
+ * <td>alwaysFail(String)</td>
+ * <td></td>
+ * <td></td>
+ * <td>-</td>
+ * </tr>
+ * <tr>
+ * <td>begin(String) + -</td>
+ * </tr>
+ * <tr>
+ * <td>getCoordinations() + -</td>
+ * </tr>
+ * <tr>
+ * <td>isActive() + + + -</td>
+ * </tr>
+ * <tr>
+ * <td>isFailed() + + + -</td>
+ * </tr>
+ * <tr>
+ * <td>participate(Participant) + -</td>
+ * </tr>
+ * <tr>
+ * <td>participateOrBegin(Participant) + and + -</td>
+ * </tr>
+ * <tr>
+ * <td>Coordination</td>
+ * </tr>
+ * <tr>
+ * <td>end() +</td>
+ * </tr>
+ * <tr>
+ * <td>fail(String) +</td>
+ * </tr>
+ * <tr>
+ * <td>getName() +</td>
+ * </tr>
+ * <tr>
+ * <td>getParticipants() + -</td>
+ * </tr>
+ * <tr>
+ * <td>isFailed() +</td>
+ * </tr>
+ * <tr>
+ * <td>setTimeout(long) + + -</td>
+ * </tr>
+ * <tr>
+ * <td>terminate() +</td>
+ * </tr>
+ * </table>
+ * </li>
+ * </ol>
+ *
+ * @Provisional
+ */
+@Deprecated
+public class CoordinationPermission extends BasicPermission {
+
+ private static final long serialVersionUID = 1566605398519619478L;
+
+ /**
+ * Initiate a Coordination. An owner of this permission can initiate, end,
+ * fail, and terminate a Coordination.
+ */
+ public static final String INITIATE = "initiate";
+
+ /**
+ * The action string admin.
+ */
+ public static final String ADMIN = "admin";
+
+ /**
+ * The action string participate.
+ */
+ public static final String PARTICIPATE = "participate";
+
+ /**
+ * 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:
+ *
+ * @param filterExpression A filter expression asserting the bundle
+ * associated with the coordination.
+ * @param actions A comma separated combination of INITIATE, ADMIN,
+ * PARTICIPATE.
+ */
+ public CoordinationPermission(String filterExpression, String actions) {
+ super(filterExpression, actions);
+ }
+
+ /**
+ * 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 actions The set of actions required, which is a combination of
+ * INITIATE, ADMIN, PARTICIPATE.
+ */
+ public CoordinationPermission(org.osgi.framework.Bundle bundle,
+ String coordinationName, String actions) {
+ super(coordinationName, actions);
+ }
+}
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
new file mode 100644
index 0000000..4be5763
--- /dev/null
+++ b/coordinator/src/main/java/org/apache/felix/service/coordination/Coordinator.java
@@ -0,0 +1,203 @@
+/*
+ * 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;
+
+ /**
+ * Participate if there is an active Coordination otherwise initiate a new
+ * Coordination. This method is a short cut that atomically checks if there
+ * is a current Coordination. It either returns a new current Coordination
+ * object if no current Coordination exists or it adds the participant to
+ * the current Coordination. Notice that this method can block until the
+ * participant is free to participate on the current or new Coordination.
+ * This method makes it simple to start a new Coordination or to participate
+ * in an existing Coordination. See begin(String) and
+ * participate(Participant) for the details of those methods.
+ *
+ * @param ifActive The participant
+ * @return null if there is a current Coordination otherwise a newly
+ * initiated Coordination.
+ * @throws SecurityException This method requires the action for the current
+ * Coordination, if any. Otherwise it requires to create a new
+ * coordination.
+ */
+ Coordination participateOrBegin(Participant ifActive);
+
+ /**
+ * 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
new file mode 100644
index 0000000..2348c24
--- /dev/null
+++ b/coordinator/src/main/java/org/apache/felix/service/coordination/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.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/coordination/package-info.java b/coordinator/src/main/java/org/apache/felix/service/coordination/package-info.java
new file mode 100644
index 0000000..79837d3
--- /dev/null
+++ b/coordinator/src/main/java/org/apache/felix/service/coordination/package-info.java
@@ -0,0 +1,38 @@
+/*
+ * 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.
+ */
+/**
+ * Coordination 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.
+ * <p>
+ * This package has two types of users: the consumers that use the API in
+ * this 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>
+ * </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>
+ * </blockquote>
+ *
+ * @Provisional
+ */
+@Deprecated
+package org.apache.felix.service.coordination;
\ No newline at end of file