| /* |
| * 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.jboss.arquillian.container.spi.client.protocol.metadata.HTTPContext; |
| import org.jboss.arquillian.container.spi.client.protocol.metadata.ProtocolMetaData; |
| import org.jboss.arquillian.core.api.Instance; |
| import org.jboss.arquillian.core.api.InstanceProducer; |
| import org.jboss.arquillian.core.api.annotation.ApplicationScoped; |
| import org.jboss.arquillian.core.api.annotation.Inject; |
| import org.jboss.arquillian.core.api.annotation.Observes; |
| import org.jboss.arquillian.test.spi.event.enrichment.BeforeEnrichment; |
| |
| import javax.naming.Context; |
| import javax.naming.InitialContext; |
| import javax.naming.NamingException; |
| import java.lang.reflect.InvocationHandler; |
| import java.lang.reflect.InvocationTargetException; |
| import java.lang.reflect.Method; |
| import java.lang.reflect.Proxy; |
| import java.util.Arrays; |
| import java.util.Properties; |
| import java.util.concurrent.Callable; |
| |
| public class RemoteInitialContextObserver { |
| private static final String REMOTE_INITIAL_CONTEXT_FACTORY = "org.apache.openejb.client.RemoteInitialContextFactory"; |
| |
| @Inject |
| @ApplicationScoped |
| private InstanceProducer<Context> context; |
| |
| @Inject |
| private Instance<Context> existingContext; |
| |
| @Inject |
| private Instance<ProtocolMetaData> protocolMetadata; |
| |
| public void beforeSuite(@Observes final BeforeEnrichment event) { |
| final ProtocolMetaData metaData = protocolMetadata.get(); |
| if(metaData == null || !metaData.hasContext(HTTPContext.class)) { |
| return; |
| } |
| |
| try { |
| Thread.currentThread().getContextClassLoader().loadClass(REMOTE_INITIAL_CONTEXT_FACTORY); |
| |
| final HTTPContext httpContext = metaData.getContexts(HTTPContext.class).iterator().next(); |
| final Properties props = new Properties(); |
| props.setProperty(Context.INITIAL_CONTEXT_FACTORY, REMOTE_INITIAL_CONTEXT_FACTORY); |
| props.setProperty(Context.PROVIDER_URL, "http://" + httpContext.getHost() + ":" + httpContext.getPort() + "/tomee/ejb"); |
| |
| Context existing = null; |
| try { |
| existing = existingContext.get(); |
| } catch (final Throwable t) { |
| // no-op |
| } |
| |
| final Context proxyInstance = (Context) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), new Class<?>[]{Context.class}, new MultipleContextHandler(props, existing)); |
| context.set(new InitialContextWrapper(proxyInstance)); // cause ContextProducer of arquillian supports InitialContext |
| } catch (final ClassNotFoundException | NamingException e) { |
| // no-op |
| } |
| } |
| |
| private static class MultipleContextHandler implements InvocationHandler { |
| private final Context context; |
| private final Properties properties; |
| |
| public MultipleContextHandler(final Properties props, final Context initialContexts) { |
| properties = props; |
| context = initialContexts; |
| } |
| |
| @Override |
| public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable { |
| Exception err = null; |
| for (final Callable<Context> callable : Arrays.asList( // order is important to avoid to start an embedded container for some cases |
| new Callable<Context>() { // then try to create a remote context |
| @Override |
| public Context call() throws Exception { |
| return new InitialContext(properties); |
| } |
| }, |
| new Callable<Context>() { // then existing context |
| @Override |
| public Context call() throws Exception { |
| return context; |
| } |
| }, |
| new Callable<Context>() { // then contextual context, this can start an embedded container in some cases |
| @Override |
| public Context call() throws Exception { |
| return new InitialContext(); |
| } |
| } |
| |
| )) { |
| |
| try { |
| final Context ctx = callable.call(); |
| if (ctx == null) { |
| continue; |
| } |
| return method.invoke(ctx, args); |
| } catch (final Exception e) { |
| err = e; |
| } |
| } |
| |
| if (err != null) { |
| if (InvocationTargetException.class.isInstance(err)) { |
| throw err.getCause(); |
| } |
| throw err; |
| } |
| |
| return null; |
| } |
| } |
| |
| private static class InitialContextWrapper extends InitialContext { |
| private final Context delegate; |
| |
| public InitialContextWrapper(final Context proxyInstance) throws NamingException { |
| super(true); |
| this.delegate = proxyInstance; |
| } |
| |
| @Override |
| protected Context getURLOrDefaultInitCtx(final String name) { |
| return delegate; |
| } |
| } |
| } |