/* * JBoss, Home of Professional Open Source * Copyright 2014 Red Hat Inc. and/or its affiliates and other contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * Licensed 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.jboss.arquillian.core.impl.threading; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.Callable; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.Future; import org.jboss.arquillian.core.api.Injector; import org.jboss.arquillian.core.api.threading.ContextSnapshot; import org.jboss.arquillian.core.impl.ManagerImpl; import org.jboss.arquillian.core.spi.context.Context; import org.jboss.arquillian.core.spi.context.IdBoundContext; import org.jboss.arquillian.core.spi.context.NonIdBoundContext; public class ThreadedExecutorService implements org.jboss.arquillian.core.api.threading.ExecutorService { private ExecutorService service; private ManagerImpl manager; private Injector injector; public ThreadedExecutorService(final ManagerImpl manager) { this.manager = manager; try { this.injector = manager.executeInApplicationContext(new Callable<Injector>() { @Override public Injector call() throws Exception { return manager.resolve(Injector.class); } }); } catch (Exception e) { throw new RuntimeException(e); } } @Override public <T> Future<T> submit(Callable<T> task) { return executor().submit(wrap(injector.inject(task))); } @Override public ContextSnapshot createSnapshotContext() { return ContextualStateSnapshot.from(manager); } private ExecutorService executor() { if (this.service == null) { this.service = Executors.newCachedThreadPool(); } return this.service; } private <T> Callable<T> wrap(Callable<T> callable) { return new ContextualCallable<T>(callable, createSnapshotContext()); } private static class ContextualCallable<T> implements Callable<T> { private Callable<T> delegate; private ContextSnapshot state; public ContextualCallable(Callable<T> delegate, ContextSnapshot state) { this.delegate = delegate; this.state = state; } @Override public T call() throws Exception { try { state.activate(); return delegate.call(); } finally { state.deactivate(); } } } public static class ContextualStateSnapshot implements ContextSnapshot { private Map<Context, Object> activeContexts; private ContextualStateSnapshot(Map<Context, Object> activeContexts) { this.activeContexts = activeContexts; } @SuppressWarnings("unchecked") private static ContextSnapshot from(ManagerImpl manager) { List<Context> contexts = manager.getContexts(); Map<Context, Object> activeContexts = new HashMap<Context, Object>(); for (Context context : contexts) { if (context.isActive()) { if (context instanceof NonIdBoundContext) { activeContexts.put(context, null); } else { activeContexts.put(context, ((IdBoundContext<Object>) context).getActiveId()); } } } return new ContextualStateSnapshot(activeContexts); } @SuppressWarnings("unchecked") public void activate() { for (Map.Entry<Context, Object> entry : activeContexts.entrySet()) { if (entry.getKey() instanceof NonIdBoundContext) { ((NonIdBoundContext) entry.getKey()).activate(); } else if (entry.getKey() instanceof IdBoundContext) { ((IdBoundContext<Object>) entry.getKey()).activate(entry.getValue()); } } } @SuppressWarnings("unchecked") public void deactivate() { for (Map.Entry<Context, Object> entry : activeContexts.entrySet()) { if (entry.getKey() instanceof NonIdBoundContext) { ((NonIdBoundContext) entry.getKey()).deactivate(); } else if (entry.getKey() instanceof IdBoundContext) { ((IdBoundContext<Object>) entry.getKey()).deactivate(); } } } } }