/*
* 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;
public class TestObserver {
@Inject
private Instance<ClassLoader> 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()));
final ClassLoader loader = classLoader.get();
if (loader != null) {
setTCCL(loader);
}
}
public void observesUndeploy(@Observes final BeforeUnDeploy beforeUnDeploy) {
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();
if (classLoader.get() != null) {
setTCCL(classLoader.get());
}
}
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;
}
}
}