You are viewing a plain text version of this content. The canonical link for it is here.
Posted to kandula-dev@ws.apache.org by da...@apache.org on 2007/06/18 22:10:03 UTC
svn commit: r548471 [1/2] -
/webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/
Author: dasarath
Date: Mon Jun 18 13:10:02 2007
New Revision: 548471
URL: http://svn.apache.org/viewvc?view=rev&rev=548471
Log:
Hannes Erven, Georg Hicker
Added:
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/AbstractCoordParticipant.java
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/AbstractCoordParticipantProxy.java
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAAtomicOutcome.java
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BACoordinator.java
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BACoordinatorService.java
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwCCCoordParticipant.java
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwCCParticipantProxy.java
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwPCCoordParticipant.java
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwPCParticipantProxy.java
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwithAtomicOutcomeCoordinator.java
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwithMixedOutcomeCoordinator.java
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/CoordinationState.java
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/CoordinatorIService.java
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/CoordinatorIService_Atomic.java
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/CoordinatorIService_Mixed.java
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/InitiatorProxy.java
webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/InvalidOutcomeAssertion.java
Added: webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/AbstractCoordParticipant.java
URL: http://svn.apache.org/viewvc/webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/AbstractCoordParticipant.java?view=auto&rev=548471
==============================================================================
--- webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/AbstractCoordParticipant.java (added)
+++ webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/AbstractCoordParticipant.java Mon Jun 18 13:10:02 2007
@@ -0,0 +1,461 @@
+/*
+ * Copyright 2007 The Apache Software Foundation.
+ *
+ * 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.
+ *
+ * @author Hannes Erven, Georg Hicker
+ */
+
+package org.apache.kandula.coordinator.ba.coordinator;
+
+import java.rmi.RemoteException;
+
+import javax.xml.namespace.QName;
+import javax.xml.soap.Name;
+
+import org.apache.axis.encoding.AnyContentType;
+import org.apache.axis.message.addressing.EndpointReference;
+import org.apache.kandula.coordinator.Callback;
+import org.apache.kandula.coordinator.Coordinator;
+import org.apache.kandula.coordinator.TimedOutException;
+import org.apache.kandula.coordinator.ba.AbstractStateTransition;
+import org.apache.kandula.coordinator.ba.State;
+import org.apache.kandula.coordinator.ba.StateTransitionFault;
+import org.apache.kandula.coordinator.ba.StateTransitionIgnore;
+import org.apache.kandula.coordinator.ba.StateTransitionResend;
+import org.apache.kandula.coordinator.ba.StateTransitionResendPreviousState;
+import org.apache.kandula.coordinator.ba.StateTransitionState;
+import org.apache.kandula.coordinator.ba.WrongMethodCallException;
+import org.apache.kandula.wsba.ExceptionType;
+import org.apache.kandula.wsba.NotificationType;
+import org.apache.kandula.wsba.StateType;
+import org.apache.kandula.wsba.StatusType;
+
+/**
+ * Instances of this class represent business activity participants that are registered
+ * for a specific protocol in a given coordination context, as seen by the coordinator.
+ *
+ * Participant instances on the "client" (participant) side are represented by @see org.apache.kandula.coordinator.ba.participant.AbstractParticipant and its
+ * subclasses.
+ *
+ * For each coordination protocol exists a subclass implementing providing
+ * the specific behaviour required:
+ * <ul>
+ * <li>for the Participant Completion protocol, @see org.apache.kandula.coordinator.ba.coordinator.BAwPCCoordParticipant
+ * <li>for the Coordinator Completion protocol, @see org.apache.kandula.coordinator.ba.coordinator.BAwCCCoordParticipant
+ * </ul>
+ *
+ * @author Hannes Erven, Georg Hicker (C) 2006
+ *
+ */
+public abstract class AbstractCoordParticipant implements Callback {
+
+ /**
+ * The participant's state, as seen by the coordinator
+ */
+ protected CoordinationState currState;
+
+ /**
+ * My participant ID
+ */
+ private final String myParticipantID;
+
+ /**
+ * My participant's EPR (this is where the coordinator
+ * sends messages intended for the participant to)
+ */
+ private final EndpointReference myParticipantEPR;
+
+ /**
+ * My transaction context
+ */
+ private final BACoordinator transactionContext;
+
+ /**
+ * Matchcode provided by the initiator to identify the participant,
+ * unique in a given coordination context
+ */
+ private final String matchcode;
+
+ /**
+ * The default constructor. Use this to create a new Participant.
+ * EnpointReference and Protocoltype can not be changed afterwards.
+ *
+ * This constructor is used by the BACoordinator when processing a register
+ * request, after all preconditions have been successfully checked and
+ * the participant is finally enrolled.
+ * (Actually, the BACoordinator invokes the constructor on one of the subclasses,
+ * which in turn pushes the request up here.)
+
+ * @param participantID
+ * This participant's participant ID, generated by the coordinator.
+ * @param participantEPR
+ * The EndpointReference of the Participant.
+ * @param context
+ * The transaction context the participant registered for.
+ * @param matchcodeP
+ * The matchcode the initiator assigned to this participant.
+ */
+ protected AbstractCoordParticipant(
+ final String participantID,
+ final EndpointReference participantEPR,
+ final BACoordinator context,
+ final String matchcodeP
+ ) {
+ super();
+ this.myParticipantID = participantID;
+ this.myParticipantEPR = participantEPR;
+ this.currState = new CoordinationState(getProtocolIdentifier());
+ this.transactionContext = context;
+ this.matchcode = matchcodeP;
+ }
+
+ /**
+ * Getter for the ProtocolType
+ *
+ * @return The ProtocolType
+ */
+ public abstract QName getProtocolIdentifier();
+
+ /**
+ * Getter for the State the Participant is in.
+ *
+ * @return The State
+ */
+ public QName getCurrentState() {
+ return this.currState.getCurrentState();
+ }
+
+ /**
+ * Gets the participant proxy for this participant.
+ * @return The participant proxy object.
+ */
+ public abstract AbstractCoordParticipantProxy getParticipantProxy();
+
+ /*
+ * Below are the methods that can be called on any WS-BA participant
+ * These methods are OUTGOING !
+ */
+
+ /**
+ * Tells the participant to cancel
+ * @throws RemoteException A RemoteException that occured while sending a message to the participant.
+ */
+ public void tellCancel() throws RemoteException{
+ this.tell(State.MESSAGE_CANCEL);
+ }
+
+ /**
+ * Tells the participant to close
+ * @throws RemoteException A RemoteException that occured while sending a message to the participant.
+ */
+ public void tellClose() throws RemoteException{
+ this.tell(State.MESSAGE_CLOSE);
+ }
+
+ /**
+ * Tells the participant the current coordinator's state.
+ *
+ * Attention: this method does *direct* calls to the participant's
+ * web service and skips the use of @see #tell(QName) and @see #tellAgain(QName),
+ * since state queries are always allowed and do not modify anything here.
+ *
+ * @throws RemoteException A RemoteException that occured while sending a message to the participant.
+ */
+ public void tellStatus() throws RemoteException {
+ final StatusType st = new StatusType(
+ StateType.fromValue(this.currState.getCurrentState()),
+ null
+ );
+ this.getParticipantProxy().statusOperation(st);
+ }
+
+ /**
+ * Tell the participant to report its state
+ * @throws RemoteException A RemoteException that occured while sending a message to the participant.
+ */
+ public void tellGetStatus() throws RemoteException {
+ this.tell(State.MESSAGE_STATUS);
+ }
+
+ /**
+ * Tell the participant to compensate
+ * @throws RemoteException A RemoteException that occured while sending a message to the participant.
+ */
+ public void tellCompensate() throws RemoteException {
+ this.tell(State.MESSAGE_COMPENSATE);
+ }
+
+ /**
+ * Tell the participant that "fault" was accepted
+ * @throws RemoteException A RemoteException that occured while sending a message to the participant.
+ */
+ public void tellFaulted() throws RemoteException {
+ this.tell(State.MESSAGE_FAULTED);
+ }
+
+ /**
+ * Tell the participant that "exit" was accepted
+ * @throws RemoteException A RemoteException that occured while sending a message to the participant.
+ */
+ public void tellExited() throws RemoteException {
+ this.tell(State.MESSAGE_EXITED);
+ }
+
+ /*
+ * Here come the Callback implementation methods
+ */
+
+ /**
+ * Get this participant's ID
+ * (Don't mix this one up with the matchcode: the participant ID is
+ * created by the BACoordinator, the matchcode is assigned
+ * by the initiator)
+ *
+ * @return This participant's id.
+ */
+ public String getID() {
+ return this.myParticipantID;
+ }
+
+ /**
+ * Handle fault
+ * @param code The fault code.
+ */
+ public void onFault(final Name code) {
+ // TODO WSBA Handle faults
+ if (code != null)
+ code.toString();
+ }
+
+ /**
+ * Handle timeout
+ * @throws TimedOutException //TODO WSBA Handle timeouts
+ */
+ public void timeout() throws TimedOutException {
+ // TODO WSBA Handle faults
+
+ if (false)
+ throw new TimedOutException();
+ }
+
+ /**
+ * Get the participant's EPR. This EPR is used
+ * to send messages to the participant.
+ * @return This participant's endpoint reference.
+ */
+ public EndpointReference getEndpointReference() {
+ return this.myParticipantEPR;
+ }
+
+ /**
+ * Accept an incoming message and do what is to be done.
+ *
+ * @param messageType The incoming message's type
+ * @param params The params the message contained
+ * @throws RemoteException A RemoteException that occured while sending a message to the participant.
+ */
+ protected void handleIncomingMessage(final QName messageType, final NotificationType params) throws RemoteException{
+ try{
+ final AbstractStateTransition transition = this.currState.transistStateByMessage(messageType);
+ System.out.println("Participant Incoming "+messageType+", Transition: "+transition);
+
+ handleTransition(transition, params);
+ }catch(RemoteException e){
+ throw e;
+ }catch(Exception e){
+ throw Coordinator.INVALID_STATE_SOAP_FAULT() ;
+ }
+ }
+ /**
+ * Accept an incoming message and do what is to be done.
+ *
+ * @param messageType The incoming message's type
+ * @param params The params the message contained
+ * @throws RemoteException A RemoteException that occured while sending a message to the participant.
+ */
+ protected void handleIncomingMessage(final QName messageType, final StatusType params) throws RemoteException{
+ try{
+ final AbstractStateTransition transition = this.currState.transistStateByMessage(messageType);
+ System.out.println("+ Transition: "+transition);
+
+ handleTransition(transition, params);
+ }catch(RemoteException e){
+ throw e;
+ }catch(Exception e){
+ throw Coordinator.INVALID_STATE_SOAP_FAULT();
+ }
+ }
+ /**
+ * Accept an incoming message and do what is to be done.
+ *
+ * @param messageType The incoming message's type
+ * @param params The params the message contained
+ * @throws RemoteException A RemoteException that occured while sending a message to the participant.
+ */
+ public void handleIncomingMessage(final QName messageType, final ExceptionType params) throws RemoteException{
+ try{
+ final AbstractStateTransition transition = this.currState.transistStateByMessage(messageType);
+ System.out.println("+ Transition: "+transition);
+
+ handleTransition(transition, params);
+ }catch(RemoteException e){
+ throw e;
+ }catch(Exception e){
+ throw Coordinator.INVALID_STATE_SOAP_FAULT() ;
+ }
+ }
+
+ /**
+ * Handle a state transition. This method accepts a transition that was obtained by comparing
+ * the participant's current state and the incoming message against the protocol state table.
+ *
+ * This method executes the actions given by the transition, e.g. moving into new state, notifying
+ * the initiator about that, throwing faults, sending acknownledgements etc.
+ *
+ *
+ * @param transition The transition object from State
+ * @param params Any parameters that the participant sent along
+ * @throws WrongMethodCallException
+ * @throws RemoteException
+ */
+ private void handleTransition(
+ final AbstractStateTransition transition,
+ final AnyContentType params
+ ) throws WrongMethodCallException, RemoteException{
+
+ // Suppress compiler warning about unused parameter
+ if (params != null)
+ params.toString();
+
+ // Check if there actually is a transition
+ if (transition == null)
+ return;
+
+ if (transition instanceof StateTransitionFault){
+ final StateTransitionFault stf = (StateTransitionFault) transition;
+ throw stf.getAxisFault();
+
+ }else if(transition instanceof StateTransitionIgnore){
+ // Ignore
+
+ }else if (transition instanceof StateTransitionResend){
+ final StateTransitionResend str = (StateTransitionResend) transition;
+ this.tellAgain(str.getMessageToResend());
+
+ }else if (transition instanceof StateTransitionResendPreviousState){
+ final QName messageToResend = this.currState.getMessageForTransition(this.currState.getLastState(), this.currState.getSecondLastState());
+ tellAgain(messageToResend);
+
+ }else if (transition instanceof StateTransitionState){
+ final StateTransitionState sts = (StateTransitionState) transition;
+ System.out.println(" Participant changed state to "+sts.getState());
+ this.transactionContext.handleStateTransition(this, sts.getState());
+
+ }else{
+ throw new IllegalArgumentException("Sorry, handleTransition does not know how to handle "+transition);
+ }
+ }
+
+ /**
+ * Send some message to the participant. This method may only be used with participant operations
+ * that do not require arguments.
+ * This method ensures that the message to be sent is valid in the
+ * current state of the participant and throws an exception if not.
+ * If the message is OK, it is sent out and the associated state change is performed.
+ *
+ * Calls @see #tellAgain(QName) to actually deliver the message.
+ *
+ * This method is called from all the public tellXXX() methods in this class,
+ * e.g. @see #tellCancel().
+ *
+ * @param message The message to send.
+ * @throws RemoteException If the participant did not accept the message
+ */
+ protected synchronized void tell(final QName message) throws RemoteException{
+ final QName stateBefore = this.currState.getCurrentState();
+
+ if (this.currState.handleOutgoingMessage(message) ){
+ // Message was OK and the new state has been set
+
+ final QName stateAfter = this.currState.getCurrentState();
+
+ if (stateBefore != null && (! stateBefore.equals(stateAfter))){
+ this.transactionContext.handleStateTransition(this, stateAfter);
+ }
+
+ this.tellAgain(message);
+ }else{
+ // Error !
+ throw State.GET_INVALID_STATE_SOAP_FAULT();
+ }
+ }
+ /**
+ * Forward some message to the participant. This method may only be used with participant operations
+ * that do not require arguments.
+ * This method does no more than send the message out.
+ * @param message The message to send.
+ * @throws RemoteException If the participant did not accept the message
+ */
+ protected void tellAgain(final QName message) throws RemoteException{
+ final AbstractCoordParticipantProxy proxy =
+ this.getParticipantProxy();
+
+ if (State.MESSAGE_CANCEL.equals(message)){
+ proxy.cancelOperation(null);
+
+ }else if (State.MESSAGE_COMPENSATE.equals(message)){
+ proxy.compensateOperation(null);
+
+ }else if (State.MESSAGE_CLOSE.equals(message)){
+ proxy.closeOperation(null);
+
+ }else if (State.MESSAGE_EXITED.equals(message)){
+ proxy.exitedOperation(null);
+
+ }else if (State.MESSAGE_FAULTED.equals(message)){
+ proxy.faultedOperation(null);
+
+ }else if (State.MESSAGE_GETSTATUS.equals(message)){
+ proxy.getStatusOperation(null);
+
+ }else{
+ throw new IllegalArgumentException("Sorry, cannot tell a participant "+message);
+ }
+ }
+
+ /**
+ * Get the participant matchcode that was set for this participant.
+ * @return This participant's matchcode.
+ */
+ public String getMatchcode() {
+ return this.matchcode;
+ }
+
+ /**
+ * Return the result state of the participant, either
+ * Completing
+ * Canceling
+ * Exiting
+ * Faulting
+ * when ended;
+ *
+ * Completed, when completed;
+ *
+ * else Active .
+ * @return The state characterizing the participant's outcome best.
+ */
+ public QName getResultState() {
+ return this.currState.getResultState();
+ }
+}
Added: webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/AbstractCoordParticipantProxy.java
URL: http://svn.apache.org/viewvc/webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/AbstractCoordParticipantProxy.java?view=auto&rev=548471
==============================================================================
--- webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/AbstractCoordParticipantProxy.java (added)
+++ webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/AbstractCoordParticipantProxy.java Mon Jun 18 13:10:02 2007
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2007 The Apache Software Foundation.
+ *
+ * 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.
+ *
+ * @author Hannes Erven, Georg Hicker
+ */
+
+package org.apache.kandula.coordinator.ba.coordinator;
+
+/**
+ * This interface defines common methods all BusinessActivity participants share.
+ *
+ * In fact, as the BAwPC and BAwCC protocols only differ by one single state and one single message,
+ * this interface helps reduce duplicate code.
+ *
+ * @author Hannes Erven, Georg Hicker (C) 2006
+ *
+ */
+public interface AbstractCoordParticipantProxy {
+
+ /**
+ * Invoke the "close" operation on the participant.
+ * @param parameters Parameters.
+ * @throws java.rmi.RemoteException A fault from the participant.
+ */
+ public void closeOperation(org.apache.kandula.wsba.NotificationType parameters) throws java.rmi.RemoteException;
+
+ /**
+ * Invoke the "cancel" operation on the participant.
+ * @param parameters Parameters.
+ * @throws java.rmi.RemoteException A fault from the participant.
+ */
+ public void cancelOperation(org.apache.kandula.wsba.NotificationType parameters) throws java.rmi.RemoteException;
+
+ /**
+ * Invoke the "compensate" operation on the participant.
+ * @param parameters Parameters.
+ * @throws java.rmi.RemoteException A fault from the participant.
+ */
+ public void compensateOperation(org.apache.kandula.wsba.NotificationType parameters) throws java.rmi.RemoteException;
+
+ /**
+ * Invoke the "faulted" operation on the participant.
+ * @param parameters Parameters.
+ * @throws java.rmi.RemoteException A fault from the participant.
+ */
+ public void faultedOperation(org.apache.kandula.wsba.NotificationType parameters) throws java.rmi.RemoteException;
+
+ /**
+ * Invoke the "exited" operation on the participant.
+ * @param parameters Parameters.
+ * @throws java.rmi.RemoteException A fault from the participant.
+ */
+ public void exitedOperation(org.apache.kandula.wsba.NotificationType parameters) throws java.rmi.RemoteException;
+
+ /**
+ * Invoke the "getStatus" operation on the participant.
+ * @param parameters Parameters.
+ * @throws java.rmi.RemoteException A fault from the participant.
+ */
+ public void getStatusOperation(org.apache.kandula.wsba.NotificationType parameters) throws java.rmi.RemoteException ;
+
+ /**
+ * Invoke the "status" operation on the participant.
+ * @param parameters Parameters.
+ * @throws java.rmi.RemoteException A fault from the participant.
+ */
+ public void statusOperation(org.apache.kandula.wsba.StatusType parameters) throws java.rmi.RemoteException;
+}
Added: webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAAtomicOutcome.java
URL: http://svn.apache.org/viewvc/webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAAtomicOutcome.java?view=auto&rev=548471
==============================================================================
--- webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAAtomicOutcome.java (added)
+++ webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAAtomicOutcome.java Mon Jun 18 13:10:02 2007
@@ -0,0 +1,138 @@
+/*
+ * Copyright 2007 The Apache Software Foundation.
+ *
+ * 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.
+ *
+ * @author Hannes Erven, Georg Hicker
+ */
+
+package org.apache.kandula.coordinator.ba.coordinator;
+
+import javax.xml.namespace.QName;
+
+/**
+ * This class is a container for atomic business activity outcomes.
+ *
+ * After instantiating it, the result is undecided. At any given point,
+ * the BACoordinator may call either @see #decideToClose() or @see #decideToCancelOrCompensate() ,
+ * which sets the final outcome.
+ * After that, no more methods may be called.
+ *
+ * @author Hannes Erven, Georg Hicker (C) 2006
+ *
+ */
+public class BAAtomicOutcome {
+ /**
+ * The result QName for coordination contexts that are not yet decided.
+ */
+ public static final QName RESULT_UNDECIDED = new QName(BACoordinator.PROTOCOL_ID_INITIATOR, "AtomicOutcome_Undecided");
+
+ /**
+ * The result QName for coordination contexts that are decided to close.
+ */
+ public static final QName RESULT_CLOSE = new QName(BACoordinator.PROTOCOL_ID_INITIATOR, "AtomicOutcome_Close");
+
+ /**
+ * The result QName for coordination contexts that are decided to cancel or compensate.
+ */
+ public static final QName RESULT_COMPENSATE = new QName(BACoordinator.PROTOCOL_ID_INITIATOR, "AtomicOutcome_Compensate");
+
+
+ /**
+ * The private field where the result qname is stored.
+ */
+ private QName myOutcome = RESULT_UNDECIDED;
+
+ /**
+ * Set the final outcome to CLOSE.
+ * If isDecided() is already true, this method will throw an IllegalStateException.
+ *
+ */
+ public void decideToClose(){
+ synchronized(this){
+ if (isDecided()){
+ throw new IllegalStateException("Sorry, this outcome has already been decided: "+this.myOutcome);
+ }
+
+ this.myOutcome = RESULT_CLOSE;
+ }
+ }
+
+ /**
+ * Set the final outcome to CANCEL or COMPENSATE.
+ * If isDecided() is already true, this method will throw an IllegalStateException.
+ *
+ */
+ public void decideToCancelOrCompensate(){
+ synchronized(this){
+ if (isDecided()){
+ throw new IllegalStateException("Sorry, this outcome has already been decided: "+this.myOutcome);
+ }
+ this.myOutcome = RESULT_COMPENSATE;
+ }
+ }
+
+ /**
+ * Query if the outcome has alredy been decided.
+ * @return true, if the outcome has already been decided; false, if not.
+ *
+ */
+ public boolean isDecided(){
+ if (RESULT_UNDECIDED.equals( this.myOutcome )){
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Query if the outcome has alredy been decided to successfully close the transaction.
+ * @return true, if the outcome has already been decided to close; false, if not.
+ *
+ */
+ public boolean isDecidedToClose(){
+ return RESULT_CLOSE.equals( this.myOutcome );
+ }
+
+ /**
+ * Query if the outcome has alredy been decided to roll back (cancel or compensate) the transaction.
+ * @return true, if the outcome has already been decided to cancel or compensate; false, if not.
+ *
+ */
+ public boolean isDecidedToCancelOrCompensate(){
+ return RESULT_COMPENSATE.equals( this.myOutcome );
+ }
+
+ /**
+ * Query the outcome decision.
+ * @return null, if undecided; or one of @see #RESULT_CLOSE and @see #RESULT_COMPENSATE , if
+ * already decided.
+ *
+ */
+ public QName getOutcomeDecision(){
+ if (this.isDecided())
+ return this.myOutcome;
+
+ return null;
+ }
+
+ /**
+ * Query the current outcome.
+ * @return @see #RESULT_UNDECIDED if undecided, or one of @see #RESULT_CLOSE and @see #RESULT_COMPENSATE , if
+ * already decided.
+ *
+ */
+ public QName getOutcome(){
+ return this.myOutcome;
+ }
+}
Added: webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BACoordinator.java
URL: http://svn.apache.org/viewvc/webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BACoordinator.java?view=auto&rev=548471
==============================================================================
--- webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BACoordinator.java (added)
+++ webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BACoordinator.java Mon Jun 18 13:10:02 2007
@@ -0,0 +1,525 @@
+/*
+ * Copyright 2007 The Apache Software Foundation.
+ *
+ * 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.
+ *
+ * @author Hannes Erven, Georg Hicker
+ */
+
+package org.apache.kandula.coordinator.ba.coordinator;
+
+
+import java.rmi.RemoteException;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+
+import javax.xml.namespace.QName;
+import javax.xml.soap.Name;
+
+import org.apache.axis.AxisFault;
+import org.apache.axis.components.uuid.UUIDGen;
+import org.apache.axis.components.uuid.UUIDGenFactory;
+import org.apache.axis.message.addressing.EndpointReference;
+import org.apache.axis.types.URI;
+import org.apache.axis.types.URI.MalformedURIException;
+import org.apache.kandula.coordinator.CallbackRegistry;
+import org.apache.kandula.coordinator.CoordinationContext;
+import org.apache.kandula.coordinator.CoordinationService;
+import org.apache.kandula.coordinator.Coordinator;
+import org.apache.kandula.coordinator.CoordinatorImpl;
+import org.apache.kandula.coordinator.InvalidCoordinationProtocolException;
+import org.apache.kandula.coordinator.TimedOutException;
+import org.apache.kandula.coordinator.ba.ProtocolType;
+import org.apache.kandula.coordinator.ba.State;
+import org.apache.kandula.wsba.StateType;
+import org.apache.kandula.wsba.StatusType;
+import org.apache.kandula.wscoor.CreateCoordinationContextTypeCurrentContext;
+
+import org.apache.kandula.wsbai.BAParticipantReferenceType;
+import org.apache.kandula.wsbai.BAParticipantType;
+
+/**
+ * Base class for all WS-BusinessActivity coordinators.
+ *
+ * @author Hannes Erven, Georg Hicker (C) 2006
+ *
+ */
+public abstract class BACoordinator extends CoordinatorImpl {
+ /**
+ * The QName used to identify the BA with Coordinator Completion protocol.
+ * TODO WSBA Change this to the final initiator protocol identifier
+ */
+ public final static String PROTOCOL_ID_INITIATOR = "http://big.tuwien.ac.at/ws-ba--extensions/protocol/initiator";
+
+ /**
+ * The QName used to identify the Business Activity "Atomic" Outcome
+ */
+ public final static String COORDINATION_TYPE__ATOMIC = "http://schemas.xmlsoap.org/ws/2004/10/wsba/AtomicOutcome";
+
+ /**
+ * The QName used to identify the Business Activity "Mixed" Outcome
+ */
+ public final static String COORDINATION_TYPE__MIXED = "http://schemas.xmlsoap.org/ws/2004/10/wsba/MixedOutcome";
+
+ /**
+ * This QName is used to pass around the initiator's uuid.
+ */
+ public static final QName INITIATOR_REF = new QName(
+ "http://ws.apache.org/kandula", "InitiatorRef"
+ );
+
+ /**
+ * This QName identifies an error that is thrown when attempting to register
+ * a given matchcode twice in a context
+ */
+ public static final QName DUPLICATE_MATCHCODE_FAULT = new QName(
+ PROTOCOL_ID_INITIATOR, "duplicateMatchcodeFault"
+ );
+
+ /**
+ * Return a new AxisFault instance with its faultCode set to
+ * the @see #DUPLICATE_MATCHCODE_FAULT QName.
+ * @param matchcode The matchcode that was requested twice.
+ * @return AxisFault
+ */
+ public AxisFault DUPLICATE_MATCHCODE_SOAP_FAULT(final String matchcode){
+ return new AxisFault(
+ DUPLICATE_MATCHCODE_FAULT,
+ "Attempted to register a matchcode that was already in use: "+matchcode,
+ "", null
+ );
+ }
+
+ /*
+ * = = = = = = = = = = = = = = =
+ */
+
+ /**
+ * This field stores the chosen outcome Type (mixed/atomic).
+ */
+ private final String outcomeType ;
+
+ /**
+ * The participants map contains all registered participants, accessible by
+ * their Participant UUID.
+ * Access to this map should be synchronized for any write access and for methods
+ * that use iterators or enumerations derived from the map. The map is expected
+ * to only extend, it never loses entries.
+ */
+ private final Map participants = new HashMap();
+
+ /**
+ * This map contains a matchcode --> participant association. matchcodes
+ * are inserted with a null value as soon as the initiator requests
+ * a registration service endpoint for a matchcode.
+ * Synchronize access to this map!!
+ */
+ private final Map participantMatchcodes = new HashMap();
+
+ /**
+ * A reference to the initiator, if they already registered.
+ */
+ private InitiatorProxy initiator = null;
+
+ /**
+ * The default constructor. Use this to create a new Business Activity Coordinator.
+ * If superContext is given, this coordinator will register itself as a CoordinatorCompletion
+ * participant in the supercontext and will provide the initiator with all messages and state
+ * changes related to the supercontext. See the WSBAI specification for more detail.
+ *
+ * @param pOutcomeType The outcome type for this coordination context.
+ * @param superContext The super context, if this is a subcontext
+ * @throws MalformedURIException Exception if the OutcomeType could not be parsed
+ * @throws InvalidOutcomeAssertion Exception if the OutcomeType could be parsed, but not accepted
+ */
+ protected BACoordinator(
+ final String pOutcomeType,
+ final CreateCoordinationContextTypeCurrentContext superContext
+ )
+ throws MalformedURIException, InvalidOutcomeAssertion
+ {
+ super(pOutcomeType);
+
+ if (superContext != null){
+ // Check the super context
+ if (false
+ || COORDINATION_TYPE__ATOMIC.equals( superContext.getCoordinationType().toString() )
+ || COORDINATION_TYPE__MIXED.equals( superContext.getCoordinationType().toString() )
+ ){
+ // Super's coordination type is OK
+ }else{
+ throw new IllegalArgumentException("The Kandula Business Activity coordination service currently can only create subordinate coordination contexts to a WS-BA parent context.");
+ }
+
+ // TODO HE set super context and act appropriately...
+
+
+ } // end supercontext checks
+
+ if (COORDINATION_TYPE__ATOMIC.equals(pOutcomeType)){
+ this.outcomeType = pOutcomeType;
+ }else if (COORDINATION_TYPE__MIXED.equals(pOutcomeType)){
+ this.outcomeType = pOutcomeType;
+ }else {
+ throw new InvalidOutcomeAssertion();
+ }
+ }
+
+
+ /**
+ * Check if a particular match code has already been asked for.
+ * @param matchcode The match code to check.
+ * @return true, if the match code is available; false, if not.
+ */
+ protected boolean isMatchCodeAvailable(final String matchcode){
+ return (! this.participantMatchcodes.containsKey(matchcode));
+ }
+
+ /**
+ * Activate a particular matchcode. A matchcode is used by the initiator to identify
+ * the transaction's participants.
+ * By default, we only allow registrations for protocols that include a valid matchcode
+ * that is activated, but not yet taken.
+ * This method returns an registrationService endpoint that is already tagged with
+ * the requested matchcode, if it was available.
+ * If the requested matchcode has already been taken, an invalidargumentexception is thrown.
+ *
+ * @param matchcode The match code to register and activate
+ * @return Endpoint to this context's registration service, tagged with the match code.
+ * @throws AxisFault A ready-made fault, if the match code is already reserved or taken.
+ */
+ public CoordinationContext registerMatchcode(final String matchcode) throws AxisFault{
+ synchronized (this.participantMatchcodes) {
+ if (matchcode == null || matchcode.length()==0 )
+ throw new IllegalArgumentException("The matchcode must not be null or emtpy!");
+
+ if (! this.isMatchCodeAvailable(matchcode)){
+ throw DUPLICATE_MATCHCODE_SOAP_FAULT(matchcode);
+ }
+
+ this.participantMatchcodes.put(matchcode, null);
+
+ return this.getCoordinationContext(matchcode);
+ } // end synchronized participantMatchcodes
+ }
+ /**
+ * Register a participant for one of the BAwCC or BAwPC protocols and
+ * return the protocol service's endpoint reference.
+ *
+ * @param protocol The requested protocol.
+ * @param participantEndpoint The participant's endpoint.
+ * @param matchcode The match code the participant asked for.
+ * @return The endpoint reference of the coordinator's protocol service, tagged with the
+ * participant and transaction identifiers.
+ *
+ * @throws InvalidCoordinationProtocolException
+ */
+ public EndpointReference register(
+ final String protocol,
+ final EndpointReference participantEndpoint,
+ final String matchcode
+ )
+ throws InvalidCoordinationProtocolException {
+
+ // Check, whether a "valid" callback was supplied
+ if (participantEndpoint == null)
+ throw new IllegalArgumentException("Register: Participant Endpoint must not be null");
+
+
+ // Calculate the new participant's GUID
+ // The kandula coordination service
+ final CoordinationService cs = CoordinationService.getInstance();
+
+ final UUIDGen gen = UUIDGenFactory.getUUIDGen();
+ final String newRef = "uuid:" + gen.nextUUID();
+
+ final EndpointReference epr;
+
+ try{
+ // Check whether a valid protocol was supplied and register
+ if (protocol.equals(PROTOCOL_ID_INITIATOR)){
+ // OK, register as initiator; synchronize and set the initiator fields
+
+ synchronized(this){
+ if (this.initiator != null)
+ throw new IllegalStateException("Sorry, there already is an initiator registered!");
+
+ this.initiator = new InitiatorProxy(newRef, participantEndpoint);
+ epr = cs.getInitiatorCoordinatorService(this, newRef);
+ } // end synchronized this
+ }else{
+ // Other protocols
+ final AbstractCoordParticipant newParticipant;
+
+ /*
+ * While registration is in progress, lock the match code table
+ *
+ */
+ synchronized(this.participantMatchcodes){
+ if (! this.participantMatchcodes.containsKey(matchcode)){
+ throw new IllegalArgumentException("Sorry, the matchcode "+matchcode+" has not been activated.");
+ }
+ if (this.participantMatchcodes.get(matchcode) != null){
+ final IllegalArgumentException x = new IllegalArgumentException("Sorry, the matchcode "+matchcode+" has already been taken.");
+ throw x;
+ }
+
+ if (! this.isRegistrationPossible() ){
+ final AxisFault af = CONTEXT_REFUSED_SOAP_FAULT();
+ af.addFaultDetailString("The context exists, but work has progressed so far that no more registrations are accepted.");
+ throw af;
+ }
+
+ if (protocol.equals(ProtocolType.PROTOCOL_ID_CC.getNamespaceURI()+ProtocolType.PROTOCOL_ID_CC.getLocalPart())){
+ // OK, register for Coordinator Completion
+
+ newParticipant = new BAwCCCoordParticipant(newRef, participantEndpoint, this, matchcode);
+ }else if (protocol.equals(ProtocolType.PROTOCOL_ID_PC.getNamespaceURI()+ProtocolType.PROTOCOL_ID_PC.getLocalPart())){
+
+ // OK, register for Participant Completion
+
+ newParticipant = new BAwPCCoordParticipant(newRef, participantEndpoint, this, matchcode);
+ }else{
+ throw new InvalidCoordinationProtocolException();
+ }
+
+ // Register participant object
+ this.participantMatchcodes.put(matchcode, newParticipant);
+ } // End synchronized (this.participantMatchcode)
+
+ /*
+ * Synchronize on both this (used by buildParticipantList) and this.participants
+ * (used by registration) to lock participant lists before adding
+ */
+ synchronized(this){
+ synchronized (this.participants) {
+ this.participants.put(newRef, newParticipant);
+ }
+ }
+ epr = cs.getCoordinatorService(this, newRef, protocol);
+ CallbackRegistry.getInstance().registerCallback(newParticipant);
+ } // End protocol switch
+ }
+ catch(AxisFault f){
+ throw new IllegalArgumentException("Sorry, could not instantiate a participant: "+f);
+ }
+ return epr;
+ }
+
+ /**
+ * Check if enrolling a new participant is allowed in the current state
+ * of the transaction.
+ * @return false, if registration requests shall be rejected.
+ */
+ abstract boolean isRegistrationPossible();
+
+
+ /**
+ * Registers an incoming fault.
+ * @param code The fault code.
+ */
+ public void onFault(Name code) {
+ // TODO WSBA Handle faults
+
+ System.out.println("[BACoordinator] onFault: " + code);
+ }
+
+ /**
+ * The transaction context timed out. Notify all participants
+ * and get outta here!
+ * @throws TimedOutException ???
+ */
+ public void timeout() throws TimedOutException {
+ // TODO WSBA Handle timeouts
+
+ if (false)
+ throw new TimedOutException();
+ }
+
+ /**
+ * This coordinator's endpoint reference.
+ * (Seems to be an unused method, since there is always an UnsupportedOperationException thrown)
+ * @return ERROR !
+ */
+ public EndpointReference getEndpointReference() {
+ throw new UnsupportedOperationException();
+ }
+
+ /**
+ * Returns this Coordinator's coordination type.
+ *
+ * @return One of COORDINATION_TYPE__ATOMIC and COORDINATION_TYPE__MIXED
+ * @see #COORDINATION_TYPE__ATOMIC
+ * @see #COORDINATION_TYPE__MIXED
+ */
+ public String getOutcomeType() {
+ return this.outcomeType;
+ }
+
+ /**
+ * Check, if the given participant is a registered participant in this context.
+ * @param participant The participant.
+ * @return true, if the participant is registered in the current transaction; false, if not.
+ */
+ public boolean containsParticipant(final AbstractCoordParticipant participant){
+
+ // Doesn't need synchronization since de-registration is not possible
+
+ return this.participants.containsValue(participant);
+ }
+
+ /**
+ * This method is used by participant objects to signal state changes to the coordination context.
+ * It is synchronized to avoid any problems that may arise when multiple participants change
+ * states at the same time.
+ *
+ * This method contains any process logic that does not need business logic and hence may be
+ * implemented in the coordinator, e.g. automatically
+ * acknowledging state changes as ACTIVE->EXIT->EXITING->EXITED->ENDED .
+ *
+ * Any state change will also be automatically be forwarded to the initiator. For those state
+ * changes where the coordinator does not have sufficient knowledge of the initiator's goals to
+ * direct the participant to the next state, it will wait for the initiator to issue new commands.
+ *
+ * @param participant The participant that changed states
+ * @param newState The state after the transition (= current state of the participant)
+ * @throws RemoteException Exception while handling the transition.
+ */
+ public void handleStateTransition(
+ final AbstractCoordParticipant participant,
+ final QName newState
+ ) throws RemoteException {
+ // TODO WSBA Forward any state change to the initiator
+
+ // Ensure we may change participant states
+ // (this should be the case anyways)
+ synchronized(this){
+ if (State.STATE_EXITING.equals(newState)){
+ // Participant is in state EXITING, send EXITED and set state to ENDED.
+ participant.tellExited();
+ }else if (false
+ || State.STATE_FAULTING.equals(newState)
+ || State.STATE_FAULTING_ACTIVE.equals(newState)
+ || State.STATE_FAULTING_COMPENSATING.equals(newState)
+ ){
+ participant.tellFaulted();
+ }else{
+ System.out.println("State transition to "+newState+" must be handled by initiator!");
+ }
+
+ /*
+ * As soon as the ENDED state is reached, we no longer accept
+ * messages from the client and hence remove them from the
+ * callback registry. (This also aborts the timeout timertask.)
+ * We dont remove them from the participants map, so the initiator
+ * can still see the participant and their state.
+ */
+ if (State.STATE_ENDED.equals(newState)){
+ CallbackRegistry.getInstance().remove(participant);
+ }
+ }
+ }
+
+
+ /**
+ * Return a participant list. This method is synchronized on "this"
+ * and "this.participants" to ensure maximum consistency.
+ *
+ * @return An array of BAParticipantType objects.
+ */
+ public BAParticipantType[] buildParticipantList() {
+ final BAParticipantType[] result ;
+
+ synchronized (this){
+ synchronized (this.participants) {
+ result = new BAParticipantType[this.participants.size()];
+
+ final Iterator it = this.participants.values().iterator();
+ int count = 0;
+
+ // circle through the participants...
+ while(it.hasNext()){
+ final AbstractCoordParticipant participant = (AbstractCoordParticipant) it.next();
+
+ final URI proto;
+ {
+ URI tmpProto = null;
+ try{
+ tmpProto = new org.apache.axis.types.URI(
+ participant.getProtocolIdentifier().getNamespaceURI()+
+ participant.getProtocolIdentifier().getLocalPart()
+ );
+ }
+ catch(MalformedURIException x){
+ // forget it
+ }
+ proto = tmpProto;
+ }
+
+ final StateType resultState = StateType.fromValue(participant.getResultState());
+
+ // Fill all fields...
+ result[count] = new BAParticipantType(
+ new BAParticipantReferenceType(participant.getMatchcode()),
+ new StatusType(StateType.fromValue(participant.getCurrentState()), null),
+ new StatusType(resultState, null),
+ proto
+ );
+
+ count++;
+ }
+ } // end synchronized this.participants
+ } // end synchronized this
+ return result;
+ }
+
+ /**
+ * Fetches the participant associated to the given matchcode in the current context.
+ * Returns null if either the matchcode was not registered in the context, or
+ * the matchcode is valid but no participant has yet registered for it.
+ * @param matchCode
+ * @return The participant that registered for the requested matchcode, or null
+ * if the matchcode is either unused or no participant registered for it.
+ */
+ public AbstractCoordParticipant getParticipantByMatchcode(final String matchCode){
+ return (AbstractCoordParticipant) this.participantMatchcodes.get(matchCode);
+ }
+
+ /**
+ * Returns the collection of participants who are registered in the transaction.
+ * @return The participant collection.
+ */
+ protected final Collection getParticipants(){
+ return this.participants.values();
+ }
+
+ /**
+ * Checks if the current request has all properties a request from the genuine
+ * initiator must have. At this time, we check that the @see
+ * @throws RemoteException
+ */
+ public void ensureRequestOriginatesFromInitiatorOrThrowFault() throws RemoteException{
+ final String initiatorRef = CallbackRegistry.getRef(BACoordinator.INITIATOR_REF);
+
+ if (initiatorRef != null
+ && initiatorRef.equals(this.initiator.myID)
+ ){
+ // OK
+ }else{
+ throw Coordinator.CONTEXT_REFUSED_SOAP_FAULT();
+ }
+ }
+
+}
Added: webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BACoordinatorService.java
URL: http://svn.apache.org/viewvc/webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BACoordinatorService.java?view=auto&rev=548471
==============================================================================
--- webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BACoordinatorService.java (added)
+++ webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BACoordinatorService.java Mon Jun 18 13:10:02 2007
@@ -0,0 +1,245 @@
+/*
+ * Copyright 2007 The Apache Software Foundation.
+ *
+ * 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.
+ *
+ * @author Hannes Erven, Georg Hicker
+ */
+
+package org.apache.kandula.coordinator.ba.coordinator;
+
+import java.rmi.RemoteException;
+
+import javax.xml.namespace.QName;
+
+import org.apache.kandula.coordinator.Callback;
+import org.apache.kandula.coordinator.CallbackRegistry;
+import org.apache.kandula.coordinator.Coordinator;
+import org.apache.kandula.coordinator.ba.State;
+import org.apache.kandula.wsba.BusinessAgreementWithCoordinatorCompletionCoordinatorPortType;
+import org.apache.kandula.wsba.BusinessAgreementWithParticipantCompletionCoordinatorPortType;
+import org.apache.kandula.wsba.ExceptionType;
+import org.apache.kandula.wsba.NotificationType;
+import org.apache.kandula.wsba.StatusType;
+
+/**
+ * This is the class that represents the Business Activity protocol web service
+ * to the client.
+ * Internally, on an incoming message, it checks whether that message can be correlated
+ * to an existing business activity, and forwards it to the BACoordinator object
+ * managing that activity.
+ *
+ *
+ * @author Hannes Erven, Georg Hicker (C) 2006
+ *
+ *
+ */
+public class BACoordinatorService implements
+ BusinessAgreementWithCoordinatorCompletionCoordinatorPortType,
+ BusinessAgreementWithParticipantCompletionCoordinatorPortType {
+
+ /**
+ * Retrieves the BACoordinator associated with the coordinator context attached to
+ * the current message.
+ * If no context could be associated, an exception is thrown. This method never returns null.
+ * @return The BACoordinator.
+ * @throws RemoteException
+ */
+ public static BACoordinator getBACoordinatorOrThrowFault() throws RemoteException{
+ final Callback c = CallbackRegistry.getInstance().correlateMessage(
+ CallbackRegistry.CALLBACK_REF, false
+ );
+
+ if (c == null)
+ throw Coordinator.CONTEXT_REFUSED_SOAP_FAULT();
+
+ if (! (c instanceof BACoordinator) || c == null)
+ throw Coordinator.CONTEXT_REFUSED_SOAP_FAULT();
+
+ return (BACoordinator) c;
+ }
+
+ /**
+ * Retrieves the Participant who sent the current message.
+ * @param context The current transaction's context.
+ * @return The participant, if found
+ * @throws RemoteException if no participant could be found
+ */
+ protected static AbstractCoordParticipant getBAParticipantOrThrowFault(final BACoordinator context) throws RemoteException {
+ final AbstractCoordParticipant p = (AbstractCoordParticipant) CallbackRegistry.getInstance().correlateMessage(
+ Coordinator.PARTICIPANT_REF, false
+ );
+
+ // The message could not be correlated to a registered participant
+ if (p == null){
+ throw Coordinator.CONTEXT_REFUSED_SOAP_FAULT() ;
+ }
+
+ // The message contained a reference to a participant and a context,
+ // but the participant is not registered in the context
+ if (! context.containsParticipant(p)){
+ throw Coordinator.CONTEXT_REFUSED_SOAP_FAULT();
+ }
+
+ return p;
+ }
+
+ /*
+ * Below are the web service's methods
+ */
+
+ /**
+ * Completed.
+ * @param parameters Any parameters.
+ * @throws RemoteException Any fault thrown while processing the incoming message.
+ */
+ public void completedOperation(final NotificationType parameters)
+ throws RemoteException {
+ handleIncomingMessage(State.MESSAGE_COMPLETED, parameters);
+ }
+
+ /**
+ * Fault.
+ * @param parameters Any parameters.
+ * @throws RemoteException Any fault thrown while processing the incoming message.
+ */
+ public void faultOperation(final ExceptionType parameters) throws RemoteException {
+ handleIncomingMessage(State.MESSAGE_FAULT, parameters);
+ }
+
+ /**
+ * Compensated.
+ * @param parameters Any parameters.
+ * @throws RemoteException Any fault thrown while processing the incoming message.
+ */
+ public void compensatedOperation(final NotificationType parameters)
+ throws RemoteException {
+ handleIncomingMessage(State.MESSAGE_COMPENSATED, parameters);
+ }
+
+ /**
+ * Closed
+ * @param parameters Any parameters.
+ * @throws RemoteException Any fault thrown while processing the incoming message.
+ */
+ public void closedOperation(final NotificationType parameters)
+ throws RemoteException {
+ handleIncomingMessage(State.MESSAGE_CLOSED, parameters);
+ }
+
+ /**
+ * Canceled
+ * @param parameters Any parameters.
+ * @throws RemoteException Any fault thrown while processing the incoming message.
+ */
+ public void canceledOperation(final NotificationType parameters)
+ throws RemoteException {
+ handleIncomingMessage(State.MESSAGE_CANCELED, parameters);
+ }
+
+ /**
+ * Exit
+ * @param parameters Any parameters.
+ * @throws RemoteException Any fault thrown while processing the incoming message.
+ */
+ public void exitOperation(final NotificationType parameters)
+ throws RemoteException {
+ handleIncomingMessage(State.MESSAGE_EXIT, parameters);
+ }
+
+ /**
+ * GetStatus
+ * @param parameters Any parameters.
+ * @throws RemoteException Any fault thrown while processing the incoming message.
+ */
+ public void getStatusOperation(final NotificationType parameters)
+ throws RemoteException {
+ handleIncomingMessage(State.MESSAGE_GETSTATUS, parameters);
+ }
+
+ /**
+ * Status
+ * @param parameters Any parameters.
+ * @throws RemoteException Any fault thrown while processing the incoming message.
+ */
+ public void statusOperation(final StatusType parameters) throws RemoteException {
+ handleIncomingMessage(State.MESSAGE_STATUS, parameters);
+ }
+
+ /*
+ * End Web Service Methods
+ */
+
+
+ /**
+ * Handle an incoming messages. That is, fetch the coordination context associated
+ * with the given coordination context references; fetch the participant associated
+ * with the given participant references;
+ * and pass further message processing to the coordinator-side participant object.
+ * @param messageType The message's type. @see CoordinationStates
+ * @param params The message's parameters.
+ * @throws RemoteException If context or participant could not be created, or message processing
+ * by the participant was not successfull, we throw an error back to the calling party.
+ */
+ protected void handleIncomingMessage(final QName messageType, final NotificationType params) throws RemoteException{
+
+ final BACoordinator coord = getBACoordinatorOrThrowFault();
+ final AbstractCoordParticipant part = getBAParticipantOrThrowFault(coord);
+
+ System.out.println("+++ CoordIncoming: "+messageType+" ("+params+"+ in TX "+coord+" from participant "+part);
+
+ if (messageType.equals(State.MESSAGE_GETSTATUS)){
+ // Reply with the status
+
+ part.tellStatus();
+ }else{
+ part.handleIncomingMessage(messageType, params);
+ }
+ }
+ /**
+ * Handle an incoming messages. That is, fetch the coordination context associated
+ * with the given coordination context references; fetch the participant associated
+ * with the given participant references;
+ * and pass further message processing to the coordinator-side participant object.
+ * @param messageType The message's type. @see CoordinationStates
+ * @param params The message's parameters.
+ * @throws RemoteException If context or participant could not be created, or message processing
+ * by the participant was not successfull, we throw an error back to the calling party.
+ */
+ protected void handleIncomingMessage(final QName messageType, final ExceptionType params) throws RemoteException{
+
+ final BACoordinator coord = getBACoordinatorOrThrowFault();
+ final AbstractCoordParticipant part = getBAParticipantOrThrowFault(coord);
+
+ System.out.println("+++ CoordIncoming: "+messageType+" ("+params+"+ in TX "+coord+" from participant "+part);
+ part.handleIncomingMessage(messageType, params);
+ }
+ /**
+ * Handle an incoming messages. That is, fetch the coordination context associated
+ * with the given coordination context references; fetch the participant associated
+ * with the given participant references;
+ * and pass further message processing to the coordinator-side participant object.
+ * @param messageType The message's type. @see CoordinationStates
+ * @param params The message's parameters.
+ * @throws RemoteException If context or participant could not be created, or message processing
+ * by the participant was not successfull, we throw an error back to the calling party.
+ */
+ protected void handleIncomingMessage(final QName messageType, final StatusType params) throws RemoteException{
+
+ final BACoordinator coord = getBACoordinatorOrThrowFault();
+ final AbstractCoordParticipant part = getBAParticipantOrThrowFault(coord);
+
+ System.out.println("+++ CoordIncoming: "+messageType+" ("+params+"+ in TX "+coord+" from participant "+part);
+ part.handleIncomingMessage(messageType, params);
+ }
+}
Added: webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwCCCoordParticipant.java
URL: http://svn.apache.org/viewvc/webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwCCCoordParticipant.java?view=auto&rev=548471
==============================================================================
--- webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwCCCoordParticipant.java (added)
+++ webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwCCCoordParticipant.java Mon Jun 18 13:10:02 2007
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2007 The Apache Software Foundation.
+ *
+ * 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.
+ *
+ * @author Hannes Erven, Georg Hicker
+ */
+
+package org.apache.kandula.coordinator.ba.coordinator;
+
+import java.net.MalformedURLException;
+import java.rmi.RemoteException;
+
+import javax.xml.namespace.QName;
+
+import org.apache.axis.AxisFault;
+import org.apache.axis.message.addressing.EndpointReference;
+import org.apache.kandula.coordinator.ba.ProtocolType;
+import org.apache.kandula.coordinator.ba.State;
+
+
+/**
+ * A server-side WS-BA transaction particpant, registered for the
+ * CoordinatorCompletion Protocol.
+ *
+ * @author Hannes Erven, Georg Hicker (C) 2006
+ *
+ */
+public class BAwCCCoordParticipant extends AbstractCoordParticipant {
+
+ private final BAwCCParticipantProxy myPCProxy;
+
+ /**
+ * The default constructor for the new participant.
+ *
+ * @param participantID The participant's ID.
+ * @param participantEPR The participant's protocol service endpoint reference.
+ * @param coordinationContext The coordination context the participant is registered in.
+ * @param matchcode The matchcode the participant was given by the initiator.
+ * @throws AxisFault Any fault while initializing the participant object.
+ */
+ public BAwCCCoordParticipant(
+ final String participantID,
+ final EndpointReference participantEPR,
+ final BACoordinator coordinationContext,
+ final String matchcode
+
+ ) throws AxisFault {
+ super(participantID, participantEPR, coordinationContext, matchcode);
+
+ try {
+ this.myPCProxy = new BAwCCParticipantProxy(participantID, participantEPR);
+ } catch (MalformedURLException e) {
+ throw new AxisFault("ERROR!!! "+e);
+ }
+ }
+
+ /**
+ * As this is a CC participant, always returns CC.
+ * @return This particpant's protocol identifier.
+ * @see ProtocolType#PROTOCOL_ID_CC
+ */
+ public QName getProtocolIdentifier() {
+ return ProtocolType.PROTOCOL_ID_CC;
+ }
+
+ /*
+ * Methods for the PC participant
+ */
+
+ /**
+ * Tell the participant to complete
+ * @throws java.rmi.RemoteException A fault from the participant.
+ */
+ public void tellComplete() throws RemoteException {
+ this.tell(State.MESSAGE_COMPLETE);
+ }
+
+ /**
+ * Return the participant proxy
+ * @return The participant proxy.
+ */
+ public AbstractCoordParticipantProxy getParticipantProxy() {
+ return this.myPCProxy;
+ }
+
+ /**
+ * Overrides @see AbstractCoordParticipant#tellAgain(QName) , as the BAwCC participant
+ * needs an additional message: @see State#MESSAGE_COMPLETED
+ * @param message The message type to send.
+ * @throws java.rmi.RemoteException A fault from the participant.
+ */
+ protected void tellAgain(final QName message) throws RemoteException {
+ if (State.MESSAGE_COMPLETE.equals(message)){
+ this.myPCProxy.completeOperation(null);
+ }else{
+ super.tellAgain(message);
+ }
+ }
+
+}
Added: webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwCCParticipantProxy.java
URL: http://svn.apache.org/viewvc/webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwCCParticipantProxy.java?view=auto&rev=548471
==============================================================================
--- webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwCCParticipantProxy.java (added)
+++ webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwCCParticipantProxy.java Mon Jun 18 13:10:02 2007
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2007 The Apache Software Foundation.
+ *
+ * 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.
+ *
+ * @author Hannes Erven, Georg Hicker
+ */
+
+package org.apache.kandula.coordinator.ba.coordinator;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.axis.AxisFault;
+import org.apache.axis.message.addressing.EndpointReference;
+import org.apache.kandula.utils.AddressingHeaders;
+import org.apache.kandula.utils.Service;
+import org.apache.kandula.utils.TCPSnifferHelper;
+import org.apache.kandula.wsba.BusinessAgreementWithCoordinatorCompletionParticipantPortTypeBindingStub;
+
+/**
+ * This class is a wrapper around the autogenerated axis web service stubs.
+ *
+ * @author Hannes Erven, Georg Hicker (C) 2006
+ *
+ */
+public class BAwCCParticipantProxy
+ extends BusinessAgreementWithCoordinatorCompletionParticipantPortTypeBindingStub
+ implements AbstractCoordParticipantProxy
+{
+
+ /**
+ * The participant ID.
+ */
+ protected final String myID;
+
+ /**
+ * The endpoint where the participant can be reached.
+ */
+ protected final EndpointReference myEndpoint;
+
+
+ /**
+ * Current Addressing Headers
+ */
+ final AddressingHeaders headers;
+
+ /**
+ * Constructor for a new participant.
+ * @param id The participant ID
+ * @param epr The EPR the participant can be reached at.
+ * @throws AxisFault ???
+ * @throws MalformedURLException ???
+ */
+ public BAwCCParticipantProxy(final String id, final EndpointReference epr)
+ throws AxisFault, MalformedURLException{
+ super(new URL(TCPSnifferHelper.redirect(epr.getAddress().toString())),
+ new Service());
+ this.headers = new AddressingHeaders(epr, null);
+ ((Service) this.service).setAddressingHeaders(this.headers);
+
+
+ if (id == null || id.length()==0)
+ throw new IllegalArgumentException("Sorry, participant ID must not be null or empty");
+
+ if (epr == null)
+ throw new IllegalArgumentException("Sorry, participant EPR must not be null");
+
+ this.myID = id;
+ this.myEndpoint = epr;
+ }
+
+ /**
+ * The addressing headers this proxy is using.
+ * @return The addressing headers.
+ */
+ public AddressingHeaders getAddressingHeaders(){
+ return this.headers;
+ }
+
+}
Added: webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwPCCoordParticipant.java
URL: http://svn.apache.org/viewvc/webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwPCCoordParticipant.java?view=auto&rev=548471
==============================================================================
--- webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwPCCoordParticipant.java (added)
+++ webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwPCCoordParticipant.java Mon Jun 18 13:10:02 2007
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2007 The Apache Software Foundation.
+ *
+ * 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.
+ *
+ * @author Hannes Erven, Georg Hicker
+ */
+
+package org.apache.kandula.coordinator.ba.coordinator;
+
+import java.net.MalformedURLException;
+
+import javax.xml.namespace.QName;
+
+import org.apache.axis.AxisFault;
+import org.apache.axis.message.addressing.EndpointReference;
+import org.apache.kandula.coordinator.ba.ProtocolType;
+
+
+/**
+ * A server-side WS-BA transaction particpant, registered for the
+ * ParticipantCompletion Protocol.
+ *
+ * @author Hannes Erven, Georg Hicker (C) 2006
+ *
+ */
+public class BAwPCCoordParticipant extends AbstractCoordParticipant {
+
+ private final BAwPCParticipantProxy myPCProxy;
+
+ /**
+ * Build a coordinator side PC participant object and proxy.
+ *
+ * @param participantID The participant's ID.
+ * @param participantEPR The participant's EPR.
+ * @param coordinationContext The coordination context the participant is enrolled in.
+ * @param matchcode The participant's matchcode in the context.
+ * @throws AxisFault Any fault from within.
+ */
+ public BAwPCCoordParticipant(
+ final String participantID,
+ final EndpointReference participantEPR,
+ final BACoordinator coordinationContext,
+ final String matchcode
+ ) throws AxisFault {
+ super(participantID, participantEPR, coordinationContext, matchcode);
+
+ try{
+ this.myPCProxy = new BAwPCParticipantProxy(participantID, participantEPR);
+ }catch(MalformedURLException x){
+ throw new AxisFault("ERROR: "+x);
+ }
+ }
+
+ /**
+ * As this is a PC participant, always returns PC.
+ * @see ProtocolType#PROTOCOL_ID_PC
+ * @return The PC protocol's QName
+ */
+ public QName getProtocolIdentifier() {
+ return ProtocolType.PROTOCOL_ID_PC;
+ }
+
+ /**
+ * Return the participant proxy
+ * @return The participant proxy.
+ */
+ public AbstractCoordParticipantProxy getParticipantProxy() {
+ return this.myPCProxy;
+ }
+
+ /**
+ * Methods for the PC participant - already implemented in @see org.apache.kandula.coordinator.ba.coordinator.AbstractCoordParticipant
+ */
+
+
+}
Added: webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwPCParticipantProxy.java
URL: http://svn.apache.org/viewvc/webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwPCParticipantProxy.java?view=auto&rev=548471
==============================================================================
--- webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwPCParticipantProxy.java (added)
+++ webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwPCParticipantProxy.java Mon Jun 18 13:10:02 2007
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2007 The Apache Software Foundation.
+ *
+ * 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.
+ *
+ * @author Hannes Erven, Georg Hicker
+ */
+
+package org.apache.kandula.coordinator.ba.coordinator;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import org.apache.axis.AxisFault;
+import org.apache.axis.message.addressing.EndpointReference;
+import org.apache.kandula.utils.AddressingHeaders;
+import org.apache.kandula.utils.Service;
+import org.apache.kandula.utils.TCPSnifferHelper;
+import org.apache.kandula.wsba.BusinessAgreementWithParticipantCompletionParticipantPortTypeBindingStub;
+
+/**
+ * This class is a wrapper around the autogenerated axis web service stubs.
+ *
+ * @author Hannes Erven, Georg Hicker (C) 2006
+ *
+ */
+public class BAwPCParticipantProxy
+ extends BusinessAgreementWithParticipantCompletionParticipantPortTypeBindingStub
+ implements AbstractCoordParticipantProxy
+{
+
+ /**
+ * The participant ID.
+ */
+ protected final String myID;
+
+ /**
+ * The endpoint where the participant can be reached.
+ */
+ protected final EndpointReference myEndpoint;
+
+ /**
+ * Current addressing headers.
+ */
+ final AddressingHeaders headers;
+
+ /**
+ * Constructor for a new participant.
+ * @param id The participant ID
+ * @param epr The EPR the participant can be reached at.
+ * @throws AxisFault ???
+ * @throws MalformedURLException ???
+ */
+ public BAwPCParticipantProxy(final String id, final EndpointReference epr)
+ throws AxisFault, MalformedURLException {
+ super(new URL(TCPSnifferHelper.redirect(epr.getAddress().toString())),
+ new Service());
+ this.headers = new AddressingHeaders(epr, null);
+ ((Service) this.service).setAddressingHeaders(this.headers);
+
+
+ if (id == null || id.length()==0)
+ throw new IllegalArgumentException("Sorry, participant ID must not be null or empty");
+
+ if (epr == null)
+ throw new IllegalArgumentException("Sorry, participant EPR must not be null");
+
+ this.myID = id;
+ this.myEndpoint = epr;
+ }
+
+
+ /**
+ * Current addressing headers.
+ * @return Addressing headers.
+ */
+ public AddressingHeaders getAddressingHeaders(){
+ return this.headers;
+ }
+
+}
Added: webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwithAtomicOutcomeCoordinator.java
URL: http://svn.apache.org/viewvc/webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwithAtomicOutcomeCoordinator.java?view=auto&rev=548471
==============================================================================
--- webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwithAtomicOutcomeCoordinator.java (added)
+++ webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwithAtomicOutcomeCoordinator.java Mon Jun 18 13:10:02 2007
@@ -0,0 +1,221 @@
+/*
+ * Copyright 2007 The Apache Software Foundation.
+ *
+ * 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.
+ *
+ * @author Hannes Erven, Georg Hicker
+ */
+
+package org.apache.kandula.coordinator.ba.coordinator;
+
+
+import java.rmi.RemoteException;
+import java.util.Collection;
+import java.util.Iterator;
+
+import javax.xml.namespace.QName;
+
+import org.apache.axis.types.URI.MalformedURIException;
+import org.apache.kandula.coordinator.ba.State;
+import org.apache.kandula.wscoor.CreateCoordinationContextTypeCurrentContext;
+
+
+/**
+ * This class represents an Business Activity coordinator for a context
+ * with Atomic Outcome assertion.
+ *
+ * Atomic outcome means that all participants will be directed to either
+ * - close, or
+ * - cancel/compensate
+ *
+ * depending on the progress the participants made. If the transaction's state
+ * does not require the coordinator to automatically choose one of these
+ * options, the initiator must decide which outcome they desire.
+ *
+ * The following rules apply to business activities with atomic outcome:
+ * <ul>
+ * <li>participants who 'exit' do not affect the progress of other participants and are discarded.
+ * <li>participants who 'fault' require all other participants to cancel or compensate, depending
+ * on their progress.
+ * <li>participants who 'cancel' while active or completing also require all other participants
+ * to cancel or compensate, again depending on their progress.
+ * <li>only if all participants progress to the 'completed' state may the initiator decide on the
+ * way to go.
+ * </ul>
+ *
+ * This class overrides the handleTransition method of BACoordinator and adds handling for
+ * participants who reach one of the 'completed', 'exiting' or 'faulting' states and hence
+ * require action on the other participants.
+ *
+ *
+ * @author Hannes Erven, Georg Hicker (C) 2006
+ *
+ */
+public class BAwithAtomicOutcomeCoordinator extends BACoordinator {
+
+ /**
+ * The object containing the outcome decision.
+ */
+ private final BAAtomicOutcome myOutcome = new BAAtomicOutcome();
+
+ /**
+ * Default constructor, called by the activation service. Prepares a new
+ * empty business activity context.
+ * @param superContext The super context, null if there is no super context.
+ *
+ * @throws MalformedURIException Indicates a severe programming error in the @see BACoordinator#COORDINATION_TYPE__ATOMIC constant.
+ * @throws InvalidOutcomeAssertion Indicates a severe programming error in the @see BACoordinator#COORDINATION_TYPE__ATOMIC constant.
+ */
+ public BAwithAtomicOutcomeCoordinator(
+ final CreateCoordinationContextTypeCurrentContext superContext
+ )
+ throws MalformedURIException, InvalidOutcomeAssertion
+ {
+ super(BACoordinator.COORDINATION_TYPE__ATOMIC, superContext);
+ }
+
+ /**
+ * This method adds handling logic for participants that reach one of the
+ * 'completed' or 'faulting' states and hence
+ * may require action on the other participants.
+ *
+ * This method uses the following process logic:
+ * <ul>
+ * <li>faulting: decide to cancel or compensate all participants
+ * <li>completed: check if the outcome has already been decided. If yes, compensate; if no, check if all participants
+ * are in state 'completed' and wait for the initiator to decide.
+ * </ul>
+ *
+ *
+ * @see org.apache.kandula.coordinator.ba.coordinator.BACoordinator#handleStateTransition(org.apache.kandula.coordinator.ba.coordinator.AbstractCoordParticipant, javax.xml.namespace.QName)
+ */
+ public void handleStateTransition(
+ final AbstractCoordParticipant participant,
+ final QName newState
+ ) throws RemoteException {
+
+ synchronized(this){
+// if (false
+// || State.STATE_FAULTING.equals(newState)
+// || State.STATE_FAULTING_ACTIVE.equals(newState)
+// ){
+ // new State: Faulting! decide to cancel/compensate if not already done
+ // remark: it is impossible that at this point it has already been decided to close, since
+ // fault is no valid message when closing.
+//
+ // TODO BA Perhaps it is better to support this as an optional feature.
+
+// if (! this.myOutcome.isDecided()){
+// System.out.println("Auto-deciding "+this.getID()+" to cancel/compensate due to participant fault ");
+// this.myOutcome.decideToCancelOrCompensate();
+// }
+
+// executeDecision();
+// }else
+ if (false
+ || State.STATE_COMPLETED.equals(newState)
+ ){
+ // If it has already been decided to abort the transaction,
+ // and a participant reports completed, automatically
+ // compensate them.
+ if (this.myOutcome.isDecidedToCancelOrCompensate()){
+ participant.tellCompensate();
+ }
+ }
+
+ super.handleStateTransition(participant, newState);
+ }
+ }
+
+ /**
+ * Execute a given decision.
+ * This means, if decision is
+ * <ul>
+ * <li>undecided: throw illegalstateexception
+ * <li>close: tell all participants who are in state completed to close.
+ * <li>cancel or compensate: tell all participants who are in active or completing to cancel,
+ * participants who are in completed to compensate and ignore all others.
+ * </ul>
+ *
+ */
+ protected void executeDecision() {
+ if (! this.myOutcome.isDecided())
+ throw new IllegalStateException("No decision to execute: it's still undecided!");
+
+ synchronized (this) {
+ final Collection participants = this.getParticipants();
+ final Iterator it = participants.iterator();
+
+ while(it.hasNext()){
+ final AbstractCoordParticipant part = (AbstractCoordParticipant) it.next();
+
+ if (this.myOutcome.isDecidedToClose()){
+ if (State.STATE_COMPLETED.equals( part.getCurrentState() ) ){
+ // We expect all participants to be in this state...
+
+ try{
+ part.tellClose();
+ }catch(Exception e){
+ e.printStackTrace();
+ // Ignore exceptions
+ }
+ }
+ // end Close Outcome
+ }else if (this.myOutcome.isDecidedToCancelOrCompensate()){
+ final QName cState = part.getCurrentState();
+
+ try{
+ if (false
+ || State.STATE_ACTIVE.equals( cState )
+ || State.STATE_COMPLETING.equals( cState )
+ ){
+ part.tellCancel();
+ }else if (false
+ || State.STATE_COMPLETED.equals( cState )
+ ){
+ part.tellCompensate();
+ }
+ }catch(Exception e){
+ e.printStackTrace();
+ // ignore exception
+ }
+
+ // end cancel/compensate outcome
+ }else{
+ throw new IllegalArgumentException("Sorry, unknown decided outcome: "+this.myOutcome.getOutcome());
+ }
+ }
+ }
+ }
+
+ /**
+ * Check if the current state of the transaction allows for additional
+ * @see #myOutcome
+ * @return true, if registration is possible.
+ * false, if no more registrations are accepted.
+ *
+ */
+ boolean isRegistrationPossible() {
+ return (! this.myOutcome.isDecided());
+ }
+
+ /**
+ * Return the outcome object.
+ * @return The outcome container.
+ */
+ public BAAtomicOutcome getOutcomeDecision() {
+ return this.myOutcome;
+ }
+
+
+}
Added: webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwithMixedOutcomeCoordinator.java
URL: http://svn.apache.org/viewvc/webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwithMixedOutcomeCoordinator.java?view=auto&rev=548471
==============================================================================
--- webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwithMixedOutcomeCoordinator.java (added)
+++ webservices/kandula/branches/Kandula_1/src/java/org/apache/kandula/coordinator/ba/coordinator/BAwithMixedOutcomeCoordinator.java Mon Jun 18 13:10:02 2007
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2007 The Apache Software Foundation.
+ *
+ * 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.
+ *
+ * @author Hannes Erven, Georg Hicker
+ */
+
+package org.apache.kandula.coordinator.ba.coordinator;
+
+import org.apache.axis.types.URI.MalformedURIException;
+import org.apache.kandula.wscoor.CreateCoordinationContextTypeCurrentContext;
+
+/**
+ *
+ * @author Hannes Erven, Georg Hicker (C) 2006
+ *
+ */
+public class BAwithMixedOutcomeCoordinator extends BACoordinator {
+
+ /**
+ * Create a new mixed outcome BA Coordinator.
+ *
+ * @param superContext The super context, if any
+ * @throws MalformedURIException Invalid URI.
+ * @throws InvalidOutcomeAssertion Invalid Outcome Type
+ */
+ public BAwithMixedOutcomeCoordinator(
+ final CreateCoordinationContextTypeCurrentContext superContext
+ ) throws MalformedURIException, InvalidOutcomeAssertion {
+ super(BACoordinator.COORDINATION_TYPE__MIXED, superContext);
+ }
+
+ /**
+ * Check if additional participants are allowed to register. With mixed
+ * outcome, this is always true.
+ * @return true
+ */
+ boolean isRegistrationPossible() {
+ return true;
+ }
+
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: kandula-dev-unsubscribe@ws.apache.org
For additional commands, e-mail: kandula-dev-help@ws.apache.org