/*******************************************************************************
 * Copyright © 2004 VHA. All rights reserved
 ******************************************************************************/

// Package
package gov.va.med.fw.service;

// Spring classes
import org.apache.commons.lang.Validate;
import org.apache.commons.logging.Log;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ApplicationObjectSupport;

import gov.va.med.fw.util.ExceptionHandler;
import gov.va.med.fw.util.ExceptionHandlerFactory;

/**
 * An abstract component that provides access to a bean factory and a resource
 * manager to load up resources. This class is marked as as abstract class to
 * force a derived class to provide specific functionalities
 * 
 * @author Vu Le
 * @version 1.0
 */
public abstract class AbstractComponent extends ApplicationObjectSupport implements BeanNameAware,
		InitializingBean {

	/** A unique name idetifying this component its life cycle */
	private String name = null;

	/** Creates a new instance of AbstractComponent */
	protected AbstractComponent() {
		super();
	}

	protected Log getLogger() {
		return logger; // logger is instantiated by the ApplicationObjectSupport
	}

	/**
	 * Sets a component name
	 * 
	 * @param name
	 *            A component name
	 */
	public void setBeanName(String name) {
		this.name = name;
	}

	/**
	 * Returns a name identifying this component in a container
	 * 
	 * @return A bean's name.
	 */
	public String getBeanName() {
		return name;
	}

	/**
	 * Returns a generic component managed by an application context
	 * 
	 * @param name
	 *            A component name
	 * @return A generic component managed by an application context
	 */
	public Object getComponent(String name) throws ServiceException {

		Object component = null;
		try {
			ApplicationContext context = getApplicationContext();
			component = context.getBean(name);
		} catch (BeansException e) {
			// Failed to get a component
			throw new ServiceException("Failed to get a component by name " + name, e);
		}
		return component;
	}

	/**
	 * Returns a specific component managed by an application context
	 * 
	 * @param name
	 *            A component name
	 * @param type
	 *            A component name's type
	 * @return A specific component managed by an application context
	 */
	public Object getComponent(String name, Class type) throws ServiceException {

		Object component = null;
		try {
			ApplicationContext context = getApplicationContext();
			component = context.getBean(name, type);
		} catch (BeansException e) {
			// Failed to get a component
			throw new ServiceException("Failed to get a component by name " + name + " and type "
					+ type, e);
		}
		return component;
	}

	protected Throwable processException(Exception e, Object obj) {

		Throwable handled = e;
		try {
			ExceptionHandlerFactory factory = (ExceptionHandlerFactory) getComponent(ExceptionHandlerFactory.class
					.getName());
			ExceptionHandler handler = factory.getExceptionHandler(e.getClass().getName());
			handled = handler.handleException(e, e.getMessage(), obj);
		} catch (Exception exception) {
			if (logger.isDebugEnabled()) {
				logger.debug("failed to find an exeption handler to handle exception "
						+ exception.getClass().getName());
				logger.trace(this, exception);
			}
		}
		return handled;
	}

	/**
	 * Deallocate and dereference resources
	 */
	protected void finalize() throws Throwable {
		name = null;
	}

	public void afterPropertiesSet() throws Exception {
		Validate.notNull(this.name, "A bean name must not be null");
	}
}
