com.bstek.dorado.config.text.DispatchableTextParser.java Source code

Java tutorial

Introduction

Here is the source code for com.bstek.dorado.config.text.DispatchableTextParser.java

Source

/*
 * This file is part of Dorado 7.x (http://dorado7.bsdn.org).
 * 
 * Copyright (c) 2002-2012 BSTEK Corp. All rights reserved.
 * 
 * This file is dual-licensed under the AGPLv3 (http://www.gnu.org/licenses/agpl-3.0.html) 
 * and BSDN commercial (http://www.bsdn.org/licenses) licenses.
 * 
 * If you are unsure which license is appropriate for your use, please contact the sales department
 * at http://www.bstek.com/contact.
 */

package com.bstek.dorado.config.text;

import java.util.HashMap;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import com.bstek.dorado.util.Assert;

/**
 * ?<br>
 * ??
 *
 * <pre>
 * ? ??1:1; ??2:2; ??3:3
 * </pre>
 * @author Benny Bao (mailto:benny.bao@bstek.com)
 * @since Feb 28, 2008
 */
public abstract class DispatchableTextParser implements TextParser {
    /**
     * ?????
     */
    public static final String HEADER_ATTRIBUTE = "$header";

    private static final int BEFORE_HEADER = 0;
    private static final int IN_HEADER = 1;
    private static final int AFTER_HEADER = 2;
    private static final int BEFORE_ATTRIBUTE_NAME = 3;
    private static final int IN_ATTRIBUTE_NAME = 4;
    private static final int AFTER_ATTRIBUTE_NAME = 5;
    private static final int BEFORE_ATTRIBUTE_VALUE = 6;

    /**
     * ???<br>
     * ????????WILDCARD?
     */
    public static final String WILDCARD = "*";

    private Map<String, TextParser> attributeParsers = new HashMap<String, TextParser>();
    private Map<String, TextParser> subParsers = new HashMap<String, TextParser>();

    /**
     * ?????<br>
     * ?????$header
     */
    public boolean supportsHeader() {
        return false;
    }

    /**
     * ????
     * @param constraint ?????null{@link #WILDCARD}
     *            ??
     * @param parser ?
     */
    public void registerAttributeParser(String constraint, TextParser parser) {
        Assert.notNull(parser, "[parser] is required");
        constraint = StringUtils.defaultString(constraint, WILDCARD);
        attributeParsers.put(constraint, parser);
    }

    /**
     * ?Map???
     * @return ?Map?
     */
    public Map<String, TextParser> getAttributeParsers() {
        return attributeParsers;
    }

    /**
     * ?????
     * @param constraint ??
     *            ??????WILDCARD??
     */
    protected TextParser findAttributeParser(String constraint) {
        constraint = StringUtils.defaultString(constraint, WILDCARD);
        TextParser parser = attributeParsers.get(constraint);
        if (parser == null && !WILDCARD.equals(constraint)) {
            parser = attributeParsers.get(WILDCARD);
        }
        return parser;
    }

    /**
     * ?????
     * @param constraint ????? ?nullWILDCARD??
     * @param parser ??
     */
    public void registerSubParser(String constraint, TextParser parser) {
        Assert.notNull(parser, "[parser] is required");
        constraint = StringUtils.defaultString(constraint, WILDCARD);
        subParsers.put(constraint, parser);
    }

    /**
     * ?? Map????
     * @return ??Map?
     */
    public Map<String, TextParser> getSubParsers() {
        return subParsers;
    }

    /**
     * ??????
     * @param constraint ??
     *            ??????WILDCARD??\\
     * @param context
     * @return ???
     * @throws Exception
     */
    protected TextParser findSubParser(String constraint, TextParseContext context) throws Exception {
        constraint = StringUtils.defaultString(constraint, WILDCARD);
        TextParser parser = subParsers.get(constraint);
        if (parser == null && !WILDCARD.equals(constraint)) {
            parser = subParsers.get(WILDCARD);
        }
        return parser;
    }

    /**
     * ????
     */
    protected boolean isValidPropertyNameChar(char c) {
        return (c >= '0' && c <= '9' || c >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c == '-' || c == '_'
                || c == '$');
    }

    /**
     * ??<br>
     * ??
     */
    protected boolean isIgnoredChar(char c) {
        return (c == ' ' || c == '\n' || c == '\r' || c == '\t');
    }

    /**
     * ????Map?
     */
    public Object parse(char[] charArray, TextParseContext context) throws Exception {
        return parseToAttributes(charArray, context);
    }

    /**
     * ????Map?Map??? ????
     * {@link #HEADER_ATTRIBUTE}??
     */
    protected Map<String, Object> parseToAttributes(char[] charArray, TextParseContext context) throws Exception {
        Map<String, Object> attributes = new HashMap<String, Object>();
        int status;

        if (supportsHeader()) {
            String header = parseHeader(charArray, context);
            if (header != null)
                attributes.put(HEADER_ATTRIBUTE, header);
        }

        status = BEFORE_ATTRIBUTE_NAME;
        StringBuffer nameStack = new StringBuffer();
        for (int currentIndex = context.getCurrentIndex(); currentIndex < charArray.length; currentIndex++) {
            char c = charArray[currentIndex];
            context.setCurrentIndex(currentIndex);

            switch (status) {
            case BEFORE_ATTRIBUTE_NAME:
                if (isValidPropertyNameChar(c)) {
                    status = IN_ATTRIBUTE_NAME;
                    nameStack.append(c);
                } else if (isIgnoredChar(c)) {
                    continue;
                } else if (c == ':') {
                    throw new TextParseException(charArray, context);
                }
                break;
            case IN_ATTRIBUTE_NAME:
                if (isValidPropertyNameChar(c)) {
                    nameStack.append(c);
                } else if (isIgnoredChar(c)) {
                    status = AFTER_ATTRIBUTE_NAME;
                    continue;
                } else if (c == ':') {
                    status = BEFORE_ATTRIBUTE_VALUE;
                    continue;
                } else if (c == ';') {
                    throw new TextParseException(charArray, context);
                }
                break;
            case AFTER_ATTRIBUTE_NAME:
                if (isValidPropertyNameChar(c)) {
                    throw new TextParseException(charArray, context);
                } else if (isIgnoredChar(c)) {
                    continue;
                } else if (c == ':') {
                    status = BEFORE_ATTRIBUTE_VALUE;
                    continue;
                } else if (c == ';') {
                    throw new TextParseException(charArray, context);
                }
                break;
            case BEFORE_ATTRIBUTE_VALUE:
                if (nameStack.length() == 0) {
                    throw new TextParseException("Attribute name can not be empty.", charArray, context);
                } else {
                    String name = nameStack.toString();
                    char firstC = name.charAt(0);
                    if (firstC >= '0' && firstC <= '9') {
                        throw new TextParseException("Attribute name [" + name + "] can not start with number.");
                    }

                    Object value = dispatchAttribute(name, charArray, context);
                    attributes.put(name, value);

                    currentIndex = context.getCurrentIndex();
                    status = BEFORE_ATTRIBUTE_NAME;
                    nameStack.setLength(0);
                }
                break;
            }
        }

        if (nameStack.length() > 0) {
            throw new TextParseException(charArray, context);
        }
        return attributes;
    }

    protected String parseHeader(char[] charArray, TextParseContext context) throws TextParseException {
        int status;
        status = BEFORE_HEADER;
        StringBuffer headerStack = new StringBuffer();
        int startIndex = context.getCurrentIndex();
        for (int currentIndex = startIndex; currentIndex < charArray.length
                && status != AFTER_HEADER; currentIndex++) {
            char c = charArray[currentIndex];
            context.setCurrentIndex(currentIndex);

            switch (status) {
            case BEFORE_HEADER:
                if (isIgnoredChar(c)) {
                    continue;
                } else if (c == ':' || c == ';') {
                    throw new TextParseException(charArray, context);
                } else {
                    headerStack.append(c);
                    status = IN_HEADER;
                }
                break;
            case IN_HEADER:
                if (isIgnoredChar(c)) {
                    status = AFTER_HEADER;
                } else if (c == ':' || c == ';') {
                    headerStack.setLength(0);
                    status = AFTER_HEADER;
                } else {
                    headerStack.append(c);
                }
                break;
            }
        }

        if (status != AFTER_HEADER) {
            context.increaseCurrentIndex();
        }
        String header = null;
        if (headerStack.length() > 0) {
            header = headerStack.toString();
        } else {
            context.setCurrentIndex(startIndex);
        }
        return header;
    }

    /**
     * ?????????
     * @param constraint ??
     * @param charArray ??
     * @param context ?
     * @return ?
     * @throws Exception
     */
    protected Object dispatchAttribute(String constraint, char[] charArray, TextParseContext context)
            throws Exception {
        TextParser parser = findAttributeParser(constraint);
        if (parser != null) {
            return parser.parse(charArray, context);
        } else {
            return null;
        }
    }

}