001    /**
002     *
003     * Licensed to the Apache Software Foundation (ASF) under one or more
004     * contributor license agreements.  See the NOTICE file distributed with
005     * this work for additional information regarding copyright ownership.
006     * The ASF licenses this file to You under the Apache License, Version 2.0
007     * (the "License"); you may not use this file except in compliance with
008     * the License.  You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     *  Unless required by applicable law or agreed to in writing, software
013     *  distributed under the License is distributed on an "AS IS" BASIS,
014     *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     *  See the License for the specific language governing permissions and
016     *  limitations under the License.
017     */
018    package org.apache.geronimo.openejb;
019    
020    import javax.naming.Context;
021    import javax.resource.ResourceException;
022    import javax.security.auth.Subject;
023    import javax.security.jacc.PolicyContext;
024    
025    import org.apache.commons.logging.Log;
026    import org.apache.commons.logging.LogFactory;
027    import org.apache.geronimo.connector.outbound.connectiontracking.ConnectorInstanceContext;
028    import org.apache.geronimo.connector.outbound.connectiontracking.ConnectorInstanceContextImpl;
029    import org.apache.geronimo.connector.outbound.connectiontracking.TrackedConnectionAssociator;
030    import org.apache.geronimo.naming.java.RootContext;
031    import org.apache.geronimo.security.Callers;
032    import org.apache.geronimo.security.ContextManager;
033    import org.apache.openejb.core.CoreDeploymentInfo;
034    import org.apache.openejb.core.ThreadContext;
035    import org.apache.openejb.core.ThreadContextListener;
036    
037    /**
038     * @version $Rev$ $Date$
039     */
040    public class GeronimoThreadContextListener implements ThreadContextListener {
041        private static final Log log = LogFactory.getLog(GeronimoThreadContextListener.class);
042    
043        // A single stateless listener is used for Geronimo
044        private static final GeronimoThreadContextListener instance = new GeronimoThreadContextListener();
045    
046        static {
047            ThreadContext.addThreadContextListener(instance);
048        }
049    
050        public static void init() {
051            // do nothing.. the goal here is to kick off the onetime init above
052        }
053    
054        private GeronimoThreadContextListener() {
055        }
056    
057        public void contextEntered(ThreadContext oldContext, ThreadContext newContext) {
058            CoreDeploymentInfo deploymentInfo = newContext.getDeploymentInfo();
059            if (deploymentInfo == null) return;
060    
061            EjbDeployment ejbDeployment = deploymentInfo.get(EjbDeployment.class);
062            if (ejbDeployment == null) return;
063    
064            // Geronimo call context is used to track old state that must be restored
065            GeronimoCallContext geronimoCallContext = new GeronimoCallContext();
066    
067            // Get the jndi context
068            Context jndiContext = ejbDeployment.getComponentContext();
069            geronimoCallContext.oldJndiContext = RootContext.getComponentContext();
070    
071            // Demark component boundries for connection tracking if we have a tracker
072            TrackedConnectionAssociator trackedConnectionAssociator = ejbDeployment.getTrackedConnectionAssociator();
073            if (trackedConnectionAssociator != null) {
074                // create the connector context... this only works with a TrackedConnectionAssociator using lazy association
075                ConnectorInstanceContext connectorContext = new ConnectorInstanceContextImpl(ejbDeployment.getUnshareableResources(),
076                        ejbDeployment.getApplicationManagedSecurityResources());
077    
078                // Set connector context
079                try {
080                    geronimoCallContext.oldConnectorContext = trackedConnectionAssociator.enter(connectorContext);
081                } catch (ResourceException e) {
082                    log.error("Error while entering TrackedConnectionAssociator");
083                    return;
084                }
085            }
086    
087            // Set the jndi context into Geronimo's root context
088            RootContext.setComponentContext(jndiContext);
089    
090            // set the policy (security) context id
091            String moduleID = newContext.getDeploymentInfo().getModuleID();
092            PolicyContext.setContextID(moduleID);
093    
094            // set the default subject if needed
095            if (ContextManager.getCurrentCaller() == null) {
096                Subject defaultSubject = ejbDeployment.getDefaultSubject();
097    
098                if (defaultSubject != null) {
099                    ContextManager.setCallers(defaultSubject, defaultSubject);
100                    geronimoCallContext.clearCallers = true;
101                }
102            }
103    
104            // apply run as
105            Subject runAsSubject = ejbDeployment.getRunAs();
106            geronimoCallContext.callers = ContextManager.pushNextCaller(runAsSubject);
107    
108            newContext.set(GeronimoCallContext.class, geronimoCallContext);
109        }
110    
111        public void contextExited(ThreadContext exitedContext, ThreadContext reenteredContext) {
112            CoreDeploymentInfo deploymentInfo = exitedContext.getDeploymentInfo();
113            if (deploymentInfo == null) return;
114    
115            EjbDeployment ejbDeployment = deploymentInfo.get(EjbDeployment.class);
116            if (ejbDeployment == null) return;
117    
118            // Geronimo call context is used to track old state that must be restored
119            GeronimoCallContext geronimoCallContext = exitedContext.get(GeronimoCallContext.class);
120            if (geronimoCallContext == null) return;
121    
122            // reset run as
123            ContextManager.popCallers(geronimoCallContext.callers);
124    
125            // reset default subject
126            if (geronimoCallContext.clearCallers) {
127                ContextManager.clearCallers();
128            }
129    
130            // reset Geronimo's root jndi context
131            RootContext.setComponentContext(geronimoCallContext.oldJndiContext);
132    
133            // reset old connector context
134            TrackedConnectionAssociator trackedConnectionAssociator = ejbDeployment.getTrackedConnectionAssociator();
135            if (trackedConnectionAssociator != null) {
136                try {
137                    trackedConnectionAssociator.exit(geronimoCallContext.oldConnectorContext);
138                } catch (ResourceException e) {
139                    log.error("Error while exiting TrackedConnectionAssociator");
140                }
141            }
142        }
143    
144        private static final class GeronimoCallContext {
145            private Context oldJndiContext;
146            private ConnectorInstanceContext oldConnectorContext;
147            private boolean clearCallers;
148            private Callers callers;
149        }
150    }