/*
 * This software is distributed under following license based on modified BSD
 * style license.
 * ----------------------------------------------------------------------
 * 
 * Copyright 2009 The Nimbus2 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 copyright notice,
 *    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.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE NIMBUS PROJECT ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN
 * NO EVENT SHALL THE NIMBUS PROJECT OR 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.
 * 
 * The views and conclusions contained in the software and documentation are
 * those of the authors and should not be interpreted as representing official
 * policies, either expressed or implied, of the Nimbus2 Project.
 */
package jp.ossc.nimbus.service.aop.interceptor;

import java.lang.reflect.InvocationTargetException;
import java.util.Locale;

import jp.ossc.nimbus.core.*;
import jp.ossc.nimbus.service.aop.*;

/**
 * 例外インターセプタ。<p>
 * メソッドの呼び出しに対して、何もせずに例外を返すインターセプタである。<br>
 * 以下に、UnsupportedOperationExceptionをthrowするインターセプタのサービス定義例を示す。<br>
 * <pre>
 * &lt;?xml version="1.0" encoding="Shift_JIS"?&gt;
 * 
 * &lt;nimbus&gt;
 *     
 *     &lt;manager name="Sample"&gt;
 *         
 *         &lt;service name="UnsupportedOperationExceptionTrowInterceptor"
 *                  code="jp.ossc.nimbus.service.aop.interceptor.ExceptionThrowInterceptorService"&gt;
 *             &lt;attribute name="ThrowableClass"&gt;java.lang.UnsupportedOperationException&lt;/attribute&gt;
 *             &lt;attribute name="ThrowableMessage"&gt;このメソッドは呼び出してはいけません。&lt;/attribute&gt;
 *         &lt;/service&gt;
 *         
 *     &lt;/manager&gt;
 *     
 * &lt;/nimbus&gt;
 * </pre>
 * 
 * @author M.Takata
 */
public class ExceptionThrowInterceptorService extends ServiceBase
 implements Interceptor, ExceptionThrowInterceptorServiceMBean, ExceptionThrow{
    
    private static final long serialVersionUID = -7750833087537700407L;
    
    private Throwable throwable;
    private Class<?> throwableClass;
    private String throwableMessage;
    private String throwableMessageKey;
    private Locale throwableMessageLocale;
    private Object[] throwableMessageArgs;
    private boolean isEnabled = true;
    
    // ExceptionThrowInterceptorServiceMBeanのJavaDoc
    public void setEnabled(boolean enabled){
        isEnabled = enabled;
    }
    
    // ExceptionThrowInterceptorServiceMBeanのJavaDoc
    public boolean isEnabled(){
        return isEnabled;
    }
    public void setThrowable(Throwable th){
        this.throwable = th;
    }
    public Throwable getThrowable(){
        return throwable;
    }
    
    public void setThrowableClass(Class<?> clazz){
        this.throwableClass = clazz;
    }
    public Class<?> getThrowableClass(){
        return throwableClass;
    }
    
    public void setThrowableMessage(String message){
        this.throwableMessage = message;
    }
    public String getThrowableMessage(){
        return throwableMessage;
    }
    
    public void setThrowableMessageKey(String key){
        this.throwableMessageKey = key;
    }
    public String getThrowableMessageKey(){
        return throwableMessageKey;
    }
    
    public void setThrowableMessageLocale(Locale locale){
        this.throwableMessageLocale = locale;
    }
    public Locale getThrowableMessageLocale(){
        return throwableMessageLocale;
    }
    
    public void setThrowableMessageArgs(Object[] args){
        this.throwableMessageArgs = args;
    }
    public Object[] getThrowableMessageArgs(){
        return throwableMessageArgs;
    }
    
    /**
     * サービスの開始処理を行う。<p>
     *
     * @exception Exception 指定された例外が生成できない場合
     */
    public void startService() throws Exception{
        if(createThrowable() == null){
            throw new IllegalArgumentException("Throwable is null.");
        }
    }
    
    
    protected Throwable createThrowable(){
        if(getThrowable() != null){
            return getThrowable();
        }
        if(getThrowableClass() == null){
            return null;
        }
        Throwable ret = null;
        if(getThrowableMessage() == null && getThrowableMessageKey() == null){
            try{
                ret = (Throwable)getThrowableClass().newInstance();
            }catch(InstantiationException e){
            }catch(IllegalAccessException e){
            }
        }else{
            String msg = getThrowableMessage();
            if(getThrowableMessageKey() != null){
                msg = getMessageRecordFactory().findMessage(
                    getThrowableMessageKey(),
                    getThrowableMessageLocale(),
                    getThrowableMessageArgs()
                );
            }
            try{
                ret = (Throwable)getThrowableClass()
                    .getConstructor(String.class).newInstance(msg);
            }catch(IllegalArgumentException e){
            }catch(SecurityException e){
            }catch(InstantiationException e){
            }catch(IllegalAccessException e){
            }catch(InvocationTargetException e){
            }catch(NoSuchMethodException e){
            }
        }
        return ret;
    }
    
    /**
     * 設定された例外をthrowする。<p>
     * サービスが開始されていない場合は、設定された例外はthrowせずに、次のインターセプタを呼び出す。
     *
     * @param context 呼び出しのコンテキスト情報
     * @param chain 次のインターセプタを呼び出すためのチェーン
     * @return 呼び出し結果の戻り値
     * @exception Throwable 設定された例外
     */
    public Object invoke(
        InvocationContext context,
        InterceptorChain chain
    ) throws Throwable{
        if(getState() == State.STARTED && isEnabled){
            throw createThrowable();
        }else{
            return chain.invokeNext(context);
        }
    }
}
