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 }