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