/*
 * The contents of this file are subject to the Mozilla Public License Version 1.1
 * (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.mozilla.org/MPL/>.
 * 
 * Software distributed under the License is distributed on an "AS IS" basis, WITHOUT
 * WARRANTY OF ANY KIND, either express or implied. See the License for the specific
 * language governing rights and limitations under the License.
 * 
 * The Original Code is the Venice Web Communities System.
 * 
 * The Initial Developer of the Original Code is Eric J. Bowersox <erbo@silcom.com>,
 * for Silverwrist Design Studios.  Portions created by Eric J. Bowersox are
 * Copyright (C) 2003 Eric J. Bowersox/Silverwrist Design Studios.  All Rights Reserved.
 * 
 * Contributor(s): 
 */
package com.silverwrist.dynamo.util;

import org.apache.log4j.Logger;
import org.w3c.dom.*;
import com.silverwrist.util.xml.*;
import com.silverwrist.dynamo.except.*;
import com.silverwrist.dynamo.iface.*;

public class LoaderUtils
{
  /*--------------------------------------------------------------------------------
   * Static data members
   *--------------------------------------------------------------------------------
   */

  private static Logger logger = Logger.getLogger(LoaderUtils.class);

  /*--------------------------------------------------------------------------------
   * Constructor
   *--------------------------------------------------------------------------------
   */

  public LoaderUtils()
  { // do nothing
  } // end constructor

  /*--------------------------------------------------------------------------------
   * External static operations
   *--------------------------------------------------------------------------------
   */

  public static final Object query(Class iface, Object obj)
  {
    if (iface.isInstance(obj))
      return obj;
    if (obj instanceof ServiceProvider)
    { // try querying it for the service
      try
      { // query the service
	return ((ServiceProvider)obj).queryService(iface);

      } // end try
      catch (NoSuchServiceException e)
      { // just fall out and return null
      } // end catch

    } // end if

    return null;

  } // end query

  public static final NamedObject loadObject(Element config, ServiceProvider services, Class extratest)
      throws ConfigException
  {
    XMLLoader loader = XMLLoader.get();
    String klassname = null;
    try
    { // get the class name for the object
      klassname = loader.getAttribute(config,"classname");
      if (logger.isDebugEnabled())
      { // output a proper debug message
	Class desired = (extratest==null) ? NamedObject.class : extratest;
	logger.debug("loadObject: Creating new NamedObject of class " + klassname + ", which should implement "
		     + desired.getName());

      } // end if

      // load the class
      Class klass = Class.forName(klassname);

      // make sure the class represents a valid Dynamo NamedObject
      if (!(NamedObject.class.isAssignableFrom(klass)))
      { // this object is not a valid NamedObject
	logger.error("object " + klassname + " does not implement NamedObject");
	ConfigException ce = new ConfigException(LoaderUtils.class,"LoaderMessages","no.notDynamo");
	ce.setParameter(0,klassname);
	throw ce;

      } // end if

      // make sure it implements the class we want, too
      if ((extratest!=null) && !(extratest.isAssignableFrom(klass)))
      { // this object is not a valid (whatever)
	logger.error("object " + klassname + " does not implement " + extratest.getName());
	ConfigException ce = new ConfigException(LoaderUtils.class,"LoaderMessages","no.notClass");
	ce.setParameter(0,klassname);
	ce.setParameter(1,extratest.getName());
	throw ce;

      } // end if

      // instantiate the object
      Object rc = klass.newInstance();

      // initialize the object
      ComponentInitialize init = (ComponentInitialize)query(ComponentInitialize.class,rc);
      if (init!=null)
	init.initialize(config,services);

      if (logger.isDebugEnabled())
	logger.debug("Object \"" + ((NamedObject)rc).getName() + "\" (of class " + klassname + ") created");

      return (NamedObject)rc;

    } // end try
    catch (XMLLoadException e)
    { // error getting class name - throw the ConfigException
      logger.error("XML loader failure",e);
      throw new ConfigException(e);

    } // end catch
    catch (ClassNotFoundException e)
    { // the class was not found
      ConfigException ce = new ConfigException(LoaderUtils.class,"LoaderMessages","no.classNotFound");
      ce.setParameter(0,klassname);
      throw ce;

    } // end catch
    catch (IllegalAccessException e)
    { // unable to create this object
      ConfigException ce = new ConfigException(LoaderUtils.class,"LoaderMessages","no.createError");
      ce.setParameter(0,klassname);
      throw ce;

    } // end catch
    catch (InstantiationException e)
    { // unable to create this object
      ConfigException ce = new ConfigException(LoaderUtils.class,"LoaderMessages","no.createError");
      ce.setParameter(0,klassname);
      throw ce;

    } // end catch

  } // end loadObject

} // end class LoaderUtils
