View Javadoc
1   /*
2    * JBoss, Home of Professional Open Source
3    * Copyright 2014, Red Hat, Inc. and/or its affiliates, and individual
4    * contributors by the @authors tag. See the copyright.txt in the
5    * distribution for a full listing of individual contributors.
6    *
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   * http://www.apache.org/licenses/LICENSE-2.0
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.jboss.as.quickstarts.wsba.coordinatorcompletion.simple;
18  
19  import com.arjuna.wst.BusinessAgreementWithCoordinatorCompletionParticipant;
20  import com.arjuna.wst.FaultedException;
21  import com.arjuna.wst.SystemException;
22  import com.arjuna.wst.WrongStateException;
23  import com.arjuna.wst11.ConfirmCompletedParticipant;
24  import java.io.Serializable;
25  import java.util.HashMap;
26  import java.util.LinkedList;
27  import java.util.List;
28  
29  /**
30   * An adapter class that exposes the SetManager as a WS-BA participant using the 'Coordinator Completion' protocol.
31   * <p/>
32   * The Set Service can be invoked multiple times to add many items to the set within a single BA. The service waits for the
33   * coordinator to tell it to complete. This has the advantage that the client can continue calling methods on the service right
34   * up until it calls 'close'. However, any resources held by the service need to be held for this duration, unless the service
35   * decides to autonomously cancel the BA.
36   * 
37   * @author Paul Robinson (paul.robinson@redhat.com)
38   */
39  public class SetParticipantBA implements BusinessAgreementWithCoordinatorCompletionParticipant, ConfirmCompletedParticipant,
40          Serializable {
41      private static final long serialVersionUID = 1L;
42      // The ID of the corresponding transaction
43      private String txID;
44      // A list of values added to the set. These are removed from the set at
45      // compensation time.
46      private List<String> values = new LinkedList<String>();
47      // table of currently active participants
48      private static HashMap<String, SetParticipantBA> participants = new HashMap<String, SetParticipantBA>();
49  
50      /**
51       * Participant instances are related to business method calls in a one to one manner.
52       * 
53       * @param txID The ID of the current Business Activity
54       * @param value the value to remove from the set during compensation
55       */
56      public SetParticipantBA(String txID, String value) {
57          this.txID = txID;
58          addValue(value);
59      }
60  
61      /**
62       * Notify the participant that another value is being added to the set. This is stored in case compensation is required.
63       * 
64       * @param value the value being added to the set
65       */
66      public void addValue(String value) {
67          values.add(value);
68      }
69  
70      /**
71       * The transaction has completed successfully. The participant previously informed the coordinator that it was ready to
72       * complete.
73       * 
74       * @throws WrongStateException never in this implementation.
75       * @throws SystemException never in this implementation.
76       */
77      public void close() throws WrongStateException, SystemException {
78          // nothing to do here as the item has already been added to the set
79          System.out
80                  .println("[SERVICE] Participant.close (The participant knows that this BA is now finished and can throw away any temporary state)");
81          removeParticipant(txID);
82      }
83  
84      /**
85       * The transaction has canceled, and the participant should undo any work. The participant cannot have informed the
86       * coordinator that it has completed.
87       * 
88       * @throws WrongStateException never in this implementation.
89       * @throws SystemException never in this implementation.
90       */
91      public void cancel() throws WrongStateException, SystemException {
92          System.out.println("[SERVICE] Participant.cancel (The participant should compensate any work done within this BA)");
93          doCompensate();
94          removeParticipant(txID);
95      }
96  
97      /**
98       * The transaction has cancelled. The participant previously informed the coordinator that it had finished work but could
99       * compensate later if required, and it is now requested to do so.
100      * 
101      * @throws WrongStateException never in this implementation.
102      * @throws SystemException if unable to perform the compensating transaction.
103      */
104     public void compensate() throws FaultedException, WrongStateException, SystemException {
105         System.out.println("[SERVICE] Participant.compensate");
106         doCompensate();
107         removeParticipant(txID);
108     }
109 
110     public String status() {
111         return null;
112     }
113 
114     public void unknown() throws SystemException {
115         removeParticipant(txID);
116     }
117 
118     public void error() throws SystemException {
119         System.out.println("[SERVICE] Participant.error");
120         doCompensate();
121         removeParticipant(txID);
122     }
123 
124     private void doCompensate() {
125         System.out.println("[SERVICE] SetParticipantBA: Carrying out compensation action");
126         for (String value : values) {
127             MockSetManager.rollback(value);
128         }
129     }
130 
131     @Override
132     public void complete() throws WrongStateException, SystemException {
133         System.out
134                 .println("[SERVICE] Participant.complete (This tells the participant that the BA completed, but may be compensated later)");
135     }
136 
137     /**
138      * method called to perform commit or rollback of prepared changes to the underlying manager state after the participant
139      * recovery record has been written
140      * 
141      * @param confirmed true if the log record has been written and changes should be rolled forward and false if it has not
142      *        been written and changes should be rolled back
143      */
144     public void confirmCompleted(boolean confirmed) {
145         if (confirmed) {
146             System.out
147                     .println("[SERVICE] Participant.confirmCompleted('"
148                             + confirmed
149                             + "') (This tells the participant that compensation information has been logged and that it is safe to commit any changes.)");
150             MockSetManager.commit();
151         } else {
152             doCompensate();
153         }
154     }
155 
156     /************************************************************************/
157     /* tracking active participants */
158     /************************************************************************/
159     /**
160      * keep track of a participant
161      * 
162      * @param txID the participant's transaction id
163      * @param participant The participant associated with this BA
164      */
165     public static synchronized void recordParticipant(String txID, SetParticipantBA participant) {
166         participants.put(txID, participant);
167     }
168 
169     /**
170      * forget about a participant
171      * 
172      * @param txID the participant's transaction id
173      */
174     public static void removeParticipant(String txID) {
175         participants.remove(txID);
176     }
177 
178     /**
179      * lookup a participant
180      * 
181      * @param txID the participant's transaction id
182      * @return the participant
183      */
184     public static synchronized SetParticipantBA getParticipant(String txID) {
185         return participants.get(txID);
186     }
187 }