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.shared.dsmlv2;
021
022
023import java.io.IOException;
024import java.util.HashMap;
025
026import org.apache.directory.shared.i18n.I18n;
027import org.xmlpull.v1.XmlPullParser;
028import org.xmlpull.v1.XmlPullParserException;
029
030
031/**
032 * The abstract IGrammar which is the Mother of all the grammars. It contains
033 * the transitions table.
034 *
035 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
036 */
037public abstract class AbstractGrammar implements Grammar
038{
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     * Return the grammar's name
056     * 
057     * @return The grammar name
058     */
059    public String getName()
060    {
061        return name;
062    }
063
064
065    /**
066     * Set the grammar's name
067     * 
068     * @param name
069     *      the name to set
070     */
071    public void setName( String name )
072    {
073        this.name = name;
074    }
075
076
077    /**
078     * Get the transition associated with the state and tag
079     * 
080     * @param state
081     *            The current state
082     * @param tag
083     *            The current tag
084     * @return A valid transition if any, or null.
085     */
086    public GrammarTransition getTransition( Enum<Dsmlv2StatesEnum> state, Tag tag )
087    {
088        return transitions[state.ordinal()].get( tag );
089    }
090
091
092    /**
093     * Get the states of the current grammar
094     * 
095     * @return 
096     *      Returns the statesEnum.
097     */
098    public Enum<Dsmlv2StatesEnum>[] getStatesEnum()
099    {
100        return Dsmlv2StatesEnum.values();
101    }
102
103
104    /**
105     * Set the states for this grammar
106     * 
107     * @param statesEnum
108     *      The statesEnum to set.
109     */
110    public void setStatesEnum( Enum<Dsmlv2StatesEnum>[] statesEnum )
111    {
112        this.statesEnum = statesEnum;
113    }
114
115
116    /**
117     * {@inheritDoc}
118     */
119    public void executeAction( Dsmlv2Container container ) throws XmlPullParserException, IOException
120    {
121        XmlPullParser xpp = container.getParser();
122
123        int eventType = xpp.getEventType();
124
125        do
126        {
127            if ( eventType == XmlPullParser.START_DOCUMENT )
128            {
129                container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE );
130            }
131            else if ( eventType == XmlPullParser.END_DOCUMENT )
132            {
133                container.setState( Dsmlv2StatesEnum.GRAMMAR_END );
134            }
135            else if ( eventType == XmlPullParser.START_TAG )
136            {
137                processTag( container, Tag.START );
138            }
139            else if ( eventType == XmlPullParser.END_TAG )
140            {
141                processTag( container, Tag.END );
142            }
143
144            eventType = xpp.next();
145        }
146        while ( eventType != XmlPullParser.END_DOCUMENT );
147    }
148
149
150    /**
151     * Processes the task required in the grammar to the given tag type
152     *
153     * @param container
154     *      the DSML container
155     * @param tagType
156     *      the tag type
157     * @throws XmlPullParserException 
158     *      when an error occurs during the parsing
159     */
160    private void processTag( Dsmlv2Container container, int tagType ) throws XmlPullParserException
161    {
162        XmlPullParser xpp = container.getParser();
163
164        String tagName = xpp.getName().toLowerCase();
165
166        GrammarTransition transition = getTransition( container.getState(), new Tag( tagName, tagType ) );
167
168        if ( transition != null )
169        {
170            container.setState( transition.getNextState() );
171
172            if ( transition.hasAction() )
173            {
174                GrammarAction action = transition.getAction();
175                action.action( container );
176            }
177        }
178        else
179        {
180            throw new XmlPullParserException( I18n.err( I18n.ERR_03036, new Tag( tagName, tagType ) ), xpp, null );
181        }
182    }
183}