package com.eactive.eai.common.util; 

import java.util.Collections;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;

import javax.jms.Queue;
import javax.jms.QueueConnectionFactory;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.sql.DataSource;

import com.eactive.eai.common.exception.ExceptionUtil;

/** 
 * 1. 기능 : WAS의 각종 서비스를 레퍼런스를 얻어내는 공통 Class
 * 2. 처리 개요 : 
 * *     - 
 * 3. 주의사항 
 *
 * @author  : 
 * @version : v 1.0.0
 * @see : 관련 기능을 참조
 * @since   : 
 *  : 
 */
public class ServiceLocator { 
	/** Eai Logger */
//    static private Logger logger = Logger.getLogger(Logger.LOGGER_DEFAULT);
	/** weblogic.jndi.WLInitialContextFactory */
    public final static String WEBLOGIC_INITIAL_CONTEXT_FACTORY = "weblogic.jndi.WLInitialContextFactory";
    
    /** ServiceLocator singleton object */
    private static ServiceLocator instance;
    
    /** JNDI Context object */
    private InitialContext initial;
    
    /**	caching을 위한 collection object */
    private Map<String, Object> cache; 
    
    /**
     *	EaiMain start시 t3 url 초기화를 위해 호출된다<br>
     *	t3 url을 초기화하고, ServiceLocator singleton object를 생성 초기화한다.
     */
    /*
    static public void init(String t3Url) {
        try {
            //WEBLOGIC_T3_URL = t3Url;
            instance = new ServiceLocator();
            if (logger.isInfo()) logger.info("ServiceLocator#init() initailized...");
        } catch (ServiceLocatorException e) {
            if (logger.isError()) logger.error("!! Cannot connect to WebLogic Server...");
            if (logger.isError()) logger.error("1. Check if WebLogic Server is alive.");
            if (logger.isError()) logger.error("2. Check if t3Url is correct in config file(server.xml).");
            if (logger.isError()) logger.error(e.getMessage(), e);
            //System.exit(1);
        }
    }
	*/
	
	/** 
     * 1. 기능 : Constructor
     * 2. 처리 개요 : 
     *     - JNDI Context object를 생성 초기화하고, cache Map object를 생성 초기화한다.
     * 3. 주의사항 
     *
     * @exception ServiceLocatorException
     **/	
    protected ServiceLocator() throws ServiceLocatorException {
        try {
			/*
        	Hashtable env = new Hashtable(); 
          	env.put(Context.INITIAL_CONTEXT_FACTORY, WEBLOGIC_INITIAL_CONTEXT_FACTORY);
          	env.put(Context.PROVIDER_URL, WEBLOGIC_T3_URL); 
            initial = new InitialContext(env);
			*/
			initial = new InitialContext();

			cache = Collections.synchronizedMap(new HashMap<String, Object>());
			
        } catch (NamingException e) {
//            throw new ServiceLocatorException(e);
		throw new ServiceLocatorException(ExceptionUtil.getErrorCode(e,"RECEAICUL101"));
        } catch (Exception e) {
 //           throw new ServiceLocatorException(e);
            throw new ServiceLocatorException(ExceptionUtil.getErrorCode(e,"RECEAICUL102"));
        }
    }
	
	/** 
     * 1. 기능 : ServiceLocator object를 반환하는 factory method
     * 2. 처리 개요 : 
     *     - ServiceLocator object를 반환하는 factory method
     * 3. 주의사항 
     *
     * @return ServiceLocator
     * @exception
     **/
    public static synchronized ServiceLocator getInstance() throws ServiceLocatorException {
		if ( instance == null ) {
			instance = new ServiceLocator();
			return instance;
		} else {
			return instance;
		}
    }
	
	/** 
     * 1. 기능 : 파라미터 name에 해당하는 DataSource를 lookup해 반환하는 method
     * 2. 처리 개요 : 
     *     - 파라미터 name에 해당하는 DataSource를 lookup해 반환하는 method
     * 3. 주의사항 
     *
     *	@param	dataSourceName	DataSource의 JNDI name
     *	@return	DataSource	JDBC DataSource object
     *	@exception	ServiceLocatorException
     **/
    public DataSource getDataSource(String dataSourceName)
                             throws ServiceLocatorException {
        DataSource dataSource = null;

        try {
            if (cache.containsKey(dataSourceName)) {
                dataSource = (DataSource) cache.get(dataSourceName);
            } else {
                dataSource = (DataSource) initial.lookup(dataSourceName);
                cache.put(dataSourceName,dataSource);
                // already made connection pool
                //throw new ServiceLocatorException("DataSource Name [" + dataSourceName + "] does not exist.");
            }
        } catch (Exception e) {
 //           throw new ServiceLocatorException(e);
            throw new ServiceLocatorException(ExceptionUtil.getErrorCode(e,"RECEAICUL103"));
        }

        return dataSource;
    }
    
    public void putDataSource(String dataSourceName, DataSource dataSource) {
    	cache.put(dataSourceName, dataSource);
	}
    /** 
     * 1. 기능 : 파라미터 name에 해당하는 Remote 서버의 DataSource를 lookup해 반환하는 method
     * 2. 처리 개요 : 
     *     - 파라미터 name에 해당하는 Remote 서버의 DataSource를 lookup해 반환하는 method
     * 3. 주의사항 
     *
     *	@param	providerUrl	Remote URI
     *	@param	dataSourceName	DataSource의 JNDI name
     *	@return	DataSource	JDBC DataSource object
     *	@exception	ServiceLocatorException
     **/
    public DataSource getRemoteDataSource(String providerUrl, String dataSourceName) {
        DataSource dataSource = null;
        
        try {
            if (cache.containsKey(dataSourceName)) {
                dataSource = (DataSource) cache.get(dataSourceName);
            } else {       	
                Hashtable<String, Object> env = new Hashtable<String, Object>(); 
                env.put(Context.INITIAL_CONTEXT_FACTORY, WEBLOGIC_INITIAL_CONTEXT_FACTORY);
                env.put(Context.PROVIDER_URL, providerUrl); 
                initial = new InitialContext(env);
                
                dataSource = (DataSource)initial.lookup(dataSourceName);
                
                cache.put(dataSourceName,dataSource);
            }
            return dataSource;
        } catch (Exception e) {
 //           throw new RuntimeException(e);
            throw new RuntimeException(ExceptionUtil.getErrorCode(e,"RECEAICUL104"));
        }  
    }   
	/** 
     * 1. 기능 : QueueConnectionFactory를 반환하는 method
     * 2. 처리 개요 : 
     *     - QueueConnectionFactory를 반환하는 method
     * 3. 주의사항 
     *
	 *	@param	qConnFactoryName	QueueConnectionFactory의 JNDI name
	 *	@return QueueConnectionFactory object
	 *	@exception	ServiceLocatorException
	 */
    public QueueConnectionFactory getQueueConnectionFactory(String qConnFactoryName)
        throws ServiceLocatorException {
        QueueConnectionFactory factory = null;

        try {
            if (cache.containsKey(qConnFactoryName)) {
                factory = (QueueConnectionFactory) cache.get(qConnFactoryName);
            } else {
//                factory = (QueueConnectionFactory) initial.lookup(qConnFactoryName);
//                cache.put(qConnFactoryName, factory);
            	
            	Hashtable<String, Object> env = new Hashtable<>();
            	env.put(Context.INITIAL_CONTEXT_FACTORY, WEBLOGIC_INITIAL_CONTEXT_FACTORY);

            	// Admin Server 포트를 사용하는 것이 안전
            	env.put(Context.PROVIDER_URL, "t3://192.168.240.176:8001");

            	InitialContext initial = new InitialContext(env);

            	factory =
            	    (QueueConnectionFactory) initial.lookup(qConnFactoryName);
            	cache.put(qConnFactoryName, factory);
            }
        } catch (NamingException ne) {
            //throw new ServiceLocatorException(ne);
            throw new ServiceLocatorException(ExceptionUtil.getErrorCode(ne,"RECEAICUL113"));
        } catch (Exception e) {
            //throw new ServiceLocatorException(e);
            throw new ServiceLocatorException(ExceptionUtil.getErrorCode(e,"RECEAICUL114"));
        }

        return factory;
    }

	/** 
     * 1. 기능 : Queue를 반환하는 method
     * 2. 처리 개요 : 
     *     - Queue를 반환하는 method
     * 3. 주의사항 
     *
	 *	@param	queueName	Queue의 JNDI name
	 *	@return	Queue object
	 *	@exception	ServiceLocatorException
	 */
    public Queue getQueue(String queueName) throws ServiceLocatorException {
        Queue queue = null;

        try {
            if (cache.containsKey(queueName)) {
                queue = (Queue) cache.get(queueName);
            } else {
                queue = (Queue) initial.lookup(queueName);
                cache.put(queueName, queue);
            }
        } catch (NamingException ne) {
            //throw new ServiceLocatorException(ne);
            throw new ServiceLocatorException(ExceptionUtil.getErrorCode(ne,"RECEAICUL115"));
        } catch (Exception e) {
            //throw new ServiceLocatorException(e);
            throw new ServiceLocatorException(ExceptionUtil.getErrorCode(e,"RECEAICUL116"));
        }

        return queue;
    }


} 
