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    /** The grammar's states */
051    protected Enum<Dsmlv2StatesEnum>[] statesEnum;
052
053
054    /**
055     * Returns the grammar's name
056     * 
057     * @return The grammar name
058     */
059    public String getName()
060    {
061        return name;
062    }
063
064
065    /**
066     * Sets the grammar's name
067     * 
068     * @param name the name to set
069     */
070    public void setName( String name )
071    {
072        this.name = name;
073    }
074
075
076    /**
077     * Gets the transition associated with the state and tag
078     * 
079     * @param state The current state
080     * @param tag The current tag
081     * @return A valid transition if any, or null.
082     */
083    public GrammarTransition getTransition( Enum<Dsmlv2StatesEnum> state, Tag tag )
084    {
085        return transitions[state.ordinal()].get( tag );
086    }
087
088
089    /**
090     * Gets the states of the current grammar
091     * 
092     * @return Returns the statesEnum.
093     */
094    public Enum<Dsmlv2StatesEnum>[] getStatesEnum()
095    {
096        return Dsmlv2StatesEnum.values();
097    }
098
099
100    /**
101     * {@inheritDoc}
102     */
103    public void executeAction( Dsmlv2Container container ) throws XmlPullParserException, IOException
104    {
105        XmlPullParser xpp = container.getParser();
106
107        int eventType = xpp.getEventType();
108
109        do
110        {
111            switch ( eventType )
112            {
113                case XmlPullParser.START_DOCUMENT:
114                    container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE );
115                    break;
116
117                case XmlPullParser.END_DOCUMENT:
118                    container.setState( Dsmlv2StatesEnum.GRAMMAR_END );
119                    break;
120
121                case XmlPullParser.START_TAG:
122                    processTag( container, Tag.START );
123                    break;
124
125                case XmlPullParser.END_TAG:
126                    processTag( container, Tag.END );
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.toLowerCase( 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}