Home » geronimo-2.2-source-release » org.apache.geronimo.openejb » [javadoc | source]

    1   /**
    2    *
    3    * Licensed to the Apache Software Foundation (ASF) under one or more
    4    * contributor license agreements.  See the NOTICE file distributed with
    5    * this work for additional information regarding copyright ownership.
    6    * The ASF licenses this file to You under the Apache License, Version 2.0
    7    * (the "License"); you may not use this file except in compliance with
    8    * the License.  You may obtain a copy of the License at
    9    *
   10    *     http://www.apache.org/licenses/LICENSE-2.0
   11    *
   12    *  Unless required by applicable law or agreed to in writing, software
   13    *  distributed under the License is distributed on an "AS IS" BASIS,
   14    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   15    *  See the License for the specific language governing permissions and
   16    *  limitations under the License.
   17    */
   18   package org.apache.geronimo.openejb;
   19   
   20   import javax.naming.Context;
   21   import javax.resource.ResourceException;
   22   import javax.security.auth.Subject;
   23   import javax.security.jacc.PolicyContext;
   24   
   25   import org.slf4j.Logger;
   26   import org.slf4j.LoggerFactory;
   27   import org.apache.geronimo.connector.outbound.connectiontracking.ConnectorInstanceContext;
   28   import org.apache.geronimo.connector.outbound.connectiontracking.ConnectorInstanceContextImpl;
   29   import org.apache.geronimo.connector.outbound.connectiontracking.TrackedConnectionAssociator;
   30   import org.apache.geronimo.naming.java.RootContext;
   31   import org.apache.geronimo.security.Callers;
   32   import org.apache.geronimo.security.ContextManager;
   33   import org.apache.openejb.core.CoreDeploymentInfo;
   34   import org.apache.openejb.core.ThreadContext;
   35   import org.apache.openejb.core.ThreadContextListener;
   36   
   37   import java.util.Map;
   38   import java.util.concurrent.ConcurrentHashMap;
   39   import java.util.concurrent.Future;
   40   import java.util.concurrent.FutureTask;
   41   import java.util.concurrent.Callable;
   42   import java.util.concurrent.ExecutionException;
   43   import java.util.concurrent.atomic.AtomicReference;
   44   
   45   /**
   46    * @version $Rev: 831811 $ $Date: 2009-11-01 23:25:53 -0800 (Sun, 01 Nov 2009) $
   47    */
   48   public class GeronimoThreadContextListener implements ThreadContextListener {
   49       private static final Logger log = LoggerFactory.getLogger(GeronimoThreadContextListener.class);
   50   
   51       // A single stateless listener is used for Geronimo
   52       private static final GeronimoThreadContextListener instance = new GeronimoThreadContextListener();
   53   
   54       static {
   55           ThreadContext.addThreadContextListener(instance);
   56       }
   57   
   58       public static void init() {
   59           // do nothing.. the goal here is to kick off the onetime init above
   60       }
   61   
   62       private final Map<String, Deployment> ejbs = new ConcurrentHashMap<String, Deployment>();
   63   
   64       private GeronimoThreadContextListener() {
   65       }
   66   
   67       public static GeronimoThreadContextListener get() {
   68           return instance;
   69       }
   70   
   71       public void addEjb(EjbDeployment ejbDeployment) {
   72           this.ejbs.put(ejbDeployment.getDeploymentId(), new Deployment(ejbDeployment));
   73       }
   74   
   75       public void removeEjb(String id) {
   76           this.ejbs.remove(id);
   77       }
   78   
   79       EjbDeployment getEjbDeployment(CoreDeploymentInfo deploymentInfo) {
   80           Deployment deployment = ejbs.get(deploymentInfo.getDeploymentID());
   81   
   82           if (deployment == null) return null;
   83   
   84           return deployment.get(deploymentInfo);
   85       }
   86   
   87   
   88       public void contextEntered(ThreadContext oldContext, ThreadContext newContext) {
   89           CoreDeploymentInfo deploymentInfo = newContext.getDeploymentInfo();
   90           if (deploymentInfo == null) return;
   91   
   92           EjbDeployment ejbDeployment = getEjbDeployment(deploymentInfo);
   93   
   94           if (ejbDeployment == null) return;
   95   
   96           // Geronimo call context is used to track old state that must be restored
   97           GeronimoCallContext geronimoCallContext = new GeronimoCallContext();
   98   
   99           // Demarcate component boundaries for connection tracking if we have a tracker
  100           TrackedConnectionAssociator trackedConnectionAssociator = ejbDeployment.getTrackedConnectionAssociator();
  101           if (trackedConnectionAssociator != null) {
  102               // create the connector context... this only works with a TrackedConnectionAssociator using lazy association
  103               ConnectorInstanceContext connectorContext = new ConnectorInstanceContextImpl(ejbDeployment.getUnshareableResources(),
  104                       ejbDeployment.getApplicationManagedSecurityResources());
  105   
  106               // Set connector context
  107               try {
  108                   geronimoCallContext.oldConnectorContext = trackedConnectionAssociator.enter(connectorContext);
  109               } catch (ResourceException e) {
  110                   log.error("Error while entering TrackedConnectionAssociator");
  111                   return;
  112               }
  113           }
  114   
  115           // Get the jndi context
  116           Context jndiContext = ejbDeployment.getComponentContext();
  117           geronimoCallContext.oldJndiContext = RootContext.getComponentContext();
  118           // Set the jndi context into Geronimo's root context
  119           RootContext.setComponentContext(jndiContext);
  120   
  121           // set the policy (security) context id
  122           geronimoCallContext.contextID = PolicyContext.getContextID();
  123           String moduleID = newContext.getDeploymentInfo().getModuleID();
  124           PolicyContext.setContextID(moduleID);
  125   
  126           // set the default subject if needed
  127           if (ContextManager.getCurrentCaller() == null) {
  128               Subject defaultSubject = ejbDeployment.getDefaultSubject();
  129   
  130               if (defaultSubject != null) {
  131                   ContextManager.setCallers(defaultSubject, defaultSubject);
  132                   geronimoCallContext.clearCallers = true;
  133               }
  134           }
  135   
  136           // apply run as
  137           Subject runAsSubject = ejbDeployment.getRunAs();
  138           geronimoCallContext.callers = ContextManager.pushNextCaller(runAsSubject);
  139   
  140           newContext.set(GeronimoCallContext.class, geronimoCallContext);
  141       }
  142   
  143       public void contextExited(ThreadContext exitedContext, ThreadContext reenteredContext) {
  144           CoreDeploymentInfo deploymentInfo = exitedContext.getDeploymentInfo();
  145           if (deploymentInfo == null) return;
  146   
  147           EjbDeployment ejbDeployment = deploymentInfo.get(EjbDeployment.class);
  148           if (ejbDeployment == null) return;
  149   
  150           // Geronimo call context is used to track old state that must be restored
  151           GeronimoCallContext geronimoCallContext = exitedContext.get(GeronimoCallContext.class);
  152           if (geronimoCallContext == null) return;
  153   
  154           // reset run as
  155           ContextManager.popCallers(geronimoCallContext.callers);
  156   
  157           // reset default subject
  158           if (geronimoCallContext.clearCallers) {
  159               ContextManager.clearCallers();
  160           }
  161   
  162           //reset ContextID
  163           PolicyContext.setContextID(geronimoCallContext.contextID);
  164   
  165           // reset Geronimo's root jndi context
  166           RootContext.setComponentContext(geronimoCallContext.oldJndiContext);
  167   
  168           // reset old connector context
  169           TrackedConnectionAssociator trackedConnectionAssociator = ejbDeployment.getTrackedConnectionAssociator();
  170           if (trackedConnectionAssociator != null) {
  171               try {
  172                   trackedConnectionAssociator.exit(geronimoCallContext.oldConnectorContext);
  173               } catch (ResourceException e) {
  174                   log.error("Error while exiting TrackedConnectionAssociator");
  175               }
  176           }
  177       }
  178   
  179       private static final class Deployment {
  180           private final EjbDeployment geronimoDeployment;
  181           private final AtomicReference<Future<EjbDeployment>> initialized = new AtomicReference<Future<EjbDeployment>>();
  182   
  183           private Deployment(EjbDeployment geronimoDeployment) {
  184               this.geronimoDeployment = geronimoDeployment;
  185           }
  186   
  187           public EjbDeployment get(final CoreDeploymentInfo openejbDeployment) {
  188               try {
  189                   // Has the deployment been initialized yet?
  190   
  191                   // If there is a Future object in the AtomicReference, then
  192                   // it's either been initialized or is being initialized now.
  193                   Future<EjbDeployment> initializedRef = initialized.get();
  194                   if (initializedRef != null) return initializedRef.get();
  195   
  196                   // The deployment has not been initialized nor is being initialized
  197   
  198                   // We will construct this FutureTask and compete with the
  199                   // other threads for the right to initialize the deployment
  200                   FutureTask<EjbDeployment> initializer = new FutureTask<EjbDeployment>(new Callable<EjbDeployment>() {
  201                       public EjbDeployment call() throws Exception {
  202                           return geronimoDeployment.initialize(openejbDeployment);
  203                       }
  204                   });
  205   
  206   
  207                   do {
  208                       // If our FutureTask was the one to win the slot
  209                       // than we are the ones responsisble for initializing
  210                       // the deployment while the others wait.
  211                       if (initialized.compareAndSet(null, initializer)) {
  212                           initializer.run();
  213                       }
  214   
  215                       // If we didn't win the slot and no other FutureTask
  216                       // has been set by a different thread, than we need
  217                       // to try again.
  218                   } while ((initializedRef = initialized.get()) == null);
  219   
  220   
  221                   // At this point we can safely return the initialized deployment
  222                   return initializedRef.get();
  223               } catch (InterruptedException e) {
  224                   Thread.interrupted();
  225                   throw new IllegalStateException("EjbDeployment.initialize() interrupted", e);
  226               } catch (ExecutionException e) {
  227                   throw new IllegalStateException("EjbDeployment.initialize() failed", e.getCause());
  228               }
  229           }
  230       }
  231       
  232       private static final class GeronimoCallContext {
  233           private Context oldJndiContext;
  234           private ConnectorInstanceContext oldConnectorContext;
  235           private boolean clearCallers;
  236           private Callers callers;
  237           private String contextID;
  238       }
  239   }

Home » geronimo-2.2-source-release » org.apache.geronimo.openejb » [javadoc | source]