Package org.jboss.arquillian.drone.impl

Source Code of org.jboss.arquillian.drone.impl.DroneContextImpl$DronePair

/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat Middleware LLC, and individual 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.drone.impl;

import java.text.MessageFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.jboss.arquillian.core.api.Event;
import org.jboss.arquillian.core.api.Instance;
import org.jboss.arquillian.core.api.annotation.Inject;
import org.jboss.arquillian.core.api.threading.ExecutorService;
import org.jboss.arquillian.drone.spi.CachingCallable;
import org.jboss.arquillian.drone.spi.DroneConfiguration;
import org.jboss.arquillian.drone.spi.DroneContext;
import org.jboss.arquillian.drone.spi.Filter;
import org.jboss.arquillian.drone.spi.InjectionPoint;
import org.jboss.arquillian.drone.spi.event.AfterDroneInstantiated;
import org.jboss.arquillian.drone.spi.event.BeforeDroneInstantiated;

/**
* Default implementation of {@link DroneContext}
*
* @author <a href="mailto:kpiwko@redhat.com>Karel Piwko</a>
*/
public class DroneContextImpl implements DroneContext {
    private static final Logger LOGGER = Logger.getLogger(DroneContextImpl.class.getName());

    private final Map<InjectionPoint<?>, DronePair<?, ?>> dronePairMap;

    @Deprecated
    private DroneConfiguration<?> globalDroneConfiguration;

    @Inject
    private Instance<ExecutorService> executorService;

    @Inject
    private Event<BeforeDroneInstantiated> beforeDroneInstantiatedEvent;

    @Inject
    private Event<AfterDroneInstantiated> afterDroneInstantiatedEvent;

    public DroneContextImpl() {
        dronePairMap = new HashMap<InjectionPoint<?>, DronePair<?, ?>>();
    }

    @Override
    public <C extends DroneConfiguration<C>> C getGlobalDroneConfiguration(Class<C> configurationClass) {
        return (C) globalDroneConfiguration;
    }

    @Override
    public void setGlobalDroneConfiguration(DroneConfiguration<?> configuration) {
        globalDroneConfiguration = configuration;
    }

    @Override
    public <T> T getDrone(InjectionPoint<T> injectionPoint) throws IllegalStateException {
        DronePair<T, ?> pair = (DronePair<T, ?>) dronePairMap.get(injectionPoint);
        if (pair == null) {
            throw new IllegalArgumentException(MessageFormat.format("Injection point doesn''t exist: {0}", injectionPoint));
        }

        CachingCallable<T> droneCallable = pair.getDroneCallable();
        if (droneCallable == null) {
            throw new IllegalStateException(MessageFormat.format("Drone callable not stored yet for injection point " +
                "{0}!", injectionPoint));
        }

        boolean newInstance = !droneCallable.isValueCached();
        if (newInstance) {
            beforeDroneInstantiatedEvent.fire(new BeforeDroneInstantiated(injectionPoint));
        }

        T drone = instantiateDrone(droneCallable);

        if (newInstance) {
            afterDroneInstantiatedEvent.fire(new AfterDroneInstantiated(drone, injectionPoint));
        }

        CachingCallable<T> newDroneCallable = pair.getDroneCallable();

        if (newDroneCallable != droneCallable) {
            return getDrone(injectionPoint);
        } else {
            return drone;
        }
    }

    private <T> T instantiateDrone(CachingCallable<T> droneCallable) {
        // FIXME we need to make some kind of global drone configuration!

        int timeout = getGlobalDroneConfiguration(DroneLifecycleManager.GlobalDroneConfiguration.class)
            .getInstantiationTimeoutInSeconds();

        try {
            T drone;
            Future<T> futureDrone = executorService.get().submit(droneCallable);
            if (timeout > 0) {
                drone = futureDrone.get(timeout, TimeUnit.SECONDS);
            }
            // here we ignore the timeout, for instance if debugging is enabled
            else {
                drone = futureDrone.get();
            }
            return drone;
        } catch (InterruptedException e) {
            throw new RuntimeException("Unable to retrieve Drone Instance, thread interrupted", e);
        } catch (ExecutionException e) {
            // make exception a bit nicer
            Throwable cause = e.getCause();
            if (DroneTimeoutException.isCausedByTimeoutException(cause)) {
                throw new DroneTimeoutException(timeout, cause);
            }
            if (e.getCause() instanceof RuntimeException) {
                throw (RuntimeException) cause;
            }
            throw new RuntimeException(cause.getMessage(), cause);
        } catch (TimeoutException e) {
            throw new DroneTimeoutException(timeout, e);
        }
    }

    @Override
    public <C extends DroneConfiguration<C>> C getDroneConfiguration(InjectionPoint<?> injectionPoint, Class<C>
        configurationClass) throws IllegalArgumentException {
        DronePair<?, C> pair = (DronePair<?, C>) dronePairMap.get(injectionPoint);
        if (pair == null) {
            throw new IllegalArgumentException(MessageFormat.format("Injection point doesn''t exist: {0}",
                injectionPoint));
        }

        C configuration = pair.getConfiguration();
        if (configuration == null) {
            throw new IllegalStateException(MessageFormat.format("Drone configuration not stored yet! Injection " +
                "point: {0}", injectionPoint));
        }

        return configuration;
    }

    @Override
    public <T> void storeFutureDrone(InjectionPoint<T> injectionPoint, CachingCallable<T> drone) {
        DronePair<T, ?> pair = (DronePair<T, ?>) dronePairMap.get(injectionPoint);
        if (pair == null) {
            throw new IllegalArgumentException(MessageFormat.format("Injection point doesn''t exist: {0}",
                injectionPoint));
        }

        if (pair.getDroneCallable() != null) {
            LOGGER.log(Level.FINE, "Future drone replaced at point {0}", injectionPoint);
        }

        pair.setDroneCallable(drone);
    }

    @Override
    public <T, C extends DroneConfiguration<C>> void storeDroneConfiguration(InjectionPoint<T> injectionPoint,
        C configuration) {
        DronePair<T, C> pair = (DronePair<T, C>) dronePairMap.get(injectionPoint);
        if (pair != null) {
            // FIXME shouldn't we just handle this peacefully with warning?
            throw new IllegalStateException(MessageFormat.format("Injection point already exists: {0}",
                injectionPoint));
        }

        pair = new DronePair<T, C>();
        pair.setConfiguration(configuration);
        dronePairMap.put(injectionPoint, pair);
    }

    @Override
    public <T> boolean isDroneInstantiated(InjectionPoint<T> injectionPoint) {
        DronePair<T, ?> dronePair = (DronePair<T, ?>) dronePairMap.get(injectionPoint);
        if (dronePair == null) {
            return false;
        }
        if (dronePair.getDroneCallable() == null) {
            return false;
        }
        return dronePair.getDroneCallable().isValueCached();
    }

    @Override
    public <T> boolean isFutureDroneStored(InjectionPoint<T> injectionPoint) {
        DronePair<T, ?> dronePair = (DronePair<T, ?>) dronePairMap.get(injectionPoint);
        if (dronePair == null) {
            return false;
        }
        return dronePair.getDroneCallable() != null;
    }

    @Override
    public <T> boolean isDroneConfigurationStored(InjectionPoint<T> injectionPoint) {
        DronePair<T, ?> dronePair = (DronePair<T, ?>) dronePairMap.get(injectionPoint);
        if (dronePair == null) {
            return false;
        }
        return dronePair.getConfiguration() != null;
    }

    @Override
    public void removeDrone(InjectionPoint<?> injectionPoint) {
        DronePair<?, ?> pair = dronePairMap.get(injectionPoint);
        if (pair == null) {
            LOGGER.log(Level.WARNING, "Couldn''t remove Drone, because it wasn''t prepared! Injection point: {0}",
                injectionPoint);
            return;
        }
        if (pair.getDroneCallable() == null) {
            LOGGER.log(Level.WARNING, "Couldn''t remove Drone, because it wasn''t set! Injection point: {0}",
                injectionPoint);
        }

        pair.setDroneCallable(null);
    }

    @Override
    public void removeDroneConfiguration(InjectionPoint<?> injectionPoint) {
        DronePair<?, ?> pair = dronePairMap.get(injectionPoint);
        if (pair == null) {
            LOGGER.log(Level.WARNING, "Couldn''t remove configuration, because the injection point wasn''t prepared. " +
                "Injection point: {0}", injectionPoint);
            return;
        }
        if (pair.getDroneCallable() != null) {
            LOGGER.log(Level.WARNING, "Drone is still set, but you won''t be able to access it anymore! Injection " +
                "point: {0}", injectionPoint);
        }
        if (pair.getConfiguration() == null) {
            LOGGER.log(Level.WARNING, "Couldn''t remove configuration, because it wasn''t set! Injection point: {0}",
                injectionPoint);
        }

        pair.setConfiguration(null);

        dronePairMap.remove(injectionPoint);
    }

    @Override
    public void removeDrones(List<InjectionPoint<?>> injectionPoints) {
        for (InjectionPoint<?> injectionPoint : injectionPoints) {
            removeDrone(injectionPoint);
        }
    }

    @Override
    public void removeDroneConfigurations(List<InjectionPoint<?>> injectionPoints) {
        for (InjectionPoint<?> injectionPoint : injectionPoints) {
            removeDroneConfiguration(injectionPoint);
        }
    }

    @Override
    public <T> InjectionPoint<? extends T> findSingle(Class<T> droneClass,
        Filter... filters) throws IllegalStateException {
        List<InjectionPoint<? extends T>> injectionPoints = find(droneClass, filters);
        int count = injectionPoints.size();
        if (count != 1) {
            throw new IllegalStateException("Total injection points matched not equal to 1! Actual: " + count);
        }
        return injectionPoints.get(0);
    }

    @Override
    public <T> List<InjectionPoint<? extends T>> find(Class<T> droneClass, Filter... filters) {
        List<InjectionPoint<? extends T>> matchedInjectionPoints = new ArrayList<InjectionPoint<? extends T>>();

        for (InjectionPoint<?> injectionPoint : dronePairMap.keySet()) {
            if (!droneClass.isAssignableFrom(injectionPoint.getDroneType())) {
                continue;
            }
            @SuppressWarnings("unchecked")
            InjectionPoint<? extends T> castInjectionPoint = (InjectionPoint<? extends T>) injectionPoint;

            boolean matches = true;

            for (Filter filter : filters) {
                if (!filter.accept(castInjectionPoint)) {
                    matches = false;
                    break;
                }
            }

            if (matches) {
                matchedInjectionPoints.add(castInjectionPoint);
            }
        }

        return matchedInjectionPoints;
    }

    private class DronePair<T, C extends DroneConfiguration<C>> {
        private CachingCallable<T> droneCallable;
        private C configuration;

        public CachingCallable<T> getDroneCallable() {
            return droneCallable;
        }

        public void setDroneCallable(CachingCallable<T> droneCallable) {
            this.droneCallable = droneCallable;
        }

        public C getConfiguration() {
            return configuration;
        }

        public void setConfiguration(C configuration) {
            this.configuration = configuration;
        }
    }
}
TOP

Related Classes of org.jboss.arquillian.drone.impl.DroneContextImpl$DronePair

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.