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