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    @Override
057    public String getName()
058    {
059        return name;
060    }
061
062
063    /**
064     * Sets the grammar's name
065     * 
066     * @param name the name to set
067     */
068    @Override
069    public void setName( String name )
070    {
071        this.name = name;
072    }
073
074
075    /**
076     * Gets the transition associated with the state and tag
077     * 
078     * @param state The current state
079     * @param tag The current tag
080     * @return A valid transition if any, or null.
081     */
082    public GrammarTransition getTransition( Enum<Dsmlv2StatesEnum> state, Tag tag )
083    {
084        return transitions[state.ordinal()].get( tag );
085    }
086
087
088    /**
089     * Gets the states of the current grammar
090     * 
091     * @return Returns the statesEnum.
092     */
093    @Override
094    public Enum<Dsmlv2StatesEnum>[] getStatesEnum()
095    {
096        return Dsmlv2StatesEnum.values();
097    }
098
099
100    /**
101     * {@inheritDoc}
102     */
103    @Override
104    public void executeAction( Dsmlv2Container container ) throws XmlPullParserException, IOException
105    {
106        XmlPullParser xpp = container.getParser();
107
108        int eventType = xpp.getEventType();
109
110        do
111        {
112            switch ( eventType )
113            {
114                case XmlPullParser.START_DOCUMENT:
115                    container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE );
116                    break;
117
118                case XmlPullParser.END_DOCUMENT:
119                    container.setState( Dsmlv2StatesEnum.GRAMMAR_END );
120                    break;
121
122                case XmlPullParser.START_TAG:
123                    processTag( container, Tag.START );
124                    break;
125
126                case XmlPullParser.END_TAG:
127                    processTag( container, Tag.END );
128                    break;
129
130                default:
131                    break;
132            }
133
134            eventType = xpp.next();
135        }
136        while ( eventType != XmlPullParser.END_DOCUMENT );
137    }
138
139
140    /**
141     * Processes the task required in the grammar to the given tag type
142     *
143     * @param container the DSML container
144     * @param tagType the tag type
145     * @throws XmlPullParserException when an error occurs during the parsing
146     */
147    private void processTag( Dsmlv2Container container, int tagType ) throws XmlPullParserException
148    {
149        XmlPullParser xpp = container.getParser();
150
151        String tagName = Strings.toLowerCaseAscii( xpp.getName() );
152
153        GrammarTransition transition = getTransition( container.getState(), new Tag( tagName, tagType ) );
154
155        if ( transition != null )
156        {
157            container.setState( transition.getNextState() );
158
159            if ( transition.hasAction() )
160            {
161                GrammarAction action = transition.getAction();
162                action.action( container );
163            }
164        }
165        else
166        {
167            throw new XmlPullParserException( I18n.err( I18n.ERR_03036_MISSING_TAG, new Tag( tagName, tagType ) ), xpp, null );
168        }
169    }
170}