/*******************************************************************************
 * The information in this document is proprietary to VeriSign and the VeriSign
 * Registry Business. It may not be used, reproduced, or disclosed without the
 * written approval of the General Manager of VeriSign Information Services.
 * 
 * PRIVILEGED AND CONFIDENTIAL VERISIGN PROPRIETARY INFORMATION (REGISTRY
 * SENSITIVE INFORMATION)
 * Copyright (c) 2006 VeriSign, Inc. All rights reserved.
 * **********************************************************
 */

// jgould -- Dec 2, 2015

package com.verisign.epp.pool.transformer;

import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerConfigurationException;
import javax.xml.transform.TransformerFactory;

import org.apache.commons.pool2.BaseObjectPool;
import org.apache.commons.pool2.BasePooledObjectFactory;
import org.apache.commons.pool2.PooledObject;
import org.apache.commons.pool2.impl.DefaultPooledObject;
import org.apache.commons.pool2.impl.SoftReferenceObjectPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.verisign.epp.util.EPPEnv;

/**
 * Singleton transformer pool class that initializes the transformer pool at
 * initialization, and provides a {@link #getPool()} to get the initialized
 * pool.
 */
public class EPPTransformerPool {

	/**
	 * Factory to use for {@link EPPTransformerPool}.
	 */
	private static class EPPTransformerPoolFactory extends BasePooledObjectFactory<Transformer> {

		/**
		 * Category for logging
		 */
		    private static Logger cat = LoggerFactory.getLogger(EPPTransformerPoolFactory.class);
		      

		/**
		 * Activating Transformer by being borrowed from the pool.
		 * 
		 * @param aTransformer
		 *           Transformer activating from the pool
		 */
		@Override
		public void activateObject(PooledObject<Transformer> aTransformer) throws Exception {
			cat.debug("Transformer activating from the pool: " + aTransformer);
			super.activateObject(aTransformer);
		}

		/**
		 * Destroying Transformer from the pool as the result of a validation
		 * error.
		 * 
		 * @param aTransformer
		 *           Transformer being destroyed from the pool
		 */
		@Override
		public void destroyObject(PooledObject<Transformer> aTransformer) throws Exception {
			cat.debug("Transformer being deleted from the pool: " + aTransformer);
			super.destroyObject(aTransformer);
		}

		/**
		 * Passivating Transformer in the pool.
		 * 
		 * @param aTransformer
		 *           Transformer being passivated in the pool
		 */
		@Override
		public void passivateObject(PooledObject<Transformer> aTransformer) throws Exception {
			cat.debug("Transformer being passivated in the pool: " + aTransformer);
			super.passivateObject(aTransformer);
		}

		/**
		 * Create instance of {@link Transformer}.
		 */
		@Override
		public Transformer create() throws Exception {
			TransformerFactory theTransformerFactory = TransformerFactory.newInstance();
			Transformer theTransformer = null;
			try {
				theTransformer = theTransformerFactory.newTransformer();
			}
			catch (TransformerConfigurationException e) {
				cat.error("EPPTransformerPoolFactory.create(): Couldn't instantiate transformer instance", e);
			}

			cat.debug("Transformer created for the pool: " + theTransformer);
			return theTransformer;
		}

		/**
		 * Wrap a {@link Transformer} in a {@link DefaultPooledObject}.
		 */
		@Override
		public PooledObject<Transformer> wrap(Transformer aTransformer) {
			return new DefaultPooledObject<Transformer>(aTransformer);
		}
	}

	/**
	 * Category for logging
	 */
	    private static Logger cat = LoggerFactory.getLogger(EPPTransformerPool.class);
	      

	/**
	 * Singleton instance
	 */
	private static EPPTransformerPool instance = new EPPTransformerPool();

	/**
	 * Contained transformer pool
	 */
	private SoftReferenceObjectPool<Transformer> pool = null;

	/**
	 * Singleton {@code getInstance} method for accessing the
	 * {@code EPPTransformerPool} instance.
	 * 
	 * @return {@code EPPTransformerPool} Singleton instance.
	 */
	public static EPPTransformerPool getInstance() {
		return instance;
	}

	/**
	 * Default constructor that will initialize the transformer pool.
	 */
	private EPPTransformerPool() {
		cat.info("EPPTransformerPool: initializing pool with " + EPPEnv.getTransformerPoolSize() + " transformers");

		this.pool = new SoftReferenceObjectPool<Transformer>(new EPPTransformerPoolFactory());

		try {
			this.pool.addObjects(EPPEnv.getTransformerPoolSize());
		}
		catch (Exception ex) {
			cat.error("EPPTransformerPool: Exception initializing the EPPTransformerPool: " + ex);
		}

		cat.info("EPPTransformerPool: pool initialized");
	}

	/**
	 * Gets the pool initialized by {@code EPPTransformerPool} for getting and
	 * returning transformer.
	 * 
	 * @return Transformer pool initialized by {@code EPPTransformerPool}.
	 */
	public BaseObjectPool<Transformer> getPool() {
		return this.pool;
	}

}
