From a3cbf8e5ffabac239cd965d8c0f9c680a83246f7 Mon Sep 17 00:00:00 2001 From: antelder Date: Mon, 11 May 2009 07:45:29 +0000 Subject: Add a new soap/jms transport module copied from the Apache WS Commons transports but with the code backported to work with Axis2 1.4.1 git-svn-id: http://svn.us.apache.org/repos/asf/tuscany@773489 13f79535-47bb-0310-9956-ffa450edef68 --- .../transport/base/tracker/AxisServiceTracker.java | 245 +++++++++++++++++++++ 1 file changed, 245 insertions(+) create mode 100644 branches/sca-java-1.x/modules/binding-ws-axis2-jms/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/transport/base/tracker/AxisServiceTracker.java (limited to 'branches/sca-java-1.x/modules/binding-ws-axis2-jms/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/transport/base/tracker/AxisServiceTracker.java') diff --git a/branches/sca-java-1.x/modules/binding-ws-axis2-jms/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/transport/base/tracker/AxisServiceTracker.java b/branches/sca-java-1.x/modules/binding-ws-axis2-jms/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/transport/base/tracker/AxisServiceTracker.java new file mode 100644 index 0000000000..fca85ee71e --- /dev/null +++ b/branches/sca-java-1.x/modules/binding-ws-axis2-jms/src/main/java/org/apache/tuscany/sca/binding/ws/axis2/transport/base/tracker/AxisServiceTracker.java @@ -0,0 +1,245 @@ +/* + * 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.tuscany.sca.binding.ws.axis2.transport.base.tracker; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Queue; +import java.util.Set; + +import org.apache.axiom.om.OMElement; +import org.apache.axis2.AxisFault; +import org.apache.axis2.description.AxisModule; +import org.apache.axis2.description.AxisService; +import org.apache.axis2.description.AxisServiceGroup; +import org.apache.axis2.description.Parameter; +import org.apache.axis2.engine.AxisConfiguration; +import org.apache.axis2.engine.AxisEvent; +import org.apache.axis2.engine.AxisObserver; + +/** + *

Tracks services deployed in a given {@link AxisConfiguration}. + * The tracker is configured with references to three objects:

+ *
    + *
  1. An {@link AxisConfiguration} to watch.
  2. + *
  3. An {@link AxisServiceFilter} restricting the services to track.
  4. + *
  5. An {@link AxisServiceTrackerListener} receiving tracking events.
  6. + *
+ *

An instance of this class maintains an up-to-date list of services + * satisfying all of the following criteria:

+ *
    + *
  1. The service is deployed in the given {@link AxisConfiguration}.
  2. + *
  3. The service is started, i.e. {@link AxisService#isActive()} returns true.
  4. + *
  5. The service matches the criteria specified by the given + * {@link AxisServiceFilter} instance.
  6. + *
+ *

Whenever a service appears on the list, the tracker will call + * {@link AxisServiceTrackerListener#serviceAdded(AxisService)}. When a service disappears, it + * will call {@link AxisServiceTrackerListener#serviceRemoved(AxisService)}.

+ *

When the tracker is created, it is initially in the stopped state. In this state no + * events will be sent to the listener. It can be started using {@link #start()} and stopped again + * using {@link #stop()}. The tracker list is defined to be empty when the tracker is in the + * stopped state. This implies that a call to {@link #start()} will generate + * {@link AxisServiceTrackerListener#serviceAdded(AxisService)} events for all services that meet + * the above criteria at that point in time. In the same way, {@link #stop()} will generate + * {@link AxisServiceTrackerListener#serviceRemoved(AxisService)} events for the current entries + * in the list.

+ *

As a corollary the tracker guarantees that during a complete lifecycle (start-stop), + * there will be exactly one {@link AxisServiceTrackerListener#serviceRemoved(AxisService)} event + * for every {@link AxisServiceTrackerListener#serviceAdded(AxisService)} event and vice-versa. + * This property is important when the tracker is used to allocate resources for a dynamic set + * of services.

+ * + *

Limitations

+ * + *

The tracker is not able to detect property changes on services. E.g. if a service initially + * matches the filter criteria, but later changes so that it doesn't match the criteria any more, + * the tracker will not be able to detect this and the service will not be removed from the tracker + * list.

+ */ +public class AxisServiceTracker { + private final AxisObserver observer = new AxisObserver() { + public void init(AxisConfiguration axisConfig) {} + + public void serviceUpdate(AxisEvent event, final AxisService service) { + switch (event.getEventType()) { + case AxisEvent.SERVICE_DEPLOY: + case AxisEvent.SERVICE_START: + if (filter.matches(service)) { + boolean pending; + synchronized (lock) { + if (pending = (pendingActions != null)) { + pendingActions.add(new Runnable() { + public void run() { + serviceAdded(service); + } + }); + } + } + if (!pending) { + serviceAdded(service); + } + } + break; + case AxisEvent.SERVICE_REMOVE: + case AxisEvent.SERVICE_STOP: + // Don't check filter here because the properties of the service may have + // changed in the meantime. + boolean pending; + synchronized (lock) { + if (pending = (pendingActions != null)) { + pendingActions.add(new Runnable() { + public void run() { + serviceRemoved(service); + } + }); + } + } + if (!pending) { + serviceRemoved(service); + } + } + } + + public void moduleUpdate(AxisEvent event, AxisModule module) {} + public void addParameter(Parameter param) throws AxisFault {} + public void removeParameter(Parameter param) throws AxisFault {} + public void deserializeParameters(OMElement parameterElement) throws AxisFault {} + public Parameter getParameter(String name) { return null; } + public ArrayList getParameters() { return null; } + public boolean isParameterLocked(String parameterName) { return false; } + public void serviceGroupUpdate(AxisEvent event, AxisServiceGroup serviceGroup) {} + }; + + private final AxisConfiguration config; + final AxisServiceFilter filter; + private final AxisServiceTrackerListener listener; + + /** + * Object used to synchronize access to {@link #pendingActions} and {@link #services}. + */ + final Object lock = new Object(); + + /** + * Queue for notifications received by the {@link AxisObserver} during startup of the tracker. + * We need this because the events may already be reflected in the list of services returned + * by {@link AxisConfiguration#getServices()} (getting the list of currently deployed services + * and adding the observer can't be done atomically). It also allows us to make sure that + * events are sent to the listener in the right order, e.g. when a service is being removed + * during startup of the tracker. + */ + Queue pendingActions; + + /** + * The current list of services. null if the tracker is stopped. + */ + private Set services; + + public AxisServiceTracker(AxisConfiguration config, AxisServiceFilter filter, + AxisServiceTrackerListener listener) { + this.config = config; + this.filter = filter; + this.listener = listener; + } + + /** + * Check whether the tracker is started. + * + * @return true if the tracker is started + */ + public boolean isStarted() { + return services != null; + } + + /** + * Start the tracker. + * + * @throws IllegalStateException if the tracker has already been started + */ + public void start() { + if (services != null) { + throw new IllegalStateException(); + } + synchronized (lock) { + pendingActions = new LinkedList(); + config.addObservers(observer); + services = new HashSet(); + } + for (Object o : config.getServices().values()) { + AxisService service = (AxisService)o; + if (service.isActive() && filter.matches(service)) { + serviceAdded(service); + } + } + while (true) { + Runnable action; + synchronized (lock) { + action = pendingActions.poll(); + if (action == null) { + pendingActions = null; + break; + } + } + action.run(); + } + } + + void serviceAdded(AxisService service) { + // callListener may be false because the observer got an event for a service that + // was already in the initial list of services retrieved by AxisConfiguration#getServices. + boolean callListener; + synchronized (lock) { + callListener = services.add(service); + } + if (callListener) { + listener.serviceAdded(service); + } + } + + void serviceRemoved(AxisService service) { + // callListener may be false because the observer invokes this method without applying the + // filter. + boolean callListener; + synchronized (lock) { + callListener = services.remove(service); + } + if (callListener) { + listener.serviceRemoved(service); + } + } + + /** + * Stop the tracker. + * + * @throws IllegalStateException if the tracker is not started + */ + public void stop() { + if (services == null) { + throw new IllegalStateException(); + } + // TODO: This is very bad, but AxisConfiguration has no removeObserver method! + config.getObserversList().remove(observer); + for (AxisService service : services) { + listener.serviceRemoved(service); + } + services = null; + } +} -- cgit v1.2.3