/*
 * 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.beanflow;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.Map;
import java.util.HashMap;
import java.beans.PropertyEditor;
import java.io.File;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;

import jp.ossc.nimbus.beans.NimbusPropertyEditorManager;
import jp.ossc.nimbus.core.DeploymentException;
import jp.ossc.nimbus.core.ServiceManager;
import jp.ossc.nimbus.core.ServiceName;
import jp.ossc.nimbus.core.ServiceBase;
import jp.ossc.nimbus.core.ServiceManagerFactory;
import jp.ossc.nimbus.core.ServiceMetaData;
import jp.ossc.nimbus.core.ServiceLoader;
import jp.ossc.nimbus.core.NimbusClassLoader;
import jp.ossc.nimbus.core.NimbusEntityResolver;
import jp.ossc.nimbus.core.ServiceNotFoundException;
import jp.ossc.nimbus.core.Utility;
import jp.ossc.nimbus.io.RecursiveFile;
import jp.ossc.nimbus.io.ExtentionFileFilter;
import jp.ossc.nimbus.service.context.Context;
import jp.ossc.nimbus.service.aop.InterceptorChain;
import jp.ossc.nimbus.service.aop.InterceptorChainFactory;
import jp.ossc.nimbus.service.aop.InvocationContext;
import jp.ossc.nimbus.service.aop.DefaultMethodInvocationContext;
import jp.ossc.nimbus.service.journal.Journal;
import jp.ossc.nimbus.service.journal.EditorFinder;
import jp.ossc.nimbus.service.transaction.JndiTransactionManagerFactoryService;
import jp.ossc.nimbus.service.transaction.TransactionManagerFactory;
import jp.ossc.nimbus.service.interpreter.Interpreter;
import jp.ossc.nimbus.service.queue.QueueHandlerContainer;
import jp.ossc.nimbus.service.queue.QueueHandler;

/**
 * デフォルト{@link BeanFlowFactory}サービス。<p>
 * 
 * @author M.Takata
 */
public class DefaultBeanFlowFactoryService extends ServiceBase
 implements BeanFlowFactory, DefaultBeanFlowFactoryServiceMBean{

    static{
        NimbusEntityResolver.registerEntity(
            "-//Nimbus//DTD Nimbus Bean Flow 2.0//JA",
            "jp/ossc/nimbus/service/beanflow/beanflow_2_0.dtd"
        );
    }
    
    private static final long serialVersionUID = -5990513635942145807L;
    
    private static final String INVOKE_FLOW_METHOD_NAME = "execute";
    private static final Class<?>[] INVOKE_FLOW_METHOD_PARAM = new Class[]{Object.class, BeanFlowMonitor.class};
    
    protected String[] flowDirs;
    protected String[] flowPaths;
    
    protected String documentBuilderFactoryClassName;
    protected boolean isValidate;
    
    protected ServiceName contextServiceName;
    protected Context<Object, Object> context;
    
    protected ServiceName interceptorChainFactoryServiceName;
    protected InterceptorChainFactory interceptorChainFactory;
    
    protected ServiceName journalServiceName;
    protected Journal journal;
    
    protected ServiceName editorFinderServiceName;
    protected EditorFinder editorFinder;
    
    protected ServiceName expressionInterpreterServiceName;
    protected Interpreter expressionInterpreter;
    
    protected ServiceName testInterpreterServiceName;
    protected Interpreter testInterpreter;
    
    protected ServiceName interpreterServiceName;
    protected Interpreter interpreter;
    
    protected ServiceName transactionManagerFactoryServiceName;
    protected TransactionManagerFactory transactionManagerFactory;
    
    protected ServiceName asynchExecuteQueueHandlerContainerServiceName;
    protected QueueHandlerContainer<BeanFlowAsynchContext> asynchExecuteQueueHandlerContainer;
    
    protected Map<String, BeanFlow> flowMap;
    protected Map<String, BeanFlow> aliasMap;
    
    protected String asynchExecuteErrorLogMessageId;
    protected String asynchExecuteRetryOverErrorLogMessageId;
    
    public void setFlowDirs(String[] dirs){
        flowDirs = dirs;
    }
    public String[] getFlowDirs(){
        return flowDirs;
    }
    
    public void setFlowPaths(String[] paths){
        flowPaths = paths;
    }
    public String[] getFlowPaths(){
        return flowPaths;
    }
    
    public void setDocumentBuilderFactoryClassName(String name){
        documentBuilderFactoryClassName = name;
    }
    public String getDocumentBuilderFactoryClassName(){
        return documentBuilderFactoryClassName;
    }
    
    public void setValidate(boolean validate){
        isValidate = validate;
    }
    public boolean isValidate(){
        return isValidate;
    }
    
    public void setContextServiceName(ServiceName name){
        contextServiceName = name;
    }
    public ServiceName getContextServiceName(){
        return contextServiceName;
    }
    
    public void setInterceptorChainFactoryServiceName(ServiceName name){
        interceptorChainFactoryServiceName = name;
    }
    public ServiceName getInterceptorChainFactoryServiceName(){
        return interceptorChainFactoryServiceName;
    }
    
    public void setJournalServiceName(ServiceName name){
        journalServiceName = name;
    }
    public ServiceName getJournalServiceName(){
        return journalServiceName;
    }
    
    public void setEditorFinderServiceName(ServiceName name){
        editorFinderServiceName = name;
    }
    public ServiceName getEditorFinderServiceName(){
        return editorFinderServiceName;
    }
    
    public void setExpressionInterpreterServiceName(ServiceName name){
        expressionInterpreterServiceName = name;
    }
    public ServiceName getExpressionInterpreterServiceName(){
        return expressionInterpreterServiceName;
    }
    
    public void setTestInterpreterServiceName(ServiceName name){
        testInterpreterServiceName = name;
    }
    public ServiceName getTestInterpreterServiceName(){
        return testInterpreterServiceName;
    }
    
    public void setInterpreterServiceName(ServiceName name){
        interpreterServiceName = name;
    }
    public ServiceName getInterpreterServiceName(){
        return interpreterServiceName;
    }
    
    public void setTransactionManagerFactoryServiceName(ServiceName name){
        transactionManagerFactoryServiceName = name;
    }
    public ServiceName getTransactionManagerFactoryServiceName(){
        return transactionManagerFactoryServiceName;
    }
    
    public void setAsynchExecuteQueueHandlerContainerServiceName(ServiceName name){
        asynchExecuteQueueHandlerContainerServiceName = name;
    }
    public ServiceName getAsynchExecuteQueueHandlerContainerServiceName(){
        return asynchExecuteQueueHandlerContainerServiceName;
    }
    
    public String getAsynchExecuteErrorLogMessageId(){
        return asynchExecuteErrorLogMessageId;
    }
    public void setAsynchExecuteErrorLogMessageId(String id){
        asynchExecuteErrorLogMessageId = id;
    }
    
    public String getAsynchExecuteRetryOverErrorLogMessageId(){
        return asynchExecuteRetryOverErrorLogMessageId;
    }
    public void setAsynchExecuteRetryOverErrorLogMessageId(String id){
        asynchExecuteRetryOverErrorLogMessageId = id;
    }
    
    public void setContext(Context<Object, Object> context){
        this.context = context;
    }
    public Context<Object, Object> getContext(){
        return context;
    }
    
    public void setInterceptorChainFactory(InterceptorChainFactory fac){
        interceptorChainFactory = fac;
    }
    public InterceptorChainFactory getInterceptorChainFactory(){
        return interceptorChainFactory;
    }
    
    public void setJournal(Journal journal){
        this.journal = journal;
    }
    public Journal getJournal(){
        return journal;
    }
    
    public void setEditorFinder(EditorFinder finder){
        this.editorFinder = finder;
    }
    public EditorFinder getEditorFinder(){
        return editorFinder;
    }
    
    public void setExpressionInterpreter(Interpreter interpreter){
        this.expressionInterpreter = interpreter;
    }
    public Interpreter getExpressionInterpreter(){
        return expressionInterpreter;
    }
    
    public void setTestInterpreter(Interpreter interpreter){
        this.testInterpreter = interpreter;
    }
    public Interpreter getTestInterpreter(){
        return testInterpreter;
    }
    
    public void setInterpreter(Interpreter interpreter){
        this.interpreter = interpreter;
    }
    public Interpreter getInterpreter(){
        return interpreter;
    }
    
    public void setTransactionManagerFactory(TransactionManagerFactory fac){
        transactionManagerFactory = fac;
    }
    public TransactionManagerFactory getTransactionManagerFactory(){
        return transactionManagerFactory;
    }
    
    public void setAsynchExecuteQueueHandlerContainer(QueueHandlerContainer<BeanFlowAsynchContext> container){
        asynchExecuteQueueHandlerContainer = container;
    }
    public QueueHandlerContainer<BeanFlowAsynchContext> getAsynchExecuteQueueHandlerContainer(){
        return asynchExecuteQueueHandlerContainer;
    }
    
    public void startService() throws Exception{
        if(contextServiceName != null){
            context = ServiceManagerFactory.getServiceObject(contextServiceName);
        }
        if(interceptorChainFactoryServiceName != null){
            interceptorChainFactory = ServiceManagerFactory.getServiceObject(interceptorChainFactoryServiceName);
        }
        if(journalServiceName != null){
            journal = ServiceManagerFactory.getServiceObject(journalServiceName);
        }
        if(editorFinderServiceName != null){
            editorFinder = ServiceManagerFactory.getServiceObject(editorFinderServiceName);
        }
        if(expressionInterpreterServiceName != null){
            expressionInterpreter = ServiceManagerFactory.getServiceObject(expressionInterpreterServiceName);
        }
        if(testInterpreterServiceName != null){
            testInterpreter = ServiceManagerFactory.getServiceObject(testInterpreterServiceName);
        }
        if(interpreterServiceName != null){
            interpreter = ServiceManagerFactory.getServiceObject(interpreterServiceName);
        }
        if(asynchExecuteQueueHandlerContainerServiceName != null){
            asynchExecuteQueueHandlerContainer = ServiceManagerFactory.getServiceObject(asynchExecuteQueueHandlerContainerServiceName);
            asynchExecuteQueueHandlerContainer.setQueueHandler(new BeanFlowAsynchExecuteQueueHandler());
            asynchExecuteQueueHandlerContainer.accept();
        }
        
        if(transactionManagerFactoryServiceName != null){
            transactionManagerFactory = ServiceManagerFactory.getServiceObject(transactionManagerFactoryServiceName);
        }
        if(transactionManagerFactory == null){
            JndiTransactionManagerFactoryService transactionManagerFactoryService = new JndiTransactionManagerFactoryService();
            transactionManagerFactoryService.create();
            transactionManagerFactoryService.start();
            transactionManagerFactory = transactionManagerFactoryService;
        }
        
        reload();
    }
    
    public synchronized void reload() throws Exception{
        
        Map<String, BeanFlow> tmpFlowMap = new HashMap<String, BeanFlow>();
        Map<String, BeanFlow> tmpAliasMap = new HashMap<String, BeanFlow>();
        
        File serviceDefDir = null;
        if(getServiceNameObject() != null){
            try{
                ServiceMetaData metaData = ServiceManagerFactory.getServiceMetaData(getServiceNameObject());
                ServiceLoader loader = metaData.getServiceLoader();
                if(loader != null){
                    String filePath = loader.getServiceURL().getFile();
                    if(filePath != null){
                        serviceDefDir = new File(filePath).getParentFile();
                    }
                }
            }catch(ServiceNotFoundException e){
            }
        }
        if(flowDirs != null){
            for(String dir : flowDirs){
                RecursiveFile file = new RecursiveFile(dir);
                if(!file.exists() && serviceDefDir != null){
                    file = new RecursiveFile(serviceDefDir, dir);
                }
                final File[] files = file.listAllTreeFiles(
                    new ExtentionFileFilter("xml")
                );
                if(files != null){
                    for(File f : files){
                        load(f, tmpFlowMap, tmpAliasMap);
                    }
                }
            }
        }
        if(flowPaths != null){
            for(String path : flowPaths){
                File file = new File(path);
                if(!file.exists() && serviceDefDir != null){
                    file = new File(serviceDefDir, path);
                }
                load(file, tmpFlowMap, tmpAliasMap);
            }
        }
        
        flowMap = tmpFlowMap;
        aliasMap = tmpAliasMap;
    }
    
    protected void load(File file, Map<String, BeanFlow> flowMap, Map<String, BeanFlow> aliasMap) throws Exception{
        DocumentBuilderFactory domFactory = null;
        if(documentBuilderFactoryClassName == null){
            domFactory = DocumentBuilderFactory.newInstance();
        }else{
            domFactory = DocumentBuilderFactory.newInstance(
                documentBuilderFactoryClassName,
                NimbusClassLoader.getInstance()
            );
        }
        domFactory.setValidating(isValidate());
        final DocumentBuilder builder = domFactory.newDocumentBuilder();
        final NimbusEntityResolver resolver = new NimbusEntityResolver();
        builder.setEntityResolver(resolver);
        final MyErrorHandler handler = new MyErrorHandler();
        builder.setErrorHandler(handler);
        Document doc = null;
        try{
            doc = builder.parse(file);
        }catch(SAXParseException e){
            throw new DeploymentException("Bean flow file parse error. : " + file, e);
        }
        if(handler.isError()){
            throw new DeploymentException(
                "Bean flow definition validate error : " + file
            );
        }
        
        NodeList flowList = doc.getElementsByTagName("flow");
        for(int i = 0; i < flowList.getLength(); i++){
            Element flowElement = (Element)flowList.item(i);
            DefaultBeanFlow flow = new DefaultBeanFlow(this);
            flow.importXML(flowElement);
            if(flowMap.containsKey(flow.getFlowName())){
                throw new DuplicatedBeanFlowException(flow.getFlowName());
            }
            flowMap.put(flow.getFlowName(), flow);
            List<String> list = flow.getAiliasFlowNames();
            for(String alias : list){
                if(aliasMap.containsKey(alias)){
                    throw new DuplicatedBeanFlowException(alias);
                }
                aliasMap.put(alias, flow);
            }
        }
    }
    
    @Override
    public BeanFlow createFlow(String key) throws BeanFlowException{
        return createFlow(key, null, true);
    }
    
    @Override
    public BeanFlow createFlow(String key, String caller, boolean isOverride) throws BeanFlowException{
        
        BeanFlow flow = createFlowInternal(key, caller, isOverride);
        
        key = flow.getFlowName();
        
        if(interceptorChainFactory == null){
            return flow;
        }
        final InterceptorChain chain
             = interceptorChainFactory.getInterceptorChain(key);
        if(chain == null){
            return flow;
        }
        return new WrappedBeanFlow(flow, chain);
    }
    
    protected BeanFlow createFlowInternal(
        String key,
        String caller,
        boolean isOverride
    ) throws BeanFlowException{
        BeanFlow flow = flowMap.get(key);
        if(flow == null){
            flow = aliasMap.get(key);
        }
        if(flow == null){
            throw new NoSuchBeanFlowException(key);
        }
        if(isOverride){
            String[] overrides = flow.getOverrideFlowNames();
            if(overrides != null){
                for(int i = overrides.length; --i >= 0;){
                    final String overrideName = replaceProperty(overrides[i]);
                    if(key.equals(overrideName)){
                        break;
                    }
                    if(caller != null && caller.equals(overrideName)){
                        continue;
                    }
                    if(containsFlow(overrideName)){
                        BeanFlow override = createFlowInternal(overrideName, caller, isOverride);
                        if(override != null){
                            flow = override;
                            key = override.getFlowName();
                            break;
                        }
                    }
                }
            }
        }
        return flow;
    }
    
    @Override
    public Set<String> getBeanFlowKeySet(){
        final Set<String> result = new HashSet<String>();
        result.addAll(flowMap.keySet());
        result.addAll(aliasMap.keySet());
        return result;
    }
    
    @Override
    public boolean containsFlow(String key){
        return flowMap.containsKey(key) || aliasMap.containsKey(key);
    }
    
    public String replaceProperty(String textValue){
        
        // システムプロパティの置換
        textValue = Utility.replaceSystemProperty(textValue, false);
        
        // サービスローダ構成プロパティの置換
        if(getServiceNameObject() != null){
            ServiceMetaData metaData = null;
            try{
                metaData = ServiceManagerFactory.getServiceMetaData(
                    getServiceNameObject()
                );
                textValue = Utility.replaceServiceLoderConfig(
                    metaData.getServiceLoader().getConfig(),
                    textValue,
                    false
                );
            }catch(ServiceNotFoundException e){}
        }
        
        // コンテキストプロパティの置換
        textValue = replaceContextProperty(textValue, false);
        
        // マネージャプロパティの置換
        if(getServiceManager() != null){
            textValue = Utility.replaceManagerProperty(
                getServiceManager(),
                textValue,
                false
            );
        }
        
        // サーバプロパティの置換
        textValue = Utility.replaceServerProperty(textValue, true);
        
        return textValue;
    }
    
    /**
     * 指定された文字列内のプロパティ参照文字列をコンテキストプロパティの値に置換する。<p>
     *
     * @param str 文字列
     * @param applyDefault プロパティ参照文字列内のデフォルト値を適用するかどうか
     * @return プロパティ参照文字列をコンテキストプロパティの値に置換した文字列
     */
    public String replaceContextProperty(
        String str,
        boolean applyDefault
    ){
        if(context == null){
            return str;
        }
        String result = str;
        if(result == null){
            return null;
        }
        final int startIndex = result.indexOf(Utility.SYSTEM_PROPERTY_START);
        if(startIndex == -1){
            return result;
        }
        final int endIndex = result.indexOf(Utility.SYSTEM_PROPERTY_END);
        if(endIndex == -1 || startIndex > endIndex){
            return result;
        }
        String propStr = result.substring(
            startIndex + Utility.SYSTEM_PROPERTY_START.length(),
            endIndex
        );
        final int defaultValueIndex = propStr.indexOf(Utility.SYSTEM_PROPERTY_DEFAULT_VALUE_SEPARATOR);
        String defaultValue = null;
        if(defaultValueIndex != -1){
            propStr = propStr.substring(0, defaultValueIndex);
            defaultValue = propStr.substring(defaultValueIndex + 1);
        }
        String prop = applyDefault ? defaultValue : null;
        if(propStr != null && propStr.length() != 0){
            Object propObj = context.get(propStr);
            if(propObj != null){
                prop = propObj.toString();
            }
        }
        if(prop == null){
            return result.substring(0, endIndex + Utility.SYSTEM_PROPERTY_END.length())
             + replaceContextProperty(
                result.substring(endIndex + Utility.SYSTEM_PROPERTY_END.length()),
                applyDefault
             );
        }else{
            result = result.substring(0, startIndex) + prop
                 + result.substring(endIndex + Utility.SYSTEM_PROPERTY_END.length());
        }
        if(result.indexOf(Utility.SYSTEM_PROPERTY_START) != -1){
            return replaceContextProperty(result, applyDefault);
        }
        return result;
    }
    
    public PropertyEditor findEditor(Class<?> type){
        PropertyEditor editor = null;
        ServiceManager manager = this.getServiceManager();
        if(manager != null){
            ServiceMetaData metaData = manager.getServiceMetaData(getServiceName());
            if(metaData != null){
                editor = metaData.getServiceLoader().findEditor(type);
            }
        }
        if(editor == null){
            editor = NimbusPropertyEditorManager.findEditor(type);
        }
        return editor;
    }
    
    protected class WrappedBeanFlow implements BeanFlow{
        
        private BeanFlow realFlow;
        private InterceptorChain chain;
        
        public WrappedBeanFlow(
            BeanFlow realFlow,
            InterceptorChain chain
        ){
            this.realFlow = realFlow;
            this.chain = chain;
        }
        
        @Override
        public String getFlowName(){
            return realFlow.getFlowName();
        }
        
        @Override
        public String[] getOverrideFlowNames(){
            return realFlow.getOverrideFlowNames();
        }
        
        @Override
        public BeanFlowMonitor createMonitor(){
            return realFlow.createMonitor();
        }
        
        @Override
        public Object execute(Object obj) throws Exception{
            return execute(obj, null);
        }
        
        @Override
        public Object execute(Object obj, BeanFlowMonitor monitor) throws Exception{
            final InvocationContext context
                 = new DefaultMethodInvocationContext(
                    realFlow,
                    realFlow.getClass().getMethod(
                        INVOKE_FLOW_METHOD_NAME,
                        INVOKE_FLOW_METHOD_PARAM
                    ),
                    new Object[]{obj, monitor}
                );
            try{
                return chain.invokeNext(context);
            }catch(Throwable th){
                if(th instanceof Exception){
                    throw (Exception)th;
                }else{
                    throw (Error)th;
                }
            }
        }
        
        @Override
        public Object executeAsynch(Object obj, BeanFlowMonitor monitor, boolean isReply, int maxAsynchWait) throws Exception{
            return realFlow.executeAsynch(obj, monitor, isReply, maxAsynchWait);
        }
        
        @Override
        public Object getAsynchReply(Object context, BeanFlowMonitor monitor, long timeout, boolean isCancel) throws BeanFlowAsynchTimeoutException, Exception{
            return realFlow.getAsynchReply(context, monitor, timeout, isCancel);
        }
        
        @Override
        public Object executeAsynch(Object obj, BeanFlowMonitor monitor, BeanFlowAsynchCallback callback, int maxAsynchWait) throws Exception{
            return realFlow.executeAsynch(obj, monitor, callback, maxAsynchWait);
        }
        
        public void end(){
        }
    }
    
    protected class MyErrorHandler implements ErrorHandler{
        
        private boolean isError;
        
        @Override
        public void warning(SAXParseException e) throws SAXException{
            getLogger().write(
                "DBFF_00001",
                e.getMessage(), e.getLineNumber(), e.getColumnNumber()
            );
        }
        @Override
        public void error(SAXParseException e) throws SAXException{
            isError = true;
            getLogger().write(
                "DBFF_00002",
                e.getMessage(), e.getLineNumber(), e.getColumnNumber()
            );
        }
        @Override
        public void fatalError(SAXParseException e) throws SAXException{
            isError = true;
            getLogger().write(
                "DBFF_00003",
                e.getMessage(), e.getLineNumber(), e.getColumnNumber()
            );
        }
        public boolean isError(){
            return isError;
        }
    }
    
    protected class BeanFlowAsynchExecuteQueueHandler implements QueueHandler<BeanFlowAsynchContext>{
        
        // QueueHandlerのJavaDoc
        public void handleDequeuedObject(BeanFlowAsynchContext asynchCtx) throws Throwable{
            if(asynchCtx.isCancel()){
                return;
            }
            BeanFlow flow = asynchCtx.getBeanFlow();
            BeanFlowMonitor monitor = asynchCtx.getBeanFlowMonitor();
            if(flow == null){
                String flowName = asynchCtx.getFlowName();
                flow = createFlow(flowName);
            }
            Object input = asynchCtx.getInput();
            if(context != null){
                asynchCtx.applyThreadContext(context);
            }
            Object output = null;
            output = flow.execute(input, monitor);
            if(asynchCtx != null){
                asynchCtx.setOutput(output);
                if(asynchCtx.getResponseQueue() != null){
                    asynchCtx.getResponseQueue().push(asynchCtx);
                }
            }
        }
        
        // QueueHandlerのJavaDoc
        public boolean handleError(BeanFlowAsynchContext asynchCtx, Throwable th) throws Throwable{
            if(asynchExecuteErrorLogMessageId != null){
                getLogger().write(asynchExecuteErrorLogMessageId, th, asynchCtx);
            }
            if(th instanceof NoSuchBeanFlowException){
                return false;
            }else{
                return true;
            }
        }
        
        // QueueHandlerのJavaDoc
        public void handleRetryOver(BeanFlowAsynchContext asynchCtx, Throwable th) throws Throwable{
            if(asynchExecuteRetryOverErrorLogMessageId != null){
                getLogger().write(asynchExecuteRetryOverErrorLogMessageId, th, asynchCtx);
            }
            asynchCtx.setThrowable(th);
            if(asynchCtx.getResponseQueue() != null){
                asynchCtx.getResponseQueue().push(asynchCtx);
            }
        }
    }
}
