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.api.ldap.model.subtree; 022 023 024import java.io.StringReader; 025import java.text.ParseException; 026 027import org.apache.directory.api.i18n.I18n; 028import org.apache.directory.api.ldap.model.schema.NormalizerMappingResolver; 029import org.apache.directory.api.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 * @param schemaManager The SchemaManager 059 */ 060 public SubtreeSpecificationParser( SchemaManager schemaManager ) 061 { 062 // place holder for the first input 063 StringReader in = new StringReader( "" ); 064 this.lexer = new ReusableAntlrSubtreeSpecificationLexer( in ); 065 this.parser = new ReusableAntlrSubtreeSpecificationParser( lexer ); 066 // this method MUST be called while we cannot do 067 // constructor overloading for antlr generated parser 068 this.parser.init( schemaManager ); 069 this.isNormalizing = false; 070 } 071 072 073 /** 074 * Creates a normalizing subtree specification parser. 075 * 076 * @param resolver The resolver to use 077 * @param schemaManager The SchemaManager 078 */ 079 public SubtreeSpecificationParser( @SuppressWarnings("rawtypes") NormalizerMappingResolver resolver, 080 SchemaManager schemaManager ) 081 { 082 // place holder for the first input 083 StringReader in = new StringReader( "" ); 084 this.lexer = new ReusableAntlrSubtreeSpecificationLexer( in ); 085 this.parser = new ReusableAntlrSubtreeSpecificationParser( lexer ); 086 this.parser.setNormalizerMappingResolver( resolver ); 087 // this method MUST be called while we cannot do 088 // constructor overloading for antlr generated parser 089 this.parser.init( schemaManager ); 090 this.isNormalizing = true; 091 } 092 093 094 /** 095 * Initializes the plumbing by creating a pipe and coupling the parser/lexer 096 * pair with it. param spec the specification to be parsed 097 */ 098 private synchronized void reset( String spec ) 099 { 100 // append end of input token 101 StringReader in = new StringReader( spec + "end" ); 102 this.lexer.prepareNextInput( in ); 103 this.parser.resetState(); 104 } 105 106 107 /** 108 * Parses a subtree specification without exhausting the parser. 109 * 110 * @param spec 111 * the specification to be parsed 112 * @return the specification bean 113 * @throws ParseException 114 * if there are any recognition errors (bad syntax) 115 */ 116 public synchronized SubtreeSpecification parse( String spec ) throws ParseException 117 { 118 SubtreeSpecification ss; 119 120 if ( ( spec == null ) || ( spec.trim().length() == 0 ) ) 121 { 122 return null; 123 } 124 125 // reset and initialize the parser / lexer pair 126 reset( spec ); 127 128 try 129 { 130 ss = this.parser.wrapperEntryPoint(); 131 } 132 catch ( TokenStreamException | RecognitionException e ) 133 { 134 String msg = I18n.err( I18n.ERR_04329, spec, e.getLocalizedMessage() ); 135 throw new ParseException( msg, 0 ); 136 } 137 138 return ss; 139 } 140 141 142 /** 143 * Tests to see if this parser is normalizing. 144 * 145 * @return true if it normalizes false otherwise 146 */ 147 public boolean isNormizing() 148 { 149 return this.isNormalizing; 150 } 151}