package org.camunda.bpm.container.impl.threading.ra;

import java.io.Serializable;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.resource.ResourceException;
import javax.resource.spi.ActivationSpec;
import javax.resource.spi.BootstrapContext;
import javax.resource.spi.ConfigProperty;
import javax.resource.spi.Connector;
import javax.resource.spi.ResourceAdapter;
import javax.resource.spi.ResourceAdapterInternalException;
import javax.resource.spi.TransactionSupport;
import javax.resource.spi.endpoint.MessageEndpointFactory;
import javax.transaction.xa.XAResource;

import org.camunda.bpm.container.impl.threading.ra.commonj.CommonJWorkManagerExecutorService;
import org.camunda.bpm.container.impl.threading.ra.inflow.JobExecutionHandler;
import org.camunda.bpm.container.impl.threading.ra.inflow.JobExecutionHandlerActivation;
import org.camunda.bpm.container.impl.threading.ra.inflow.JobExecutionHandlerActivationSpec;


/**
 * <p>The {@link ResourceAdapter} responsible for bootstrapping the JcaExecutorService</p>
 * 
 * @author Daniel Meyer
 */
@Connector(
    reauthenticationSupport = false, 
    transactionSupport = TransactionSupport.TransactionSupportLevel.NoTransaction  
  )
public class JcaExecutorServiceConnector implements ResourceAdapter, Serializable {

  /**
   * This class must be free of engine classes to make it possible to install
   * the resource adapter without shared libraries. Some deployments scenarios might
   * require that.
   *
   * The wrapper class was introduced to provide more meaning to a otherwise
   * unspecified property.
   */
  public class ExecutorServiceWrapper {
    protected Object executorService;

    public Object getExecutorService() {
      return executorService;
    }

    private void setExecutorService(Object executorService) {
      this.executorService = executorService;
    }

  }

  protected ExecutorServiceWrapper executorServiceWrapper;

  private static final long serialVersionUID = 1L;

  private static Logger log = Logger.getLogger(JcaExecutorServiceConnector.class.getName());

  protected JobExecutionHandlerActivation jobHandlerActivation;

  // no arg-constructor
  public JcaExecutorServiceConnector() {
  }

  // Configuration Properties //////////////////////////////////////////
  
  @ConfigProperty(
      type = Boolean.class,
      defaultValue = "false",
      description = "If set to 'true', the CommonJ WorkManager is used instead of the Jca Work Manager."
      + "Can only be used on platforms where a CommonJ Workmanager is available (such as IBM & Oracle)"
  )
  protected Boolean isUseCommonJWorkManager = false;
  
  
  @ConfigProperty( 
      type=String.class, 
      defaultValue = "wm/camunda-bpm-workmanager",
      description="Allows specifying the name of a CommonJ Workmanager."      		
  )
  protected String commonJWorkManagerName = "wm/camunda-bpm-workmanager";
  
  
  // RA-Lifecycle ///////////////////////////////////////////////////
  
  public void start(BootstrapContext ctx) throws ResourceAdapterInternalException {

    try {
      Class.forName("org.activiti.engine.ProcessEngine");
    } catch (ClassNotFoundException e) {
      log.info("ProcessEngine classes not found in shared libraries. Not initializing Fox Platform JobExecutor Resource Adapter.");
      return;
    }

    executorServiceWrapper = new ExecutorServiceWrapper();

    // initialize the ExecutorService (CommonJ or JCA, depending on configuration)
    if(isUseCommonJWorkManager) {
      if(commonJWorkManagerName != null & commonJWorkManagerName.length() > 0) {
        executorServiceWrapper.setExecutorService(new CommonJWorkManagerExecutorService(this, commonJWorkManagerName));
      } else {
        throw new RuntimeException("Resource Adapter configuration property 'isUseCommonJWorkManager' is set to true but 'commonJWorkManagerName' is not provided.");
      }
      
    } else {
      executorServiceWrapper.setExecutorService(new JcaWorkManagerExecutorService(this, ctx.getWorkManager()));
    }
    
    log.log(Level.INFO, "camunda BPM executor service started.");
  }

  public void stop() {
    try {
      Class.forName("org.activiti.engine.ProcessEngine");
    } catch (ClassNotFoundException e) {
      return;
    }

    log.log(Level.INFO, "camunda BPM executor service stopped.");
    
  }
  
  // JobHandler activation / deactivation ///////////////////////////

  public void endpointActivation(MessageEndpointFactory endpointFactory, ActivationSpec spec) throws ResourceException {
    if(jobHandlerActivation != null) {
      throw new ResourceException("The camunda BPM job executor can only service a single MessageEndpoint for job execution. " +
      		"Make sure not to deploy more than one MDB implementing the '"+JobExecutionHandler.class.getName()+"' interface.");
    }
    JobExecutionHandlerActivation activation = new JobExecutionHandlerActivation(this, endpointFactory, (JobExecutionHandlerActivationSpec) spec);
    activation.start();
    jobHandlerActivation = activation;
  }

  public void endpointDeactivation(MessageEndpointFactory endpointFactory, ActivationSpec spec) {
    try {
      if(jobHandlerActivation != null) {
        jobHandlerActivation.stop();
      }
    } finally {
      jobHandlerActivation = null;
    }
  }

  // unsupported (No TX Support) ////////////////////////////////////////////
  
  public XAResource[] getXAResources(ActivationSpec[] specs) throws ResourceException {
    log.finest("getXAResources()");
    return null;
  }
  
  // getters ///////////////////////////////////////////////////////////////
  
  public ExecutorServiceWrapper getExecutorServiceWrapper() {
    return executorServiceWrapper;
  }
   
  public JobExecutionHandlerActivation getJobHandlerActivation() {
    return jobHandlerActivation;
  }
    
  public Boolean getIsUseCommonJWorkManager() {
    return isUseCommonJWorkManager;
  }
  
  public void setIsUseCommonJWorkManager(Boolean isUseCommonJWorkManager) {
    this.isUseCommonJWorkManager = isUseCommonJWorkManager;
  }
  
  public String getCommonJWorkManagerName() {
    return commonJWorkManagerName;
  }
  
  public void setCommonJWorkManagerName(String commonJWorkManagerName) {
    this.commonJWorkManagerName = commonJWorkManagerName;
  }
  
  
  // misc //////////////////////////////////////////////////////////////////


  @Override
  public int hashCode() {
    return 17;
  }

  @Override
  public boolean equals(Object other) {
    if (other == null) {
      return false;
    }
    if (other == this) {
      return true;
    }
    if (!(other instanceof JcaExecutorServiceConnector)) {
      return false;
    }
    return true;
  }

}

@@ -1941,16 +1941,47 @@
 eWrapper
+ = new ExecutorServiceWrapper()
 ;%0A%0A  pri
@@ -3367,68 +3367,8 @@
  %7D%0A%0A
-    executorServiceWrapper = new ExecutorServiceWrapper();%0A%0A
     

move instantiation of wrapper