org.soybeanMilk.core.config.parser.ConfigurationParser.java Source code

Java tutorial

Introduction

Here is the source code for org.soybeanMilk.core.config.parser.ConfigurationParser.java

Source

/**
 * Licensed under the Apache License, Version 2.0 (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.apache.org/licenses/LICENSE-2.0
 * 
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License. 
 */

package org.soybeanMilk.core.config.parser;

import java.io.File;
import java.io.FileFilter;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.Serializable;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import javax.xml.parsers.DocumentBuilderFactory;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.soybeanMilk.SbmUtils;
import org.soybeanMilk.core.Constants;
import org.soybeanMilk.core.Executable;
import org.soybeanMilk.core.ExecuteException;
import org.soybeanMilk.core.ObjectSource;
import org.soybeanMilk.core.bean.Converter;
import org.soybeanMilk.core.bean.DefaultGenericConverter;
import org.soybeanMilk.core.bean.GenericConverter;
import org.soybeanMilk.core.config.Configuration;
import org.soybeanMilk.core.config.Interceptor;
import org.soybeanMilk.core.exe.Action;
import org.soybeanMilk.core.exe.Invoke;
import org.soybeanMilk.core.exe.Invoke.Arg;
import org.soybeanMilk.core.exe.support.DefaultResolverObjectFactory;
import org.soybeanMilk.core.exe.support.DynamicResolver;
import org.soybeanMilk.core.exe.support.FactoryResolver;
import org.soybeanMilk.core.exe.support.KeyArg;
import org.soybeanMilk.core.exe.support.ObjectResolver;
import org.soybeanMilk.core.exe.support.ObjectSourceResolver;
import org.soybeanMilk.core.exe.support.ResolverObjectFactory;
import org.soybeanMilk.core.exe.support.ValueArg;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;

/**
 * ??
 * @author earthangry@gmail.com
 * @date 2010-10-1
 */
public class ConfigurationParser {
    private static Log log = LogFactory.getLog(ConfigurationParser.class);

    protected static final String TAG_ROOT = "soybean-milk";

    protected static final String TAG_GLOBAL_CONFIG = "global-config";
    protected static final String TAG_GENERIC_CONVERTER = "generic-converter";
    protected static final String TAG_GENERIC_CONVERTER_ATTR_CLASS = "class";
    protected static final String TAG_CONVERTER = "converter";
    protected static final String TAG_CONVERTER_ATTR_SRC = "src";
    protected static final String TAG_CONVERTER_ATTR_TARGET = "target";
    protected static final String TAG_CONVERTER_ATTR_CLASS = TAG_GENERIC_CONVERTER_ATTR_CLASS;

    protected static final String TAG_INTERCEPROT = "interceptor";
    protected static final String TAG_INTERCEPROT_ATTR_BEFORE = "before";
    protected static final String TAG_INTERCEPROT_ATTR_AFTER = "after";
    protected static final String TAG_INTERCEPROT_ATTR_EXCEPTION = "exception";
    protected static final String TAG_INTERCEPROT_ATTR_EXECUTION_KEY = "execution-key";

    protected static final String TAG_INCLUDES = "includes";
    protected static final String TAG_LOCATION = "location";

    protected static final String TAG_RESOLVERS = "resolvers";
    protected static final String TAG_RESOLVER = "resolver";
    protected static final String TAG_RESOLVER_ATTR_ID = "id";
    protected static final String TAG_RESOLVER_ATTR_CLASS = "class";

    protected static final String TAG_EXECUTABLES = "executables";
    protected static final String TAG_EXECUTABLES_ATTR_PREFIX = "prefix";

    protected static final String TAG_ACTION = "action";
    protected static final String TAG_ACTION_ATTR_NAME = "name";

    protected static final String TAG_INVOKE = "invoke";
    protected static final String TAG_INVOKE_ATTR_NAME = TAG_ACTION_ATTR_NAME;
    protected static final String TAG_INVOKE_ATTR_METHOD = "method";
    protected static final String TAG_INVOKE_ATTR_RESOLVER = "resolver";
    protected static final String TAG_INVOKE_ATTR_RESULT_KEY = "result-key";
    protected static final String TAG_INVOKE_ATTR_BREAKER = "breaker";

    protected static final String TAG_ARG = "arg";
    protected static final String TAG_ARG_ATTR_TYPE = "type";

    protected static final String TAG_REF = "ref";
    protected static final String TAG_REF_ATTR_NAME = "name";

    /***/
    private Document rootDocument;

    /**?*/
    private Configuration configuration;

    /**??*/
    private List<Document> modules;

    /**???*/
    private String currentExecutablePrefix;

    /**
     * ???
     */
    public ConfigurationParser() {
        this(null);
    }

    /**
     * ?????
     * @param configuration ?
     */
    public ConfigurationParser(Configuration configuration) {
        setConfiguration(configuration);
    }

    /**
     * ??
     * @return
     */
    public Configuration getConfiguration() {
        return configuration;
    }

    /**
     * ???????
     * @param configuration
     */
    public void setConfiguration(Configuration configuration) {
        this.configuration = configuration;
    }

    /**
     * ??
     * @return
     */
    public Document getDocument() {
        return this.rootDocument;
    }

    /**
     * ?
     * @param document
     */
    public void setDocument(Document document) {
        this.rootDocument = document;
    }

    /**
     * ??
     * @return
     */
    public List<Document> getModules() {
        return modules;
    }

    /**
     * ?
     * @param modules
     */
    public void setModules(List<Document> modules) {
        this.modules = modules;
    }

    /**
     * ??
     * @return
     */
    public Configuration parse() {
        return parse((String) null);
    }

    /**
     * ??
     * @param configFile ????
     * @return
     */
    public Configuration parse(String configFile) {
        if (configFile == null || configFile.length() == 0)
            configFile = getDefaultConfigFile();

        setDocument(parseDocument(configFile));

        parseAll();

        return getConfiguration();
    }

    /**
     * ??
     * @param in
     * @return
     */
    public Configuration parse(InputStream in) {
        setDocument(parseDocument(in));

        parseAll();

        return getConfiguration();
    }

    /**
     * ?
     * @param document
     * @return
     */
    public Configuration parse(Document document) {
        setDocument(document);

        parseAll();

        return getConfiguration();
    }

    /**
     * ??
     * @return ?
     */
    protected void parseAll() {
        if (getConfiguration() == null)
            setConfiguration(createConfigurationInstance());

        Element rootDocEle = getDocumentRootElement(rootDocument);

        parseGlobalConfigs(rootDocEle);
        parseIncludes(rootDocEle);
        parseResolvers(rootDocEle);
        parseExecutables(rootDocEle);

        if (modules != null) {
            for (Document doc : modules) {
                Element subDoc = getDocumentRootElement(doc);

                parseResolvers(subDoc);
                parseExecutables(subDoc);
            }
        }

        parseRefs();
    }

    /**
     * ??
     */
    protected void parseGlobalConfigs(Element docRoot) {
        Element parent = getSingleElementByTagName(docRoot, TAG_GLOBAL_CONFIG);

        parseGenericConverter(parent);

        parseInterceptor(parent);
    }

    /**
     * ????
     */
    protected void parseIncludes(Element docRoot) {
        List<Element> files = getChildrenByTagName(getSingleElementByTagName(docRoot, TAG_INCLUDES), TAG_LOCATION);

        if (files == null || files.isEmpty())
            return;

        this.modules = new ArrayList<Document>();

        for (Element el : files) {
            String fileName = getTextContent(el);
            assertNotEmpty(fileName, "<" + TAG_LOCATION + "> content must not be null");

            Document[] docs = parseDocuments(fileName);
            if (docs != null) {
                for (Document d : docs)
                    this.modules.add(d);
            }
        }
    }

    /**
     * ?
     */
    protected void parseResolvers(Element docRoot) {
        List<Element> children = getChildrenByTagName(getSingleElementByTagName(docRoot, TAG_RESOLVERS),
                TAG_RESOLVER);

        if (children != null && !children.isEmpty()) {
            ResolverObjectFactory rf = configuration.getResolverObjectFactory();
            if (rf == null) {
                rf = createResolverObjectFactoryInstance();
                configuration.setResolverObjectFactory(rf);
            }

            ResolverObjectFactory drf = (ResolverObjectFactory) rf;

            for (Element e : children) {
                String id = getAttributeValueIngoreEmpty(e, TAG_RESOLVER_ATTR_ID);
                assertNotEmpty(id,
                        "<" + TAG_RESOLVER + "> attribute [" + TAG_RESOLVER_ATTR_ID + "] must not be null");
                String clazz = getAttributeValueIngoreEmpty(e, TAG_RESOLVER_ATTR_CLASS);
                assertNotEmpty(clazz, "<" + TAG_RESOLVER + "> of id " + SbmUtils.toString(id) + " attribute ["
                        + TAG_RESOLVER_ATTR_CLASS + "] must not be null");

                Object resolver = createClassInstance(clazz);

                drf.addResolverObject(id, resolver);
            }
        }
    }

    /**
     * ??
     */
    protected void parseExecutables(Element docRoot) {
        List<Element> executables = getChildrenByTagName(docRoot, TAG_EXECUTABLES);

        if (executables != null) {
            for (Element ele : executables) {
                setCurrentExecutablePrefix(getAttributeValue(ele, TAG_EXECUTABLES_ATTR_PREFIX));

                List<Element> children = getChildrenByTagName(ele, null);

                if (children != null) {
                    for (Element e : children) {
                        Executable executable = createExecutableInstance(e.getTagName());

                        if (executable instanceof Action)
                            setActionProperties((Action) executable, e);
                        else
                            setInvokeProperties((Invoke) executable, e, true);

                        configuration.addExecutable(executable);
                    }
                }
            }
        }
    }

    /**
     * ?
     */
    protected void parseRefs() {
        processExecutableRefs();
        processInterceptorInfoRefs();
    }

    /**
     * ??
     * @param parent
     */
    protected void parseGenericConverter(Element parent) {
        Element cvtEl = getSingleElementByTagName(parent, TAG_GENERIC_CONVERTER);

        String clazz = cvtEl == null ? null : getAttributeValueIngoreEmpty(cvtEl, TAG_GENERIC_CONVERTER_ATTR_CLASS);

        GenericConverter genericConverter = configuration.getGenericConverter();
        if (genericConverter == null) {
            if (clazz == null || clazz.length() == 0)
                genericConverter = createGenericConverterInstance();
            else
                genericConverter = (GenericConverter) createClassInstance(clazz);

            configuration.setGenericConverter(genericConverter);
        }

        parseSupportConverters(genericConverter, cvtEl);
    }

    /**
     * ????
     * @param genericConverter
     * @param parent
     */
    protected void parseSupportConverters(GenericConverter genericConverter, Element parent) {
        List<Element> children = getChildrenByTagName(parent, TAG_CONVERTER);
        if (children == null || children.isEmpty())
            return;

        for (Element e : children) {
            String src = getAttributeValueIngoreEmpty(e, TAG_CONVERTER_ATTR_SRC);
            String target = getAttributeValueIngoreEmpty(e, TAG_CONVERTER_ATTR_TARGET);
            String clazz = getAttributeValueIngoreEmpty(e, TAG_CONVERTER_ATTR_CLASS);

            assertNotEmpty(src,
                    "<" + TAG_CONVERTER + "> attribute [" + TAG_CONVERTER_ATTR_SRC + "] must not be empty");
            assertNotEmpty(target,
                    "<" + TAG_CONVERTER + "> attribute [" + TAG_CONVERTER_ATTR_TARGET + "] must not be empty");
            assertNotEmpty(clazz,
                    "<" + TAG_CONVERTER + "> attribute [" + TAG_CONVERTER_ATTR_CLASS + "] must not be empty");

            genericConverter.addConverter(nameToType(src), nameToType(target),
                    (Converter) createClassInstance(clazz));
        }
    }

    /**
     * ??
     * @param element 
     */
    protected void parseInterceptor(Element parent) {
        Element el = getSingleElementByTagName(parent, TAG_INTERCEPROT);
        if (el == null)
            return;

        String before = getAttributeValueIngoreEmpty(el, TAG_INTERCEPROT_ATTR_BEFORE);
        String after = getAttributeValueIngoreEmpty(el, TAG_INTERCEPROT_ATTR_AFTER);
        String exception = getAttributeValueIngoreEmpty(el, TAG_INTERCEPROT_ATTR_EXCEPTION);
        String executionKey = getAttributeValueIngoreEmpty(el, TAG_INTERCEPROT_ATTR_EXECUTION_KEY);

        assertNotEmpty(executionKey, "<" + TAG_INTERCEPROT + "> attribute [" + TAG_INTERCEPROT_ATTR_EXECUTION_KEY
                + "] must not be empty");

        Interceptor ii = createInterceptorInfoInstance();
        ii.setExecutionKey(executionKey);

        if (before != null)
            ii.setBefore(new ExecutableRefProxy(before, getCurrentExecutablePrefix()));
        if (after != null)
            ii.setAfter(new ExecutableRefProxy(after, getCurrentExecutablePrefix()));
        if (exception != null)
            ii.setException(new ExecutableRefProxy(exception, getCurrentExecutablePrefix()));

        getConfiguration().setInterceptor(ii);
    }

    /**
     * ?
     * @param action
     * @param element
     */
    protected void setActionProperties(Action action, Element element) {
        //???""servlet??serlvet

        String name = getAttributeValue(element, TAG_ACTION_ATTR_NAME);
        assertNotNull(name, "<" + TAG_ACTION + "> attribute [" + TAG_ACTION_ATTR_NAME + "] must not be null");

        action.setName(formatGlobalExecutableName(name));

        List<Element> children = getChildrenByTagName(element, null);
        for (Element e : children) {
            String tagName = e.getTagName();
            if (TAG_REF.equals(tagName)) {
                String refExecutableName = getAttributeValue(e, TAG_REF_ATTR_NAME);
                assertNotNull(refExecutableName, "<" + TAG_REF + "> attribute [" + TAG_REF_ATTR_NAME + "] in <"
                        + TAG_ACTION + "> named " + SbmUtils.toString(action.getName()) + " must not be null");

                action.addExecutable(new ExecutableRefProxy(refExecutableName, getCurrentExecutablePrefix()));
            } else if (TAG_INVOKE.equals(tagName)) {
                Invoke invoke = createInvokeIntance();
                setInvokeProperties(invoke, e, false);

                action.addExecutable(invoke);
            }
        }
    }

    /**
     * ?
     * @param invoke
     * @param element
     * @param global ?
     */
    protected void setInvokeProperties(Invoke invoke, Element element, boolean global) {
        String methodName = getAttributeValueIngoreEmpty(element, TAG_INVOKE_ATTR_METHOD);
        String breaker = getAttributeValueIngoreEmpty(element, TAG_INVOKE_ATTR_BREAKER);

        if (breaker != null) {
            Serializable brk = null;

            if (Boolean.TRUE.toString().equals(breaker))
                brk = Boolean.TRUE;
            else if (Boolean.FALSE.toString().equals(breaker))
                brk = Boolean.FALSE;
            else
                brk = breaker;

            invoke.setBreaker(brk);
        }

        if (methodName == null)
            setInvokePropertiesStatement(invoke, element, global);
        else
            setInvokePropertiesXml(invoke, element, global);
    }

    /**
     * ??
     * @param invoke
     * @param element
     * @param global ?
     */
    protected void setInvokePropertiesStatement(Invoke invoke, Element element, boolean global) {
        String statement = getTextContent(element);
        assertNotEmpty(statement, "<" + TAG_INVOKE + "> content must not be empty");

        String name = getAttributeValue(element, TAG_INVOKE_ATTR_NAME);
        if (global)
            name = formatGlobalExecutableName(name);

        InvokeStatementParser isp = new InvokeStatementParser(statement);
        isp.parse();

        invoke.setName(name);
        invoke.setResultKey(isp.getResultKey());
        invoke.setMethodName(isp.getMethodName());
        processInvokeResolverInit(invoke, isp.getResolver());
        processInvokeArgsInit(invoke, isp.getArgs(), isp.getArgTypes());
    }

    /**
     * XML?
     * @param invoke
     * @param element
     * @param global ?
     */
    protected void setInvokePropertiesXml(Invoke invoke, Element element, boolean global) {
        String name = getAttributeValue(element, TAG_INVOKE_ATTR_NAME);
        if (global)
            name = formatGlobalExecutableName(name);
        String methodName = getAttributeValueIngoreEmpty(element, TAG_INVOKE_ATTR_METHOD);
        String resolver = getAttributeValueIngoreEmpty(element, TAG_INVOKE_ATTR_RESOLVER);
        String resultKey = getAttributeValueIngoreEmpty(element, TAG_INVOKE_ATTR_RESULT_KEY);

        if (methodName == null)
            throw new ParseException(
                    "<" + TAG_INVOKE + "> attribute [" + TAG_INVOKE_ATTR_METHOD + "] must not be null");
        if (resolver == null)
            throw new ParseException(
                    "<" + TAG_INVOKE + "> attribute [" + TAG_INVOKE_ATTR_RESOLVER + "] must not be null");

        invoke.setName(name);
        invoke.setResultKey(resultKey);
        invoke.setMethodName(methodName);
        processInvokeResolverInit(invoke, resolver);

        parseArgs(invoke, element);
    }

    /**
     * ?parent??
     * @param invoke
     * @param parent
     */
    protected void parseArgs(Invoke invoke, Element parent) {
        List<Element> elements = getChildrenByTagName(parent, TAG_ARG);
        if (elements == null)
            return;

        String[] strArgs = new String[elements.size()];
        String[] strArgTypes = new String[elements.size()];

        for (int i = 0, len = strArgs.length; i < len; i++) {
            Element e = elements.get(i);

            String type = getAttributeValue(e, TAG_ARG_ATTR_TYPE);
            String content = getTextContent(e);
            if (content == null)
                throw new ParseException("<" + TAG_ARG + "> must have text content");

            strArgs[i] = content;
            strArgTypes[i] = type;
        }

        processInvokeArgsInit(invoke, strArgs, strArgTypes);
    }

    /**
     * ?Invoke?
     * @param invoke
     * @param resultKey
     * @param resolver
     * @param methodName
     * @param args
     * @param strArgTypes
     * @date 2012-5-8
     */
    /*
    protected void processInvokePropertiesInit(Invoke invoke, String resultKey, String resolver, String methodName, String[] strArgs, String[] strArgTypes)
    {
       invoke.setResultKey(resultKey);
           
       boolean classResolver=false;
       //resolver??
       if(resolver.indexOf('.') > -1)
       {
     try
     {
        Class<?> rc=Class.forName(resolver);
        invoke.setResolverProvider(new ObjectResolverProvider(null, rc));
            
        classResolver=true;
     }
     catch(Exception e)
     {
        classResolver=false;
     }
       }
       if(!classResolver)
       {
     FactoryResolverProvider frp=new FactoryResolverProvider(configuration.getResolverObjectFactory(), resolver);
     ObjectSourceResolverProvider orp=new ObjectSourceResolverProvider(resolver);
         
     invoke.setResolverProvider(new DynamicResolverProvider(frp, orp));
       }
           
       invoke.setMethodName(methodName);
           
       if(strArgs != null)
       {
     Arg[] args=new Arg[strArgs.length];
         
     for(int i=0; i<strArgs.length; i++)
        args[i]=stringToArg(strArgs[i], (strArgTypes==null ? null : strArgTypes[i]));
         
     invoke.setArgs(args);
       }
    }
    */

    /**
     * ??
     * @param invoke
     * @param resolver
     * @date 2012-5-11
     */
    protected void processInvokeResolverInit(Invoke invoke, String resolver) {
        boolean classResolver = false;
        //resolver??
        if (resolver.indexOf('.') > -1) {
            try {
                Class<?> rc = SbmUtils.narrowToClass(nameToType(resolver));
                invoke.setResolver(new ObjectResolver(null, rc));

                classResolver = true;
            } catch (Exception e) {
                classResolver = false;
            }
        }
        if (!classResolver) {
            FactoryResolver frp = new FactoryResolver(configuration.getResolverObjectFactory(), resolver);
            ObjectSourceResolver orp = new ObjectSourceResolver(resolver);

            invoke.setResolver(new DynamicResolver(frp, orp));
        }
    }

    /**
     * ???
     * @param invoke
     * @param resolver
     * @date 2012-5-11
     */
    protected void processInvokeArgsInit(Invoke invoke, String[] strArgs, String[] strArgTypes) {
        if (strArgs != null) {
            Arg[] args = new Arg[strArgs.length];

            for (int i = 0; i < strArgs.length; i++)
                args[i] = stringToArg(strArgs[i], (strArgTypes == null ? null : strArgTypes[i]));

            invoke.setArgs(args);
        }
    }

    /**
     * ?????
     * ??
     */
    protected void processExecutableRefs() {
        Collection<Executable> executables = configuration.getExecutables();
        if (executables == null)
            return;

        for (Executable exe : executables) {
            if (exe instanceof Action) {
                Action action = (Action) exe;
                List<Executable> actionExes = action.getExecutables();
                if (actionExes == null)
                    continue;

                for (int i = 0, len = actionExes.size(); i < len; i++) {
                    Executable e = actionExes.get(i);

                    if (e instanceof ExecutableRefProxy) {
                        ExecutableRefProxy proxy = ((ExecutableRefProxy) e);
                        Executable targetExe = getTargetRefExecutable((ExecutableRefProxy) e);

                        if (targetExe == null)
                            throw new ParseException(
                                    "can not find Executable named " + SbmUtils.toString(proxy.getRefName())
                                            + " referenced in Action " + SbmUtils.toString(action.getName()));

                        actionExes.set(i, targetExe);
                    }
                }
            }
        }
    }

    /**
     * ???
     */
    protected void processInterceptorInfoRefs() {
        Interceptor ii = getConfiguration().getInterceptor();
        if (ii == null)
            return;

        {
            Executable before = ii.getBefore();
            if (before instanceof ExecutableRefProxy) {
                Executable targetExe = getTargetRefExecutable((ExecutableRefProxy) before);
                if (targetExe == null)
                    throw new ParseException("can not find 'before' interceptor named "
                            + SbmUtils.toString(((ExecutableRefProxy) before).getRefName()));

                ii.setBefore(targetExe);
            }
        }

        {
            Executable after = ii.getAfter();
            if (after instanceof ExecutableRefProxy) {
                Executable targetExe = getTargetRefExecutable((ExecutableRefProxy) after);
                if (targetExe == null)
                    throw new ParseException("can not find 'after' interceptor named "
                            + SbmUtils.toString(((ExecutableRefProxy) after).getRefName()));

                ii.setAfter(targetExe);
            }
        }

        {
            Executable exception = ii.getException();
            if (exception instanceof ExecutableRefProxy) {
                Executable targetExe = getTargetRefExecutable((ExecutableRefProxy) exception);
                if (targetExe == null)
                    throw new ParseException("can not find 'exception' interceptor named "
                            + SbmUtils.toString(((ExecutableRefProxy) exception).getRefName()));

                ii.setException(targetExe);
            }
        }
    }

    /**
     * ??
     * @param proxy
     * @return
     * @date 2011-3-15
     */
    protected Executable getTargetRefExecutable(ExecutableRefProxy proxy) {
        Executable target = null;

        //?
        if (target == null) {
            if (proxy.getCurrentExecutablePrefix() != null)
                target = configuration.getExecutable(proxy.getCurrentExecutablePrefix() + proxy.getRefName());
        }

        if (target == null)
            target = configuration.getExecutable(proxy.getRefName());

        return target;
    }

    /**
     * ??????
     * @param rawName
     * @return
     * @date 2011-3-15
     */
    protected String formatGlobalExecutableName(String rawName) {
        String cep = getCurrentExecutablePrefix();

        return cep == null ? rawName : cep + rawName;
    }

    /**
     * ??xml??
     * @param in
     * @return
     * @throws ParseException
     */
    protected Document parseDocument(InputStream in) {
        Document doc = null;

        try {
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();

            dbf.setNamespaceAware(false);

            //??
            dbf.setValidating(false);
            dbf.setAttribute("http://apache.org/xml/features/nonvalidating/load-external-dtd", false);

            doc = dbf.newDocumentBuilder().parse(in);

            in.close();

            return doc;
        } catch (Exception e) {
            throw new ParseException("", e);
        }
    }

    /**
     * ????
     * @param fileName
     * @return
     */
    protected Document[] parseDocuments(String fileName) {
        Document[] docs = null;

        if (fileName.endsWith("/*")) {
            fileName = formatIncludeFileName(fileName);
            fileName = fileName.substring(0, fileName.length() - 2);

            File folder = new File(fileName);
            if (!folder.exists() || !folder.isDirectory())
                throw new ParseException("can not find directory " + SbmUtils.toString(fileName));

            File[] files = folder.listFiles(new FileFilter() {
                //@Override
                public boolean accept(File pathname) {
                    String name = pathname.getName().toLowerCase();
                    if (name.endsWith(".xml"))
                        return true;
                    else
                        return false;
                }
            });

            if (files != null && files.length > 0) {
                docs = new Document[files.length];

                for (int i = 0; i < files.length; i++) {
                    InputStream in = null;
                    try {
                        in = new FileInputStream(files[i]);
                    } catch (Exception e) {
                        throw new ParseException("", e);
                    }

                    docs[i] = parseDocument(in);

                    if (log.isDebugEnabled())
                        log.debug("parsed Document object from " + SbmUtils.toString(files[i].getAbsolutePath()));
                }
            } else {
                if (log.isDebugEnabled())
                    log.debug("no xml file found in directory " + SbmUtils.toString(fileName));
            }
        } else {
            docs = new Document[1];
            docs[0] = parseDocument(fileName);
        }

        return docs;
    }

    /**
     * ????
     * @param fileName
     * @return
     */
    protected Document parseDocument(String fileName) {
        fileName = formatIncludeFileName(fileName);

        InputStream in = null;
        try {
            in = getClass().getClassLoader().getResourceAsStream(fileName);
        } catch (Exception e) {
        }

        if (in == null) {
            try {
                in = new FileInputStream(fileName);
            } catch (Exception e1) {
            }
        }

        if (in == null)
            throw new ParseException("can not find config file named " + SbmUtils.toString(fileName));

        Document doc = parseDocument(in);

        if (log.isDebugEnabled())
            log.debug("parsing Document object from " + SbmUtils.toString(fileName));

        return doc;
    }

    /**
     * ???
     * @param rawFileName
     * @return
     */
    protected String formatIncludeFileName(String rawFileName) {
        return rawFileName;
    }

    /**
     * ?
     * @return
     */
    protected Element getDocumentRootElement(Document doc) {
        return doc.getDocumentElement();
    }

    protected void setCurrentExecutablePrefix(String currentExecutablePrefix) {
        this.currentExecutablePrefix = currentExecutablePrefix;
    }

    /**
     * ????
     * @return
     * @date 2011-3-15
     */
    protected String getCurrentExecutablePrefix() {
        return this.currentExecutablePrefix;
    }

    /**
     * ??
     * @return
     */
    protected String getDefaultConfigFile() {
        return Constants.DEFAULT_CONFIG_FILE;
    }

    /**
     * ??null
     * ??????????null
     * @param parent
     * @param name
     * @return
     * @throws Exception
     */
    protected List<Element> getChildrenByTagName(Element parent, String name) {
        if (parent == null)
            return null;

        boolean filter = name != null;

        NodeList nl = parent.getChildNodes();

        List<Element> elements = new ArrayList<Element>();
        for (int i = 0; i < nl.getLength(); i++) {
            Node n = nl.item(i);
            if (!(n instanceof Element))
                continue;

            Element e = (Element) nl.item(i);

            if (!filter)
                elements.add(e);
            else {
                if (name.equals(e.getTagName()))
                    elements.add(e);
            }
        }

        return elements;
    }

    /**
     * ???
     * @param parent
     * @param name
     * @return
     */
    protected Element getSingleElementByTagName(Element parent, String name) {
        if (parent == null)
            return null;

        NodeList nodes = parent.getElementsByTagName(name);

        if (nodes == null || nodes.getLength() == 0)
            return null;

        return (Element) nodes.item(0);
    }

    /**
     * ??null???
     * @param o 
     * @param msg ?
     */
    protected void assertNotEmpty(Object o, String msg) {
        boolean toThrow = false;

        if (o == null)
            toThrow = true;
        else if (o instanceof String) {
            String s = (String) o;
            if (s.length() == 0)
                toThrow = true;
        }

        if (toThrow)
            throw new ParseException(msg);
    }

    /**
     * ???null
     * @param o
     * @param msg
     */
    protected void assertNotNull(Object o, String msg) {
        if (o == null)
            throw new ParseException(msg);
    }

    /**
     * ?null
     * @param element
     * @param attrName
     * @return
     */
    protected String getAttributeValueIngoreEmpty(Element element, String attrName) {
        String v = element.getAttribute(attrName);
        return v == null || v.length() == 0 ? null : v;
    }

    /**
     * ?
     * @param element
     * @param attrName
     * @return
     */
    protected String getAttributeValue(Element element, String attrName) {
        Attr attr = element.getAttributeNode(attrName);
        return attr == null ? null : attr.getValue();
    }

    /**
     * ?
     * @param element
     * @return
     */
    protected String getTextContent(Element element) {
        String re = element.getTextContent();

        return re == null || re.length() == 0 ? null : re;
    }

    /**
     * ?Arg
     * @param strArg
     * @param strType
     * @return
     * @date 2012-5-8
     */
    protected Arg stringToArg(String strArg, String strType) {
        Arg re = null;

        Type argType = null;
        if (strType != null && strType.length() > 0)
            argType = nameToType(strType);

        if (strArg == null || strArg.length() == 0)
            re = new ValueArg(strArg, argType);
        else {
            int len = strArg.length();
            char first = strArg.charAt(0);
            char end = strArg.charAt(len - 1);

            //
            if (Character.isDigit(first)) {
                Type wrappedType = (argType == null ? null : SbmUtils.wrapType(argType));

                if (Byte.class.equals(wrappedType)) {
                    re = new ValueArg(new Byte(strArg), argType);
                } else if (Short.class.equals(wrappedType)) {
                    re = new ValueArg(new Short(strArg), argType);
                } else if (Integer.class.equals(wrappedType)) {
                    re = new ValueArg(new Integer(strArg), argType);
                } else if (Long.class.equals(wrappedType)) {
                    re = new ValueArg(new Long(strArg), argType);
                } else if (Float.class.equals(wrappedType)) {
                    re = new ValueArg(new Float(strArg), argType);
                } else if (Double.class.equals(wrappedType)) {
                    re = new ValueArg(new Double(strArg), argType);
                } else if ('L' == end) {
                    re = new ValueArg(new Long(strArg.substring(0, len - 1)), Long.class);
                } else if ('l' == end) {
                    re = new ValueArg(new Long(strArg.substring(0, len - 1)), long.class);
                } else if ('F' == end) {
                    re = new ValueArg(new Float(strArg.substring(0, len - 1)), Float.class);
                } else if ('f' == end) {
                    re = new ValueArg(new Float(strArg.substring(0, len - 1)), float.class);
                } else if ('D' == end) {
                    re = new ValueArg(new Double(strArg.substring(0, len - 1)), Double.class);
                } else if ('d' == end) {
                    re = new ValueArg(new Double(strArg.substring(0, len - 1)), double.class);
                } else {
                    boolean point = strArg.indexOf('.') >= 0;

                    if (point)
                        re = new ValueArg(new Double(strArg), argType);
                    else
                        re = new ValueArg(new Integer(strArg), argType);
                }
            } else if (first == '"') {
                String ue = SbmUtils.unEscape(strArg);
                len = ue.length();

                if (len < 2 || ue.charAt(len - 1) != '"')
                    throw new ParseException("illegal String definition: " + strArg);

                if (len == 2)
                    re = new ValueArg("", argType);
                else
                    re = new ValueArg(ue.subSequence(1, len - 1), argType);
            } else if (first == '\'') {
                String ue = SbmUtils.unEscape(strArg);
                len = ue.length();

                if (len != 3 || end != '\'')
                    throw new ParseException("illegal char definition: " + strArg);

                re = new ValueArg(ue.charAt(1), argType);
            } else if ("true".equals(strArg)) {
                re = new ValueArg(Boolean.TRUE, argType);
            } else if ("false".equals(strArg)) {
                re = new ValueArg(Boolean.FALSE, argType);
            } else if ("null".equals(strArg)) {
                re = new ValueArg(null, argType);
            } else
                re = new KeyArg(strArg, argType);
        }

        return re;
    }

    /**
     * ???
     * @return
     */
    protected Configuration createConfigurationInstance() {
        return new Configuration();
    }

    protected ResolverObjectFactory createResolverObjectFactoryInstance() {
        return new DefaultResolverObjectFactory();
    }

    /**
     * ?
     * @return
     */
    protected GenericConverter createGenericConverterInstance() {
        return new DefaultGenericConverter();
    }

    /**
     * ?
     * @return
     */
    protected Interceptor createInterceptorInfoInstance() {
        return new Interceptor();
    }

    /**
     * ???
     * @return
     */
    protected Executable createExecutableInstance(String type) {
        if (TAG_ACTION.equals(type))
            return createActionIntance();
        else if (TAG_INVOKE.equals(type))
            return createInvokeIntance();
        else
            throw new ParseException("illegal Executable type <" + type + ">");
    }

    /**
     * ??
     * @return
     */
    protected Action createActionIntance() {
        return new Action();
    }

    /**
     * ??
     * @return
     */
    protected Invoke createInvokeIntance() {
        return new Invoke();
    }

    /**
     * 
     * @param clazz
     * @return
     */
    protected Object createClassInstance(String clazz) {
        try {
            return SbmUtils.narrowToClass(SbmUtils.nameToType(clazz)).newInstance();
        } catch (Exception e) {
            throw new ParseException(e);
        }
    }

    /**
     * ???
     * @param type
     * @return
     * @date 2012-5-27
     */
    protected Type nameToType(String type) {
        try {
            return SbmUtils.nameToType(type);
        } catch (Exception e) {
            throw new ParseException(e);
        }
    }

    /**
     * ????
     * @author earthangry@gmail.com
     * @date 2010-10-28
     *
     */
    protected static class ExecutableRefProxy implements Executable {
        private String refName;
        private String currentExecutablePrefix;

        public ExecutableRefProxy(String refName, String currentExecutablePrefix) {
            super();
            this.refName = refName;
            this.currentExecutablePrefix = currentExecutablePrefix;
        }

        public String getRefName() {
            return refName;
        }

        public void setRefName(String refName) {
            this.refName = refName;
        }

        public String getCurrentExecutablePrefix() {
            return currentExecutablePrefix;
        }

        public void setCurrentExecutablePrefix(String currentExecutablePrefix) {
            this.currentExecutablePrefix = currentExecutablePrefix;
        }

        //@Override
        public void execute(ObjectSource objectSource) throws ExecuteException {
            throw new UnsupportedOperationException();
        }

        //@Override
        public String getName() {
            throw new UnsupportedOperationException();
        }

        //@Override
        public String toString() {
            return Executable.class.getSimpleName() + " [name=" + refName + "]";
        }
    }
}