/*
 * Copyright 2018 Scytl Secure Electronic Voting SA
 *
 * All rights reserved
 *
 * See our extended copyright notice in *file 'Copyright.txt' which is part of this source code package
 */
package com.scytl.cryptolib.commons.concurrent;

import java.lang.reflect.Proxy;

import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.impl.GenericObjectPoolConfig;

import com.scytl.cryptolib.api.services.ServiceFactory;

/**
 * Base class for pooled and proxied service factories. This class handles pool
 * and proxy creation.
 *
 * @param <T>
 *            Service type.
 */
public abstract class PooledProxiedServiceFactory<T> extends BaseFactory<T>
        implements ServiceFactory<T> {

    private final GenericObjectPoolConfig _poolConfig;

    private final BasePooledObjectFactory<T> _factory;

    /**
     * Constructor that configures the factory with the given factory of
     * services and the given pool configuration.
     *
     * @param factory
     *            the factory is any factory that creates service instances
     *            (specially non thread-safe).
     * @param poolConfig
     *            The configuration of the pool.
     */
    public PooledProxiedServiceFactory(final ServiceFactory<T> factory,
            final GenericObjectPoolConfig poolConfig) {
        super(factory.getCreatedObjectType());
        _poolConfig = poolConfig.clone();
        _factory = new BasePooledServiceFactory<T>(factory);
    }

    /**
     * Creates a Thread-safe service instance.
     */
    @Override
    public T create() {
        Class<T> type = getCreatedObjectType();
        Object proxy = Proxy.newProxyInstance(
            type.getClassLoader(),
            new Class<?>[] {type },
            new PooledProxiedServiceAPIInvocationHandler<T>(_factory,
                _poolConfig));
        return type.cast(proxy);
    }
}
