/* * JBoss, Home of Professional Open Source * Copyright 2015, Red Hat, Inc. and/or its affiliates, and individual * contributors by the @authors tag. See the copyright.txt in the * distribution for a full listing of individual contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.as.quickstarts.wsba.coordinatorcompletion.simple; import java.io.Serializable; import java.util.HashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; import com.arjuna.wst.BusinessAgreementWithCoordinatorCompletionParticipant; import com.arjuna.wst.FaultedException; import com.arjuna.wst.SystemException; import com.arjuna.wst.WrongStateException; import com.arjuna.wst11.ConfirmCompletedParticipant; /** * An adapter class that exposes the SetManager as a WS-BA participant using the 'Coordinator Completion' protocol. * <p/> * The Set Service can be invoked multiple times to add many items to the set within a single BA. The service waits for the * coordinator to tell it to complete. This has the advantage that the client can continue calling methods on the service right * up until it calls 'close'. However, any resources held by the service need to be held for this duration, unless the service * decides to autonomously cancel the BA. * * @author Paul Robinson (paul.robinson@redhat.com) */ public class SetParticipantBA implements BusinessAgreementWithCoordinatorCompletionParticipant, ConfirmCompletedParticipant, Serializable { private static final long serialVersionUID = 1L; // The ID of the corresponding transaction private String txID; // A list of values added to the set. These are removed from the set at // compensation time. private List<String> values = new LinkedList<>(); // table of currently active participants private static Map<String, SetParticipantBA> participants = new HashMap<>(); /** * Participant instances are related to business method calls in a one to one manner. * * @param txID The ID of the current Business Activity * @param value the value to remove from the set during compensation */ public SetParticipantBA(String txID, String value) { this.txID = txID; addValue(value); } /** * Notify the participant that another value is being added to the set. This is stored in case compensation is required. * * @param value the value being added to the set */ public void addValue(String value) { values.add(value); } /** * The transaction has completed successfully. The participant previously informed the coordinator that it was ready to * complete. * * @throws WrongStateException never in this implementation. * @throws SystemException never in this implementation. */ public void close() throws WrongStateException, SystemException { // nothing to do here as the item has already been added to the set System.out .println("[SERVICE] Participant.close (The participant knows that this BA is now finished and can throw away any temporary state)"); removeParticipant(txID); } /** * The transaction has canceled, and the participant should undo any work. The participant cannot have informed the * coordinator that it has completed. * * @throws WrongStateException never in this implementation. * @throws SystemException never in this implementation. */ public void cancel() throws WrongStateException, SystemException { System.out.println("[SERVICE] Participant.cancel (The participant should compensate any work done within this BA)"); doCompensate(); removeParticipant(txID); } /** * The transaction has cancelled. The participant previously informed the coordinator that it had finished work but could * compensate later if required, and it is now requested to do so. * * @throws WrongStateException never in this implementation. * @throws SystemException if unable to perform the compensating transaction. */ public void compensate() throws FaultedException, WrongStateException, SystemException { System.out.println("[SERVICE] Participant.compensate"); doCompensate(); removeParticipant(txID); } public String status() { return null; } public void unknown() throws SystemException { removeParticipant(txID); } public void error() throws SystemException { System.out.println("[SERVICE] Participant.error"); doCompensate(); removeParticipant(txID); } private void doCompensate() { System.out.println("[SERVICE] SetParticipantBA: Carrying out compensation action"); for (String value : values) { MockSetManager.rollback(value); } } @Override public void complete() throws WrongStateException, SystemException { System.out .println("[SERVICE] Participant.complete (This tells the participant that the BA completed, but may be compensated later)"); } /** * method called to perform commit or rollback of prepared changes to the underlying manager state after the participant * recovery record has been written * * @param confirmed true if the log record has been written and changes should be rolled forward and false if it has not * been written and changes should be rolled back */ public void confirmCompleted(boolean confirmed) { if (confirmed) { System.out .println("[SERVICE] Participant.confirmCompleted('" + confirmed + "') (This tells the participant that compensation information has been logged and that it is safe to commit any changes.)"); MockSetManager.commit(); } else { doCompensate(); } } /************************************************************************/ /* tracking active participants */ /************************************************************************/ /** * keep track of a participant * * @param txID the participant's transaction id * @param participant The participant associated with this BA */ public static synchronized void recordParticipant(String txID, SetParticipantBA participant) { participants.put(txID, participant); } /** * forget about a participant * * @param txID the participant's transaction id */ public static void removeParticipant(String txID) { participants.remove(txID); } /** * lookup a participant * * @param txID the participant's transaction id * @return the participant */ public static synchronized SetParticipantBA getParticipant(String txID) { return participants.get(txID); } }