de.rrze.idmone.utils.jidgen.template.Parser.java Source code

Java tutorial

Introduction

Here is the source code for de.rrze.idmone.utils.jidgen.template.Parser.java

Source

/*
 * jidgen, developed as a part of the IDMOne project at RRZE.
 * Copyright 2008, RRZE, and individual contributors
 * as indicated by the @author tags. See the copyright.txt file in the
 * distribution for a full listing of individual contributors. This
 * product includes software developed by the Apache Software Foundation
 * http://www.apache.org/
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */

package de.rrze.idmone.utils.jidgen.template;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import de.rrze.idmone.utils.jidgen.Messages;

/**
 * Parser class for the IdGenerator's template
 * system.<br />
 * All parsing and conversion to element objects
 * is done here.
 * 
 * @author unrza249
 *
 */
public class Parser {

    /**
     *  The class logger
     */
    private static final Log logger = LogFactory.getLog(Parser.class);

    /**
     * The delimiter string that marks the end of one
     * and the beginning of another template element in
     * the template string.
     */
    private static final String ELEMENT_DELIMITER = ":";

    /**
     * This is a flag indicating whether or not the
     * already parsed elements contain a counter element.
     * It is used to limit the number of counter elements to one.
     * <b>Only used internally. Will be removed in future versions</b>
     */
    private static boolean hasCounterElement;

    /**
     * Processes the given template string by splitting it into its
     * parts and parse each part to compile a list of according 
     * element objects.<br/>
     * Those are used by the template class to finally build the
     * result string.
     * 
     * @param template
     *          the template string to process
     * @return   a list of elements representing the element parts inside
     *          the template string
     */
    public static ArrayList<IElement> getElements(String template) {

        // reset the hasCounter flag
        hasCounterElement = false;

        // init elements array
        ArrayList<IElement> elements = new ArrayList<IElement>();

        // split into parts (which later become elements)
        ArrayList<String> parts = new ArrayList<String>(Arrays.asList(template.split(ELEMENT_DELIMITER)));
        //logger.debug(parts.toString());

        boolean isResolver;

        // process the parts - here starts the fun ;)
        for (Iterator<String> iter = parts.iterator(); iter.hasNext();) {
            String currentPart = iter.next();

            /*
             * ALTERNATIVE / RESOLVER 
             */
            Matcher m = getMatcher("^\\[(.*)\\]$", currentPart);
            if (m.matches()) {
                logger.debug(
                        Messages.getString("Parser.MATCHED_PATTERN") + m.pattern() + " => ALTERNATIVE/RESOLVER");
                isResolver = true;
                currentPart = m.group(1);
            } else {
                isResolver = false;
            }

            // parse and get the element instance
            IElement element = Parser.parse(currentPart);

            // set the resolver status
            element.setResolver(isResolver);

            // add the element
            elements.add(element);
        }

        return elements;
    }

    /**
     * Helper class for the getElements() method that
     * matches the given element part string against
     * all known element patterns to determine which
     * element implementation to use.
     *  
     * @param part
     *          the element part string to match against
     * @return   a matching element object, representing the
     *          given element part string
     */
    private static IElement parse(String part) {
        logger.debug(Messages.getString("Parser.PROCESSING_PART") + part);

        Matcher m;

        /*
         * BASIC
         */

        // Basic (e.g. a)
        m = getMatcher("^([a-zA-Z])$", part);
        if (m.matches()) {
            logger.debug(Messages.getString("Parser.MATCHED_PATTERN") + m.pattern() + " => BASIC");
            return new BasicElement(m.group(1), m.group(1));
        }

        /*
         * STATIC
         */

        // Static (e.g. =my_prefix)
        m = getMatcher("^(=([a-zA-Z_0-9]*))$", part);
        if (m.matches()) {
            logger.debug(Messages.getString("Parser.MATCHED_PATTERN") + m.pattern() + " => STATIC");
            return new StaticElement(m.group(1), m.group(2));
        }

        /*
         * RANDOM
         */

        // Random - exactly one (e.g. a+) or as many as specified by repetation (e.g. aaa+)
        m = getMatcher("^(([a-zA-Z])(\\2*)\\+)$", part);
        if (m.matches()) {
            int length = m.group(3).length() + 1;
            logger.debug(Messages.getString("Parser.MATCHED_PATTERN") + m.pattern() + " => RANDOM (length=" + length
                    + ")");
            return new RandomElement(m.group(1), m.group(2), length);
        }

        // Random - as many as specified by number (e.g. a3+) - zero or leading zeros are forbidden!
        m = getMatcher("^(([a-zA-Z])([1-9][0-9]*)\\+)$", part);
        if (m.matches()) {
            int length = Integer.parseInt(m.group(3));
            logger.debug(Messages.getString("Parser.MATCHED_PATTERN") + m.pattern() + " => RANDOM (length=" + length
                    + ")");
            return new RandomElement(m.group(1), m.group(2), length);
        }

        /*
         * SUBSTRING
         */

        // Substring (e.g. 1a)
        m = getMatcher("^(([1-9])([a-zA-Z]))$", part);
        if (m.matches()) {
            logger.debug(Messages.getString("Parser.MATCHED_PATTERN") + m.pattern()
                    + " => SUBSTRING (first x characters)");
            return new SubstringElement(m.group(1), m.group(3), 1, Integer.parseInt(m.group(2)));
        }

        // Substring (e.g. a1)
        m = getMatcher("^(([a-zA-Z])([1-9]))$", part);
        if (m.matches()) {
            logger.debug(Messages.getString("Parser.MATCHED_PATTERN") + m.pattern()
                    + " => SUBSTRING (last x characters)");
            return new SubstringElement(m.group(1), m.group(2), -1, // this is special and indicates that
                    // the last x (stored in the end parameter) characters
                    // are to be used
                    Integer.parseInt(m.group(3)));
        }

        // Substring (e.g. 1a5)
        m = getMatcher("^(([1-9])([a-zA-Z])([1-9]))$", part);
        if (m.matches()) {
            logger.debug(Messages.getString("Parser.MATCHED_PATTERN") + m.pattern() + " => SUBSTRING (start, end)");
            return new SubstringElement(m.group(1), m.group(3), Integer.parseInt(m.group(2)),
                    Integer.parseInt(m.group(4)));
        }

        // Substring with start and end (e.g. a1,5)
        m = getMatcher("^(([a-zA-Z])([1-9]),([1-9]))$", part);
        if (m.matches()) {
            logger.debug(Messages.getString("Parser.MATCHED_PATTERN") + m.pattern() + " => SUBSTRING (start, end)");
            int end = Integer.parseInt(m.group(4));
            return new SubstringElement(m.group(1), m.group(2), Integer.parseInt(m.group(3)), (end <= 0) ? -1 : end // this is just to be as kind as possible to the user
            // -> even negative end values are interpreted
            );
        }

        // Substring (e.g. a1,)
        m = getMatcher("^(([a-zA-Z])([1-9]),)$", part);
        if (m.matches()) {
            logger.debug(Messages.getString("Parser.MATCHED_PATTERN") + m.pattern()
                    + " => SUBSTRING (start at x until end of the string)");
            return new SubstringElement(m.group(1), m.group(2), Integer.parseInt(m.group(3)), -1);
        }

        // Substring (e.g. a,1)
        m = getMatcher("^(([a-zA-Z]),([1-9]))$", part);
        if (m.matches()) {
            logger.debug(Messages.getString("Parser.MATCHED_PATTERN") + m.pattern()
                    + " => SUBSTRING (first x characters)");
            return new SubstringElement(m.group(1), m.group(2), 1, Integer.parseInt(m.group(3)));
        }

        /*
         * COUNTER
         */

        // Counter - exactly one (e.g. a++) or as many as specified by repetation (e.g. aaa++)
        m = getMatcher("^(([a-zA-Z])(\\2*)\\+\\+)$", part);
        if (m.matches()) {

            // limit number of counter elements to one
            if (Parser.hasCounterElement == true) {
                logger.fatal(Messages.getString("Parser.ONLY_ONE_COUNTER_ELEMENT_ALLOWED"));
                System.exit(171);
            }
            Parser.hasCounterElement = true;

            int length = m.group(3).length() + 1;
            logger.debug(Messages.getString("Parser.MATCHED_PATTERN") + m.pattern() + " => COUNTER (length="
                    + length + ")");
            return new CounterElement(m.group(1), m.group(2), length);
        }

        // Counter - as many as specified by number (e.g. a3++) - zero or leading zeros are forbidden!
        m = getMatcher("^(([a-zA-Z])([1-9][0-9]*)\\+\\+)$", part);
        if (m.matches()) {
            int length = Integer.parseInt(m.group(3));
            logger.debug(Messages.getString("Parser.MATCHED_PATTERN") + m.pattern() + " => COUNTER (length="
                    + length + ")");
            return new CounterElement(m.group(1), m.group(2), length);
        }

        /*
         * IF WE ARE HERE, NONE OF THE ABOVE PATTERNS HAS MATCHED!
         */

        logger.fatal(Messages.getString("Parser.NO_MATCHING_ELEMENT_FOUND") + part);
        System.exit(170);
        return null;
    }

    private static Matcher getMatcher(String pattern, String matchee) {
        Pattern p = Pattern.compile(pattern);
        Matcher m = p.matcher(matchee);
        return m;
    }

}