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: 706640 $ $Date: 2008-10-21 14:44:05 +0000 (Tue, 21 Oct 2008) $
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 if (deploymentInfo.get(EjbDeployment.class) == null) {
061 synchronized (deploymentInfo) {
062 if (deploymentInfo.get(EjbDeployment.class) == null) {
063 if (!deploymentInfo.isDestroyed()) {
064 try {
065 deploymentInfo.wait();
066 } catch (InterruptedException e) {
067 log.warn("Wait on deploymentInfo interrupted unexpectedly");
068 }
069 }
070 }
071 }
072 }
073 EjbDeployment ejbDeployment = deploymentInfo.get(EjbDeployment.class);
074 if (ejbDeployment == null) return;
075
076 // Geronimo call context is used to track old state that must be restored
077 GeronimoCallContext geronimoCallContext = new GeronimoCallContext();
078
079 // Demarcate component boundaries for connection tracking if we have a tracker
080 TrackedConnectionAssociator trackedConnectionAssociator = ejbDeployment.getTrackedConnectionAssociator();
081 if (trackedConnectionAssociator != null) {
082 // create the connector context... this only works with a TrackedConnectionAssociator using lazy association
083 ConnectorInstanceContext connectorContext = new ConnectorInstanceContextImpl(ejbDeployment.getUnshareableResources(),
084 ejbDeployment.getApplicationManagedSecurityResources());
085
086 // Set connector context
087 try {
088 geronimoCallContext.oldConnectorContext = trackedConnectionAssociator.enter(connectorContext);
089 } catch (ResourceException e) {
090 log.error("Error while entering TrackedConnectionAssociator");
091 return;
092 }
093 }
094
095 // Get the jndi context
096 Context jndiContext = ejbDeployment.getComponentContext();
097 geronimoCallContext.oldJndiContext = RootContext.getComponentContext();
098 // Set the jndi context into Geronimo's root context
099 RootContext.setComponentContext(jndiContext);
100
101 // set the policy (security) context id
102 geronimoCallContext.contextID = PolicyContext.getContextID();
103 String moduleID = newContext.getDeploymentInfo().getModuleID();
104 PolicyContext.setContextID(moduleID);
105
106 // set the default subject if needed
107 if (ContextManager.getCurrentCaller() == null) {
108 Subject defaultSubject = ejbDeployment.getDefaultSubject();
109
110 if (defaultSubject != null) {
111 ContextManager.setCallers(defaultSubject, defaultSubject);
112 geronimoCallContext.clearCallers = true;
113 }
114 }
115
116 // apply run as
117 Subject runAsSubject = ejbDeployment.getRunAs();
118 geronimoCallContext.callers = ContextManager.pushNextCaller(runAsSubject);
119
120 newContext.set(GeronimoCallContext.class, geronimoCallContext);
121 }
122
123 public void contextExited(ThreadContext exitedContext, ThreadContext reenteredContext) {
124 CoreDeploymentInfo deploymentInfo = exitedContext.getDeploymentInfo();
125 if (deploymentInfo == null) return;
126
127 EjbDeployment ejbDeployment = deploymentInfo.get(EjbDeployment.class);
128 if (ejbDeployment == null) return;
129
130 // Geronimo call context is used to track old state that must be restored
131 GeronimoCallContext geronimoCallContext = exitedContext.get(GeronimoCallContext.class);
132 if (geronimoCallContext == null) return;
133
134 // reset run as
135 ContextManager.popCallers(geronimoCallContext.callers);
136
137 // reset default subject
138 if (geronimoCallContext.clearCallers) {
139 ContextManager.clearCallers();
140 }
141
142 //reset ContextID
143 PolicyContext.setContextID(geronimoCallContext.contextID);
144
145 // reset Geronimo's root jndi context
146 RootContext.setComponentContext(geronimoCallContext.oldJndiContext);
147
148 // reset old connector context
149 TrackedConnectionAssociator trackedConnectionAssociator = ejbDeployment.getTrackedConnectionAssociator();
150 if (trackedConnectionAssociator != null) {
151 try {
152 trackedConnectionAssociator.exit(geronimoCallContext.oldConnectorContext);
153 } catch (ResourceException e) {
154 log.error("Error while exiting TrackedConnectionAssociator");
155 }
156 }
157 }
158
159 private static final class GeronimoCallContext {
160 private Context oldJndiContext;
161 private ConnectorInstanceContext oldConnectorContext;
162 private boolean clearCallers;
163 private Callers callers;
164 private String contextID;
165 }
166 }