001/*
002 *  Licensed to the Apache Software Foundation (ASF) under one
003 *  or more contributor license agreements.  See the NOTICE file
004 *  distributed with this work for additional information
005 *  regarding copyright ownership.  The ASF licenses this file
006 *  to you under the Apache License, Version 2.0 (the
007 *  "License"); you may not use this file except in compliance
008 *  with the License.  You may obtain a copy of the License at
009 * 
010 *    http://www.apache.org/licenses/LICENSE-2.0
011 * 
012 *  Unless required by applicable law or agreed to in writing,
013 *  software distributed under the License is distributed on an
014 *  "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
015 *  KIND, either express or implied.  See the License for the
016 *  specific language governing permissions and limitations
017 *  under the License.
018 * 
019 */
020package org.apache.directory.api.dsmlv2;
021
022
023import java.io.IOException;
024import java.util.HashMap;
025
026import org.apache.directory.api.i18n.I18n;
027import org.apache.directory.api.util.Strings;
028import org.xmlpull.v1.XmlPullParser;
029import org.xmlpull.v1.XmlPullParserException;
030
031
032/**
033 * The abstract Grammar which is the Mother of all the grammars. It contains
034 * the transitions table.
035 *
036 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
037 */
038public abstract class AbstractGrammar implements Grammar
039{
040    /**
041     * Table of transitions. It's a two dimension array, the first dimension
042     * indexes the states, the second dimension indexes the Tag value, so it is
043     * 256 wide.
044     */
045    protected HashMap<Tag, GrammarTransition>[] transitions;
046
047    /** The grammar name */
048    protected String name;
049
050
051    /**
052     * Returns the grammar's name
053     * 
054     * @return The grammar name
055     */
056    public String getName()
057    {
058        return name;
059    }
060
061
062    /**
063     * Sets the grammar's name
064     * 
065     * @param name the name to set
066     */
067    public void setName( String name )
068    {
069        this.name = name;
070    }
071
072
073    /**
074     * Gets the transition associated with the state and tag
075     * 
076     * @param state The current state
077     * @param tag The current tag
078     * @return A valid transition if any, or null.
079     */
080    public GrammarTransition getTransition( Enum<Dsmlv2StatesEnum> state, Tag tag )
081    {
082        return transitions[state.ordinal()].get( tag );
083    }
084
085
086    /**
087     * Gets the states of the current grammar
088     * 
089     * @return Returns the statesEnum.
090     */
091    public Enum<Dsmlv2StatesEnum>[] getStatesEnum()
092    {
093        return Dsmlv2StatesEnum.values();
094    }
095
096
097    /**
098     * {@inheritDoc}
099     */
100    public void executeAction( Dsmlv2Container container ) throws XmlPullParserException, IOException
101    {
102        XmlPullParser xpp = container.getParser();
103
104        int eventType = xpp.getEventType();
105
106        do
107        {
108            switch ( eventType )
109            {
110                case XmlPullParser.START_DOCUMENT:
111                    container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE );
112                    break;
113
114                case XmlPullParser.END_DOCUMENT:
115                    container.setState( Dsmlv2StatesEnum.GRAMMAR_END );
116                    break;
117
118                case XmlPullParser.START_TAG:
119                    processTag( container, Tag.START );
120                    break;
121
122                case XmlPullParser.END_TAG:
123                    processTag( container, Tag.END );
124                    break;
125
126                default:
127                    break;
128            }
129
130            eventType = xpp.next();
131        }
132        while ( eventType != XmlPullParser.END_DOCUMENT );
133    }
134
135
136    /**
137     * Processes the task required in the grammar to the given tag type
138     *
139     * @param container the DSML container
140     * @param tagType the tag type
141     * @throws XmlPullParserException when an error occurs during the parsing
142     */
143    private void processTag( Dsmlv2Container container, int tagType ) throws XmlPullParserException
144    {
145        XmlPullParser xpp = container.getParser();
146
147        String tagName = Strings.toLowerCaseAscii( xpp.getName() );
148
149        GrammarTransition transition = getTransition( container.getState(), new Tag( tagName, tagType ) );
150
151        if ( transition != null )
152        {
153            container.setState( transition.getNextState() );
154
155            if ( transition.hasAction() )
156            {
157                GrammarAction action = transition.getAction();
158                action.action( container );
159            }
160        }
161        else
162        {
163            throw new XmlPullParserException( I18n.err( I18n.ERR_03036, new Tag( tagName, tagType ) ), xpp, null );
164        }
165    }
166}