001/* 002 003 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 * 021 */ 022 023package org.apache.directory.api.ldap.model.subtree; 024 025 026import java.io.StringReader; 027import java.text.ParseException; 028 029import org.apache.directory.api.i18n.I18n; 030import org.apache.directory.api.ldap.model.schema.NormalizerMappingResolver; 031import org.apache.directory.api.ldap.model.schema.SchemaManager; 032import org.apache.directory.api.util.Strings; 033 034import antlr.RecognitionException; 035import antlr.TokenStreamException; 036 037 038/** 039 * A reusable wrapper around the antlr generated parser for an LDAP subtree 040 * specification as defined by <a href="http://www.faqs.org/rfcs/rfc3672.html"> 041 * RFC 3672</a>. This class enables the reuse of the antlr parser/lexer pair 042 * without having to recreate the pair every time. 043 * 044 * @see <a href="http://www.faqs.org/rfcs/rfc3672.html">RFC 3672</a> 045 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 046 */ 047public class SubtreeSpecificationParser 048{ 049 /** the antlr generated parser being wrapped */ 050 private ReusableAntlrSubtreeSpecificationParser parser; 051 052 /** the antlr generated lexer being wrapped */ 053 private ReusableAntlrSubtreeSpecificationLexer lexer; 054 055 private final boolean isNormalizing; 056 057 058 /** 059 * Creates a subtree specification parser. 060 * 061 * @param schemaManager The SchemaManager 062 */ 063 public SubtreeSpecificationParser( SchemaManager schemaManager ) 064 { 065 // place holder for the first input 066 StringReader in = new StringReader( "" ); 067 this.lexer = new ReusableAntlrSubtreeSpecificationLexer( in ); 068 this.parser = new ReusableAntlrSubtreeSpecificationParser( lexer ); 069 // this method MUST be called while we cannot do 070 // constructor overloading for antlr generated parser 071 this.parser.init( schemaManager ); 072 this.isNormalizing = false; 073 } 074 075 076 /** 077 * Creates a normalizing subtree specification parser. 078 * 079 * @param resolver The resolver to use 080 * @param schemaManager The SchemaManager 081 */ 082 public SubtreeSpecificationParser( @SuppressWarnings("rawtypes") NormalizerMappingResolver resolver, 083 SchemaManager schemaManager ) 084 { 085 // place holder for the first input 086 StringReader in = new StringReader( "" ); 087 this.lexer = new ReusableAntlrSubtreeSpecificationLexer( in ); 088 this.parser = new ReusableAntlrSubtreeSpecificationParser( lexer ); 089 this.parser.setNormalizerMappingResolver( resolver ); 090 // this method MUST be called while we cannot do 091 // constructor overloading for antlr generated parser 092 this.parser.init( schemaManager ); 093 this.isNormalizing = true; 094 } 095 096 097 /** 098 * Initializes the plumbing by creating a pipe and coupling the parser/lexer 099 * pair with it. 100 * 101 * @param spec The specification to parse 102 */ 103 private synchronized void reset( String spec ) 104 { 105 // append end of input token 106 StringReader in = new StringReader( spec + "end" ); 107 this.lexer.prepareNextInput( in ); 108 this.parser.resetState(); 109 } 110 111 112 /** 113 * Parses a subtree specification without exhausting the parser. 114 * 115 * @param spec 116 * the specification to be parsed 117 * @return the specification bean 118 * @throws ParseException 119 * if there are any recognition errors (bad syntax) 120 */ 121 public synchronized SubtreeSpecification parse( String spec ) throws ParseException 122 { 123 SubtreeSpecification ss; 124 125 if ( ( spec == null ) || Strings.isEmpty( spec.trim() ) ) 126 { 127 return null; 128 } 129 130 // reset and initialize the parser / lexer pair 131 reset( spec ); 132 133 try 134 { 135 ss = this.parser.wrapperEntryPoint(); 136 } 137 catch ( TokenStreamException | RecognitionException e ) 138 { 139 String msg = I18n.err( I18n.ERR_13028_SUBTREE_SPEC_PARSER_FAILURE, spec, e.getLocalizedMessage() ); 140 throw new ParseException( msg, 0 ); 141 } 142 143 return ss; 144 } 145 146 147 /** 148 * Tests to see if this parser is normalizing. 149 * 150 * @return true if it normalizes false otherwise 151 */ 152 public boolean isNormizing() 153 { 154 return this.isNormalizing; 155 } 156}