/*
 * JBoss, Home of Professional Open Source
 * Copyright 2007, Red Hat Middleware LLC, and individual contributors
 * as indicated by the @author tags.
 * See the copyright.txt in the distribution for a full listing
 * of individual contributors.
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU General Public License, v. 2.0.
 * This program is distributed in the hope that it will be useful, but WITHOUT A
 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
 * PARTICULAR PURPOSE.  See the GNU General Public License for more details.
 * You should have received a copy of the GNU General Public License,
 * v. 2.0 along with this distribution; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
 * MA  02110-1301, USA.
 *
 * (C) 2007,
 * @author JBoss Inc.
 */
package org.jboss.txbridge.ba.participant;

import com.arjuna.wst.*;
import org.apache.log4j.Logger;
import org.jboss.txbridge.ba.SingleTransactionManager;
import org.jboss.txbridge.ba.datamgmt.ExecutionDataProviderImpl;
import org.jboss.txbridge.ba.data.TaskDescription;
import org.jboss.txbridge.ba.execute.ServiceExecutor;
import org.jboss.txbridge.ba.execute.RemoteServiceExecutor;
import org.jboss.txbridge.ba.execute.LocalServiceExecutor;
import org.jboss.txbridge.ba.execute.EJBExecution;
import org.jboss.txbridge.ba.annotation.ExecutionMode;
import org.jboss.txbridge.ba.service.ServiceDescription;
import org.jboss.txbridge.ba.service.MethodDescription;
import org.jboss.txbridge.ba.exception.ActionExecutionException;

import javax.naming.InitialContext;
import javax.transaction.UserTransaction;

/**
 * Implementation of the Participant that is enlisted for the Business Agreement with Coordinator
 * Completion protocol.
 *
 * @author Maciej P. Machulak (mmachulak@redhat.com)
 * @version 0.1
 */
public class CoordinatorCompletionParticipant extends ParticipantCompletionParticipant implements BusinessAgreementWithCoordinatorCompletionParticipant
{
    // Logger
    private static Logger log = Logger.getLogger(CoordinatorCompletionParticipant.class);

    /**
     * Constructor.
     *
     * @param txId      is the transaction identifier.
     * @param serviceId is the service identifier.
     * @param stm is the single transaction manager.
     * @param cdf is the datamgmt data factory that should be used by the participant
     */
    public CoordinatorCompletionParticipant(String txId, String serviceId, SingleTransactionManager stm, ManagedDataFactory cdf)
    {
        super(txId, serviceId, stm, cdf);
        completed = false;
        log.info("constructor()");
    }

    public void complete() throws WrongStateException, SystemException
    {
        log.info("complete()");
        Thread completionNotifier = new Thread(new CompletionNotifier(txId,stm));
        completionNotifier.start();
    }

    /**
     * Completeing the work, which is handled by the participant.
     *
     * @throws ActionExecutionException if execution of any action was not successful.
     */
    public void completeWork() throws ActionExecutionException
    {
        log.info("completeWork()");
        log.info("Starting transaction");
        completed = true;
        try
        {
            InitialContext initialContext = new InitialContext();
            UserTransaction transaction = (UserTransaction) initialContext.lookup("java:comp/UserTransaction");
            transaction.begin();
            for (String taskId : taskList)
            {
                log.info("Completeing task ID: " + taskId);

                // Obtain information about the service
                // TODO: Participant should have access to the service description, not just the ID
                log.info("Getting information about the service ID: " + serviceId);
                ServiceDescription sd = sim.getServiceById(serviceId);

                // If the execution is remote than use remote executor. Otherwise use the local one.
                // TODO: Following "if" statement is bad - I should change that -> factory! :)
                MethodDescription completeMethod = sd.getMethod("completeant d");
                ExecutionMode executionMode = completeMethod.getExecutionMode();
                log.info("Execution mode: " + executionMode);
                ServiceExecutor se;
                if (executionMode == ExecutionMode.DII)
                {
                    // Use the remote executor.
                    log.info("Using remote executor");
                    se = new RemoteServiceExecutor(new TaskDescription(txId,taskId,serviceId,this));
                }
                else if (executionMode == ExecutionMode.POJO)
                {
                    // Use the local executor.
                    log.info("Using local executor");
                    se = new LocalServiceExecutor(new TaskDescription(txId,taskId,serviceId,this));
                }
                else if (executionMode == ExecutionMode.EJB)
                {
                    // Use the local executor.
                    log.info("Using local executor");
                    se = new LocalServiceExecutor(new TaskDescription(txId,taskId,serviceId,this));
                    se.setExecutionType(new EJBExecution());
                }
                else
                {
                    throw new ActionExecutionException("Incorrect execution mode");
                }
                // Invoke the datamgmt action
                log.info("Invoking the completion action");
                se.invoke(completeMethod,new ExecutionDataProviderImpl(taskId,this));
            }
            log.info("Committing");
            transaction.commit();
        }
        catch (Exception e)
        {
            throw new ActionExecutionException(e);
        }
    }
}

