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     */
020    
021    package org.apache.directory.shared.ldap.trigger;
022    
023    
024    import java.io.StringReader;
025    import java.text.ParseException;
026    
027    import org.apache.directory.shared.i18n.I18n;
028    import org.apache.directory.shared.ldap.schema.NormalizerMappingResolver;
029    
030    import antlr.RecognitionException;
031    import antlr.TokenStreamException;
032    
033    
034    /**
035     * A reusable wrapper around the ANTLR generated parser for a
036     * TriggerSpecification. This class enables the reuse of the antlr parser/lexer
037     * pair without having to recreate them every time.
038     * 
039     * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
040     * @version $Rev:$, $Date:$
041     */
042    public class TriggerSpecificationParser
043    {
044        /** the antlr generated parser being wrapped */
045        private ReusableAntlrTriggerSpecificationParser parser;
046    
047        /** the antlr generated lexer being wrapped */
048        private ReusableAntlrTriggerSpecificationLexer lexer;
049    
050        private final boolean isNormalizing;
051    
052    
053        /**
054         * Creates a TriggerSpecification parser.
055         */
056        public TriggerSpecificationParser()
057        {
058            this.lexer = new ReusableAntlrTriggerSpecificationLexer( new StringReader( "" ) );
059            this.parser = new ReusableAntlrTriggerSpecificationParser( lexer );
060    
061            this.parser.init(); // this method MUST be called while we cannot do
062            // constructor overloading for antlr generated parser
063            this.isNormalizing = false;
064        }
065    
066    
067        /**
068         * Creates a normalizing TriggerSpecification parser.
069         */
070        public TriggerSpecificationParser( NormalizerMappingResolver resolver )
071        {
072            this.lexer = new ReusableAntlrTriggerSpecificationLexer( new StringReader( "" ) );
073            this.parser = new ReusableAntlrTriggerSpecificationParser( lexer );
074    
075            this.parser.setNormalizerMappingResolver( resolver );
076            this.parser.init(); // this method MUST be called while we cannot do
077            // constructor overloading for ANTLR generated parser
078            this.isNormalizing = true;
079        }
080    
081    
082        /**
083         * Initializes the plumbing by creating a pipe and coupling the parser/lexer
084         * pair with it.
085         * 
086         * @param
087         *          spec the specification to be parsed
088         */
089        private synchronized void reset( String spec )
090        {
091            StringReader in = new StringReader( spec );
092            this.lexer.prepareNextInput( in );
093            this.parser.resetState();
094        }
095    
096    
097        /**
098         * Parses an TriggerSpecification without exhausting the parser.
099         * 
100         * @param spec
101         *          the specification to be parsed
102         * @return the specification bean
103         * @throws ParseException
104         *          if there are any recognition errors (bad syntax)
105         */
106        public synchronized TriggerSpecification parse( String spec ) throws ParseException
107        {
108            TriggerSpecification triggerSpecification = null;
109    
110            if ( spec == null || spec.trim().equals( "" ) )
111            {
112                return null;
113            }
114    
115            reset( spec ); // reset and initialize the parser / lexer pair
116    
117            try
118            {
119                triggerSpecification = this.parser.wrapperEntryPoint();
120            }
121            catch ( TokenStreamException e )
122            {
123                String msg = I18n.err( I18n.ERR_04333, spec, e.getLocalizedMessage() );
124                throw new ParseException( msg, 0 );
125            }
126            catch ( RecognitionException e )
127            {
128                String msg = I18n.err( I18n.ERR_04333, spec, e.getLocalizedMessage() );
129                throw new ParseException( msg, e.getColumn() );
130            }
131            
132            return triggerSpecification;
133    
134        }
135    
136    
137        /**
138         * Tests to see if this parser is normalizing.
139         * 
140         * @return true if it normalizes false otherwise
141         */
142        public boolean isNormizing()
143        {
144            return this.isNormalizing;
145        }
146    }