| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.apache.openejb.arquillian.common; |
| |
| import org.apache.openejb.AppContext; |
| import org.apache.openejb.BeanContext; |
| import org.apache.openejb.core.ThreadContext; |
| import org.apache.openejb.loader.SystemInstance; |
| import org.apache.openejb.spi.ContainerSystem; |
| import org.jboss.arquillian.container.spi.context.annotation.DeploymentScoped; |
| import org.jboss.arquillian.container.spi.event.container.AfterDeploy; |
| import org.jboss.arquillian.container.spi.event.container.BeforeUnDeploy; |
| import org.jboss.arquillian.core.api.Instance; |
| import org.jboss.arquillian.core.api.InstanceProducer; |
| import org.jboss.arquillian.core.api.annotation.Inject; |
| import org.jboss.arquillian.core.api.annotation.Observes; |
| import org.jboss.arquillian.core.spi.EventContext; |
| import org.jboss.arquillian.test.spi.TestClass; |
| import org.jboss.arquillian.test.spi.event.suite.TestEvent; |
| |
| import javax.enterprise.context.spi.CreationalContext; |
| import java.util.HashMap; |
| import java.util.Map; |
| |
| public class TestObserver { |
| @Inject |
| private Instance<ClassLoaders> classLoader; |
| |
| @Inject |
| private Instance<TestClass> testClass; |
| |
| @Inject |
| @DeploymentScoped |
| private InstanceProducer<DeploymentContext> contextProducer; |
| |
| @Inject |
| private Instance<DeploymentContext> context; |
| |
| public void observesDeploy(@Observes final AfterDeploy afterDeployment) { |
| contextProducer.set(new DeploymentContext(Thread.currentThread().getContextClassLoader()/*use as a fallback, multiple deployment can have webapp loader*/)); |
| final ClassLoaders loader = classLoader.get(); |
| final String name = afterDeployment.getDeployment().getArchive() != null ? afterDeployment.getDeployment().getArchive().getName() : null; |
| if (loader != null && loader.classloaders.containsKey(name)) { |
| setTCCL(loader.classloaders.get(name)); |
| } |
| } |
| |
| public void observesUndeploy(@Observes final BeforeUnDeploy beforeUnDeploy) { |
| final ClassLoaders loader = classLoader.get(); |
| if (loader != null) { // with multiple deployments order is not guaranteed so we reset it the hard way |
| setTCCL(loader.original); |
| } else { |
| final DeploymentContext deploymentContext = context.get(); |
| if (deploymentContext != null) { |
| setTCCL(deploymentContext.loader); |
| } |
| } |
| } |
| |
| public void observesTest(@Observes final EventContext<TestEvent> event) { |
| switchLoader(event); |
| } |
| |
| private void switchLoader(final EventContext<?> event) { |
| if (!SystemInstance.isInitialized()) { |
| event.proceed(); |
| return; |
| } |
| final BeanContext context = beanContext(); |
| ThreadContext oldCtx = null; |
| ClassLoader oldCl = null; |
| if (context != null) { |
| oldCtx = ThreadContext.enter(new ThreadContext(context, null)); |
| } else { |
| oldCl = Thread.currentThread().getContextClassLoader(); |
| final ClassLoaders classLoaders = classLoader.get(); |
| if (classLoaders != null) { |
| final ClassLoader loader = classLoaders.classloaders.size() == 1 /*assume it is the one we want*/ ? |
| classLoaders.classloaders.values().iterator().next() : oldCl /* we don't know the deployment so just passthrough */; |
| setTCCL(loader); |
| } |
| } |
| try { |
| event.proceed(); |
| } finally { |
| if (context != null) { |
| ThreadContext.exit(oldCtx); |
| } else { |
| setTCCL(oldCl); |
| } |
| } |
| } |
| |
| private void setTCCL(final ClassLoader cl) { |
| Thread.currentThread().setContextClassLoader(cl); |
| } |
| |
| public void release(@Observes final EventContext<BeforeUnDeploy> event) { |
| if (!SystemInstance.isInitialized()) { |
| event.proceed(); |
| return; |
| } |
| |
| try { |
| event.proceed(); |
| } finally { |
| final BeanContext bc = beanContext(); |
| if (bc != null) { // can be null if deployment exception |
| final CreationalContext<?> cc = bc.get(CreationalContext.class); |
| if (cc != null) { |
| cc.release(); |
| } |
| } |
| } |
| } |
| |
| private BeanContext beanContext() { |
| final TestClass tc = testClass.get(); |
| if (tc == null) { |
| return null; |
| } |
| |
| final String className = tc.getName(); |
| final ContainerSystem containerSystem = SystemInstance.get().getComponent(ContainerSystem.class); |
| for (final AppContext app : containerSystem.getAppContexts()) { |
| final BeanContext context = containerSystem.getBeanContext(app.getId() + "_" + className); |
| if (context != null) { |
| return context; |
| } |
| } |
| return null; |
| } |
| |
| public static class DeploymentContext { |
| private final ClassLoader loader; |
| |
| public DeploymentContext(final ClassLoader loader) { |
| this.loader = loader; |
| } |
| } |
| |
| public static class ClassLoaders { // to support multiple deployments otherwise we can lead a broken classloader |
| private final ClassLoader original = Thread.currentThread().getContextClassLoader(); // created once for multiple deployment so likely container one |
| private final Map<String, ClassLoader> classloaders = new HashMap<>(); |
| |
| public void register(final String name, final ClassLoader loader) { |
| classloaders.put(name, loader); |
| } |
| |
| public void unregister(final String name) { |
| classloaders.remove(name); |
| } |
| } |
| } |