/*
 *
 * The Seasar Software License, Version 1.1
 *
 * Copyright (c) 2003-2004 The Seasar Project. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or
 * without modification, are permitted provided that the following
 * conditions are met:
 *
 * 1. Redistributions of source code must retain the above
 *    copyrightnotice, this list of conditions and the following
 *    disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above
 *    copyright notice, this list of conditions and the following
 *    disclaimer in the documentation and/or other materials provided
 *    with the distribution.
 *
 * 3. The end-user documentation included with the redistribution,
 *    if any, must include the following acknowledgement:
 *    "This product includes software developed by the
 *    Seasar Project (http://www.seasar.org/)."
 *    Alternately, this acknowledgement may appear in the software
 *    itself, if and wherever such third-party acknowledgements
 *    normally appear.
 *
 * 4. Neither the names "The Seasar Project" nor　the name of its
 *    contributors ay be used to endour or promote products derived
 *    from this software without specific prior written permission of
 *    the Seasar Project.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR
 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIESOF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE SEASER　PROJECT
 * OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL,SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY,OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

package org.seasar.groovy;

import groovy.lang.GroovyShell;

import org.codehaus.groovy.control.CompilationFailedException;

import org.seasar.framework.container.S2Container;
import org.seasar.framework.container.factory.S2ContainerBuilder;
import org.seasar.framework.util.ResourceUtil;

import java.io.IOException;
import java.io.InputStream;


/**
 * Groovyスクリプトを読みこんでS2Containerを作成するファクトリークラス。
 * 読みこまれるGroovyスクリプトは、スクリプト内でS2Containerを作成し、 returnする必要がある。
 *
 * @author takai
 */
public class S2ContainerGroovyFactory
    implements S2ContainerBuilder
{
    protected S2ContainerGroovyFactory() {
    }

    /**
     * GroovyスクリプトからS2Containerを作成する。
     *
     * @param path 読みこむGroovyスクリプトのパス
     *
     * @return Groovyスクリプトによって作成されたS2Container
     *
     * @throws SeasarBuilderException Groovyスクリプトにエラーがあった場合に発生する
     */
    public static S2Container create(String path)
        throws SeasarBuilderException
    {
        return new S2ContainerGroovyFactory().build(path);
    }

    /**
     * @see org.seasar.framework.container.factory.S2ContainerBuilder#build(java.lang.String)
     */
    public S2Container build(String path)
        throws SeasarBuilderException
    {
        S2Container container = null;

        try {
            InputStream stream = ResourceUtil.getResourceAsStream(path);
            GroovyShell shell = new GroovyShell();
            container = (S2Container) shell.evaluate(stream, path);

            if (container == null) {
                throw new SeasarBuilderException("The return value is null or not returning.");
            }

            if (!(container instanceof S2Container)) {
                throw new SeasarBuilderException("The return value is not instance of S2Container");
            }
        } catch (CompilationFailedException e) {
            throw new SeasarBuilderException(e);
        } catch (IOException e) {
            throw new SeasarBuilderException(e);
        } catch (RuntimeException e) {
            throw new SeasarBuilderException(e);
        } catch (NoClassDefFoundError e) {
            throw new SeasarBuilderException(e);
        }

        return container;
    }

    /**
     * @see org.seasar.framework.container.factory.S2ContainerBuilder#build(java.lang.String,
     *      java.lang.ClassLoader)
     */
    public S2Container build(String path, ClassLoader classLoader)
        throws SeasarBuilderException
    {
        S2Container container = null;
        ClassLoader old = Thread.currentThread().getContextClassLoader();

        try {
            if (classLoader != null) {
                Thread.currentThread().setContextClassLoader(classLoader);
            }

            container = build(path);
        } finally {
            Thread.currentThread().setContextClassLoader(old);
        }

        return container;
    }


    /*
     * NOTE 仕様はこれで正しい？
	 * @see org.seasar.framework.container.factory.S2ContainerBuilder#include(org.seasar.framework.container.S2Container, java.lang.String)
	 */
	public S2Container include(S2Container parent, String path) {
		S2Container container = build(path);
		parent.include(container);
		
		return parent;
	}
}
