Package org.jboss.jca.core.workmanager

Source Code of org.jboss.jca.core.workmanager.WorkWrapper

/*
* JBoss, Home of Professional Open Source.
* Copyright 2010, Red Hat Middleware LLC, and individual contributors
* as indicated by the @author tags. See the copyright.txt file in the
* distribution for a full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/

package org.jboss.jca.core.workmanager;

import org.jboss.jca.core.CoreBundle;
import org.jboss.jca.core.CoreLogger;

import java.security.Principal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CountDownLatch;

import javax.resource.spi.work.ExecutionContext;
import javax.resource.spi.work.TransactionContext;
import javax.resource.spi.work.Work;
import javax.resource.spi.work.WorkCompletedException;
import javax.resource.spi.work.WorkContext;
import javax.resource.spi.work.WorkContextErrorCodes;
import javax.resource.spi.work.WorkContextLifecycleListener;
import javax.resource.spi.work.WorkEvent;
import javax.resource.spi.work.WorkException;
import javax.resource.spi.work.WorkListener;
import javax.security.auth.Subject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.message.callback.CallerPrincipalCallback;
import javax.security.auth.message.callback.GroupPrincipalCallback;
import javax.transaction.xa.Xid;

import org.jboss.logging.Logger;
import org.jboss.logging.Messages;

import org.jboss.security.SecurityContextAssociation;
import org.jboss.security.SecurityContextFactory;
import org.jboss.security.auth.callback.JASPICallbackHandler;

/**
* Wraps the resource adapter's work.
*
* @author <a href="mailto:jesper.pedersen@jboss.org">Jesper Pedersen</a>
* @version $Revision: 71538 $
*/
public class WorkWrapper implements Runnable
{
   /** The log */
   private static CoreLogger log = Logger.getMessageLogger(CoreLogger.class,
      WorkWrapper.class.getName());

   /** Whether we are tracing */
   private static boolean trace = log.isTraceEnabled();
  
   /** The bundle */
   private static CoreBundle bundle = Messages.getBundle(CoreBundle.class);
  
   /** The work */
   private Work work;

   /** The execution context */
   private ExecutionContext executionContext;
  
   /**If work is an instance of WorkContextProvider, it may contain WorkContext instances */
   private Map<Class<? extends WorkContext>, WorkContext> workContexts;

   /** the work listener */
   private WorkListener workListener;  

   /** The work manager */
   private WorkManagerImpl workManager;

   /** The start time */
   private long startTime;

   /** Any exception */
   private WorkException exception;

   /** Started latch */
   private CountDownLatch startedLatch;

   /** Completed latch */
   private CountDownLatch completedLatch;

   /**
    * Create a new WorkWrapper
    *
    * @param workManager the work manager
    * @param work the work
    * @param executionContext the execution context
    * @param workListener the WorkListener
    * @param startedLatch The latch for when work has started
    * @param completedLatch The latch for when work has completed
    * @param startTime The start time
    * @throws IllegalArgumentException for null work, execution context or a negative start timeout
    */
   public WorkWrapper(WorkManagerImpl workManager,
                      Work work,
                      ExecutionContext executionContext,
                      WorkListener workListener,
                      CountDownLatch startedLatch,
                      CountDownLatch completedLatch,
                      long startTime)
   {
      super();

      if (work == null)
         throw new IllegalArgumentException("Null work");
      if (executionContext == null)
         throw new IllegalArgumentException("Null execution context");

      this.workManager = workManager;
      this.work = work;
      this.executionContext = executionContext;
      this.workListener = workListener;
      this.startedLatch = startedLatch;
      this.completedLatch = completedLatch;
      this.startTime = startTime;
      this.workContexts = null;
   }
  
   /**
    * Get the work manager
    *
    * @return the work manager
    */
   public org.jboss.jca.core.api.workmanager.WorkManager getWorkManager()
   {
      return workManager;
   }

   /**
    * Retrieve the work
    *
    * @return the work
    */
   public Work getWork()
   {
      return work;
   }

   /**
    * Retrieve the exection context
    *
    * @return the execution context
    */
   public ExecutionContext getExecutionContext()
   {
      return executionContext;
   }

   /**
    * Retrieve the work listener
    *
    * @return the WorkListener
    */
   public WorkListener getWorkListener()
   {
      return workListener;
   }
  
   /**
    * Get any exception
    *
    * @return the exception or null if there is none
    */
   public WorkException getWorkException()
   {
      return exception;
   }

   /**
    * Set work exception
    * @param e The exception
    */
   void setWorkException(WorkException e)
   {
      exception = e;
   }

   /**
    * Run
    */
   public void run()
   {
      ClassLoader oldCL = SecurityActions.getThreadContextClassLoader();
      SecurityActions.setThreadContextClassLoader(work.getClass().getClassLoader());

      org.jboss.security.SecurityContext oldSC = SecurityContextAssociation.getSecurityContext();

      try
      {
         start();
         workManager.addWorkWrapper(this);

         if (startedLatch != null)
            startedLatch.countDown();

         work.run();

         end();
      }
      catch (Throwable t)
      {
         exception = new WorkCompletedException(t.getMessage(), t);

         cancel();
      }
      finally
      {
         workManager.removeWorkWrapper(this);
         work.release();

         if (workListener != null)
         {
            WorkEvent event = new WorkEvent(workManager, WorkEvent.WORK_COMPLETED, work, exception);
            workListener.workCompleted(event);
         }

         SecurityContextAssociation.setSecurityContext(oldSC);
         SecurityActions.setThreadContextClassLoader(oldCL);

         if (startedLatch != null)
         {
            while (startedLatch.getCount() != 0)
               startedLatch.countDown();
         }

         if (completedLatch != null)
            completedLatch.countDown();

         if (trace)
            log.tracef("Executed work: %s", this);
      }
   }

   /**
    * Start
    * @throws WorkException for any error
    */
   protected void start() throws WorkException
   {
      if (trace)
         log.tracef("Starting work: %s", this)

      if (workListener != null)
      {
         long duration = System.currentTimeMillis() - startTime;
         if (duration < 0)
            duration = javax.resource.spi.work.WorkManager.UNKNOWN;

         WorkEvent event = new WorkEvent(workManager, WorkEvent.WORK_STARTED, work, null, duration);
         workListener.workStarted(event);
      }

      // Transaction setup
      ExecutionContext ctx = getWorkContext(TransactionContext.class);
      if (ctx == null)
      {
         ctx = getExecutionContext();
      }
     
      if (ctx != null)
      {
         Xid xid = ctx.getXid();
         if (xid != null)
         {
            //JBAS-4002 base value is in seconds as per the API, here we convert to millis
            long timeout = (ctx.getTransactionTimeout() * 1000);
            workManager.getXATerminator().registerWork(work, xid, timeout);
         }
      }

      //Fires Context setup complete
      fireWorkContextSetupComplete(ctx);
     
      // Security setup
      javax.resource.spi.work.SecurityContext securityContext =
         getWorkContext(javax.resource.spi.work.SecurityContext.class);
      if (securityContext != null && workManager.getCallbackSecurity() != null)
      {
         if (trace)
            log.tracef("Setting security context: %s", securityContext);

         try
         {
            // Security context
            org.jboss.security.SecurityContext sc = null;

            // Setup callbacks
            CallbackHandler cbh = new JASPICallbackHandler();

            // Subjects for execution environment
            Subject executionSubject = null;
            Subject serviceSubject = null;
        
            if (trace)
               log.tracef("Callback security: %s", workManager.getCallbackSecurity());

            if (SecurityContextAssociation.getSecurityContext() == null ||
                workManager.getCallbackSecurity().getDomain() != null)
            {
               String scDomain = workManager.getCallbackSecurity().getDomain();

               if (trace)
                  log.tracef("Creating security context: %s", scDomain);

               if (scDomain == null || scDomain.trim().equals(""))
               {
                  fireWorkContextSetupFailed(securityContext);
                  throw new WorkException(bundle.securityContextSetupFailedSinceCallbackSecurityDomainWasEmpty());
               }

               sc = SecurityContextFactory.createSecurityContext(scDomain);
               SecurityContextAssociation.setSecurityContext(sc);
            }
            else
            {
               sc = SecurityContextAssociation.getSecurityContext();

               if (trace)
                  log.tracef("Using security context: %s", sc);
            }

            executionSubject = sc.getSubjectInfo().getAuthenticatedSubject();

            if (executionSubject == null)
            {
               if (trace)
                  log.tracef("Creating empty subject");

               executionSubject = new Subject();
            }

            // Resource adapter callback
            securityContext.setupSecurityContext(cbh, executionSubject, serviceSubject);

            List<Callback> callbacks = new ArrayList<Callback>();
            if (workManager.getCallbackSecurity().isMappingRequired())
            {
               // JCA 1.6: 16.4.4
            }

            if (workManager.getCallbackSecurity().getDefaultPrincipal() != null)
            {
               Principal defaultPrincipal = workManager.getCallbackSecurity().getDefaultPrincipal();
               CallerPrincipalCallback cpc =
                  new CallerPrincipalCallback(executionSubject, defaultPrincipal);

               callbacks.add(cpc);
            }

            if (workManager.getCallbackSecurity().getDefaultGroups() != null)
            {
               String[] defaultGroups = workManager.getCallbackSecurity().getDefaultGroups();
               GroupPrincipalCallback gpc =
                  new GroupPrincipalCallback(executionSubject, defaultGroups);

               callbacks.add(gpc);
            }

            if (callbacks.size() > 0)
            {
               Callback[] cb = new Callback[callbacks.size()];
               cbh.handle(callbacks.toArray(cb));
            }

            if (trace)
               log.tracef("Setting authenticated subject (%s) on security context (%s)", executionSubject, sc);

            // Set the authenticated subject
            sc.getSubjectInfo().setAuthenticatedSubject(executionSubject);

            fireWorkContextSetupComplete(securityContext);
         }
         catch (Throwable t)
         {
            log.securityContextSetupFailed(t.getMessage(), t);
            fireWorkContextSetupFailed(securityContext);
            throw new WorkException(bundle.securityContextSetupFailed(t.getMessage()), t);
         }
      }
      else if (securityContext != null && workManager.getCallbackSecurity() == null)
      {
         log.securityContextSetupFailedCallbackSecurityNull();
         fireWorkContextSetupFailed(securityContext);
         throw new WorkException(bundle.securityContextSetupFailedSinceCallbackSecurityWasNull());
      }
  
      if (ctx != null)
      {
         Xid xid = ctx.getXid();
         if (xid != null)
         {
            workManager.getXATerminator().startWork(work, xid);
         }
      }

      if (trace)
         log.tracef("Started work: %s", this)
   }

   /**
    * End
    */
   protected void end()
   {
      if (trace)
         log.tracef("Ending work: %s", this)

      ExecutionContext ctx = getWorkContext(TransactionContext.class);
      if (ctx == null)
      {
         ctx = getExecutionContext();
      }

      if (ctx != null)
      {
         Xid xid = ctx.getXid();
         if (xid != null)
         {
            workManager.getXATerminator().endWork(work, xid);
         }
      }

      if (trace)
         log.tracef("Ended work: %s", this)
   }

   /**
    * Cancel
    */
   protected void cancel()
   {
      if (trace)
         log.tracef("Cancel work: %s", this)

      ExecutionContext ctx = getWorkContext(TransactionContext.class);
      if (ctx == null)
      {
         ctx = getExecutionContext();
      }

      if (ctx != null)
      {
         Xid xid = ctx.getXid();
         if (xid != null)
         {
            workManager.getXATerminator().cancelWork(work, xid);
         }
      }

      if (trace)
         log.tracef("Canceled work: %s", this)
   }

   /**
    * Returns work context instance.
    *
    * @param <T> class type info
    * @param workContextClass work context type
    * @return work context instance
    */
   public <T> T getWorkContext(Class<T> workContextClass)
   {
      T instance = null;

      if (workContexts != null && workContexts.containsKey(workContextClass))
      {
         instance = workContextClass.cast(workContexts.get(workContextClass));
      }

      return instance;
   }

   /**
    * Adds new work context.
    *
    * @param workContext new work context
    * @param workContextClass work context class
    */
   public void addWorkContext(Class<? extends WorkContext> workContextClass, WorkContext workContext)
   {
      if (workContextClass == null)
      {
         throw new IllegalArgumentException("Work context class is null");
      }

      if (workContext == null)
      {
         throw new IllegalArgumentException("Work context is null");
      }

      if (workContexts == null)
      {
         workContexts = new HashMap<Class<? extends WorkContext>, WorkContext>(1);
      }

      if (trace)
         log.tracef("Adding work context %s for %s", workContextClass, this)

      workContexts.put(workContextClass, workContext);
   }
  
   /**
    * Calls listener after work context is setted up.
    * @param listener work context listener
    */
   private void fireWorkContextSetupComplete(Object workContext)
   {
      if (workContext != null && workContext instanceof WorkContextLifecycleListener)
      {
         if (trace)
            log.tracef("WorkContextSetupComplete(%s) for %s", workContext, this)

         WorkContextLifecycleListener listener = (WorkContextLifecycleListener)workContext;
         listener.contextSetupComplete();  
      }
   }
  
   /**
    * Calls listener if setup failed
    * @param listener work context listener
    */
   private void fireWorkContextSetupFailed(Object workContext)
   {
      if (workContext != null && workContext instanceof WorkContextLifecycleListener)
      {
         if (trace)
            log.tracef("WorkContextSetupFailed(%s) for %s", workContext, this)

         WorkContextLifecycleListener listener = (WorkContextLifecycleListener)workContext;
         listener.contextSetupFailed(WorkContextErrorCodes.CONTEXT_SETUP_FAILED);  
      }
   }
  
   /**
    * String representation
    * @return The string
    */
   public String toString()
   {
      StringBuilder buffer = new StringBuilder(100);
      buffer.append("WorkWrapper@").append(Integer.toHexString(System.identityHashCode(this)));
      buffer.append("[workManger=").append(workManager);
      buffer.append(" work=").append(work);

      if (executionContext != null && executionContext.getXid() != null)
      {
         buffer.append(" xid=").append(executionContext.getXid());
         buffer.append(" txTimeout=").append(executionContext.getTransactionTimeout());
      }

      buffer.append(" workListener=").append(workListener);

      buffer.append(" workContexts=").append(workContexts);

      buffer.append(" exception=").append(exception);

      buffer.append("]");

      return buffer.toString();
   }
}
TOP

Related Classes of org.jboss.jca.core.workmanager.WorkWrapper

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.