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 */ 020package org.apache.directory.shared.dsmlv2; 021 022 023import java.io.FileNotFoundException; 024import java.io.FileReader; 025import java.io.IOException; 026import java.io.InputStream; 027import java.io.Reader; 028import java.io.StringReader; 029 030import org.apache.directory.shared.dsmlv2.reponse.BatchResponseDsml; 031import org.apache.directory.shared.dsmlv2.reponse.Dsmlv2ResponseGrammar; 032import org.apache.directory.shared.i18n.I18n; 033import org.apache.directory.shared.ldap.codec.api.LdapApiService; 034import org.apache.directory.shared.ldap.model.message.Response; 035import org.xmlpull.v1.XmlPullParser; 036import org.xmlpull.v1.XmlPullParserException; 037import org.xmlpull.v1.XmlPullParserFactory; 038 039 040/** 041 * This class represents the DSMLv2 Parser. 042 * It can be used to parse a DSMLv2 Response input. 043 * 044 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 045 */ 046public class Dsmlv2ResponseParser 047{ 048 /** The associated DSMLv2 container */ 049 private Dsmlv2Container container; 050 051 052 /** 053 * Creates a new instance of Dsmlv2ResponseParser. 054 * 055 * @throws XmlPullParserException 056 * if an error occurs while the initialization of the parser 057 */ 058 public Dsmlv2ResponseParser( LdapApiService codec ) throws XmlPullParserException 059 { 060 this.container = new Dsmlv2Container( codec ); 061 062 this.container.setGrammar( Dsmlv2ResponseGrammar.getInstance() ); 063 064 XmlPullParserFactory factory = XmlPullParserFactory.newInstance(); 065 factory.setNamespaceAware( true ); 066 XmlPullParser xpp = factory.newPullParser(); 067 068 container.setParser( xpp ); 069 } 070 071 072 /** 073 * Sets the input string the parser is going to parse 074 * 075 * @param str 076 * the string the parser is going to parse 077 * @throws XmlPullParserException 078 * if an error occurs in the parser 079 */ 080 public void setInput( String str ) throws XmlPullParserException 081 { 082 container.getParser().setInput( new StringReader( str ) ); 083 } 084 085 086 /** 087 * Sets the input file the parser is going to parse 088 * 089 * @param fileName 090 * the name of the file 091 * @throws FileNotFoundException 092 * if the file does not exist 093 * @throws XmlPullParserException 094 * if an error occurs in the parser 095 */ 096 public void setInputFile( String fileName ) throws FileNotFoundException, XmlPullParserException 097 { 098 Reader reader = new FileReader( fileName ); 099 container.getParser().setInput( reader ); 100 } 101 102 103 /** 104 * Sets the input stream the parser is going to process 105 * 106 * @param inputStream 107 * contains a raw byte input stream of possibly unknown encoding (when inputEncoding is null) 108 * @param inputEncoding 109 * if not null it MUST be used as encoding for inputStream 110 * @throws XmlPullParserException 111 * if an error occurs in the parser 112 */ 113 public void setInput( InputStream inputStream, String inputEncoding ) throws XmlPullParserException 114 { 115 container.getParser().setInput( inputStream, inputEncoding ); 116 } 117 118 119 /** 120 * Launches the parsing on the input 121 * 122 * @throws XmlPullParserException 123 * when an unrecoverable error occurs 124 * @throws IOException 125 * when an IO exception occurs 126 */ 127 public void parse() throws XmlPullParserException, IOException 128 { 129 Dsmlv2ResponseGrammar grammar = Dsmlv2ResponseGrammar.getInstance(); 130 131 grammar.executeAction( container ); 132 } 133 134 135 /** 136 * Launches the parsing of the Batch Response only 137 * 138 * @throws XmlPullParserException 139 * if an error occurs in the parser 140 */ 141 public void parseBatchResponse() throws XmlPullParserException 142 { 143 XmlPullParser xpp = container.getParser(); 144 145 int eventType = xpp.getEventType(); 146 do 147 { 148 if ( eventType == XmlPullParser.START_DOCUMENT ) 149 { 150 container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE ); 151 } 152 else if ( eventType == XmlPullParser.END_DOCUMENT ) 153 { 154 container.setState( Dsmlv2StatesEnum.GRAMMAR_END ); 155 } 156 else if ( eventType == XmlPullParser.START_TAG ) 157 { 158 processTag( container, Tag.START ); 159 } 160 else if ( eventType == XmlPullParser.END_TAG ) 161 { 162 processTag( container, Tag.END ); 163 } 164 try 165 { 166 eventType = xpp.next(); 167 } 168 catch ( IOException e ) 169 { 170 throw new XmlPullParserException( I18n.err( I18n.ERR_03037, e.getLocalizedMessage() ), xpp, null ); 171 } 172 } 173 while ( container.getState() != Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP ); 174 } 175 176 177 /** 178 * Processes the task required in the grammar to the given tag type 179 * 180 * @param container 181 * the DSML container 182 * @param tagType 183 * the tag type 184 * @throws XmlPullParserException 185 * when an error occurs during the parsing 186 */ 187 private static void processTag( Dsmlv2Container container, int tagType ) throws XmlPullParserException 188 { 189 XmlPullParser xpp = container.getParser(); 190 191 String tagName = xpp.getName().toLowerCase(); 192 193 GrammarTransition transition = container.getTransition( container.getState(), new Tag( tagName, tagType ) ); 194 195 if ( transition != null ) 196 { 197 container.setState( transition.getNextState() ); 198 199 if ( transition.hasAction() ) 200 { 201 transition.getAction().action( container ); 202 } 203 } 204 else 205 { 206 throw new XmlPullParserException( I18n.err( I18n.ERR_03036, new Tag( tagName, tagType ) ), xpp, null ); 207 } 208 } 209 210 211 /** 212 * Gets the Batch Response or null if the it has not been parsed yet 213 * 214 * @return 215 * the Batch Response or null if the it has not been parsed yet 216 */ 217 public BatchResponseDsml getBatchResponse() 218 { 219 return container.getBatchResponse(); 220 } 221 222 223 /** 224 * Returns the next Request or null if there's no more request 225 * @return 226 * the next Request or null if there's no more request 227 * @throws XmlPullParserException 228 * when an error occurs during the parsing 229 */ 230 public DsmlDecorator<? extends Response> getNextResponse() throws XmlPullParserException 231 { 232 if ( container.getBatchResponse() == null ) 233 { 234 parseBatchResponse(); 235 } 236 237 XmlPullParser xpp = container.getParser(); 238 239 int eventType = xpp.getEventType(); 240 do 241 { 242 while ( eventType == XmlPullParser.TEXT ) 243 { 244 try 245 { 246 xpp.next(); 247 } 248 catch ( IOException e ) 249 { 250 throw new XmlPullParserException( I18n.err( I18n.ERR_03037, e.getLocalizedMessage() ), xpp, null ); 251 } 252 eventType = xpp.getEventType(); 253 } 254 255 if ( eventType == XmlPullParser.START_DOCUMENT ) 256 { 257 container.setState( Dsmlv2StatesEnum.INIT_GRAMMAR_STATE ); 258 } 259 else if ( eventType == XmlPullParser.END_DOCUMENT ) 260 { 261 container.setState( Dsmlv2StatesEnum.GRAMMAR_END ); 262 return null; 263 } 264 else if ( eventType == XmlPullParser.START_TAG ) 265 { 266 processTag( container, Tag.START ); 267 } 268 else if ( eventType == XmlPullParser.END_TAG ) 269 { 270 processTag( container, Tag.END ); 271 } 272 try 273 { 274 eventType = xpp.next(); 275 } 276 catch ( IOException e ) 277 { 278 throw new XmlPullParserException( I18n.err( I18n.ERR_03037, e.getLocalizedMessage() ), xpp, null ); 279 } 280 } 281 while ( container.getState() != Dsmlv2StatesEnum.BATCH_RESPONSE_LOOP ); 282 283 return container.getBatchResponse().getCurrentResponse(); 284 } 285 286 287 /** 288 * Parses all the responses 289 * 290 * @throws XmlPullParserException 291 * when an error occurs during the parsing 292 */ 293 public void parseAllResponses() throws XmlPullParserException 294 { 295 while ( getNextResponse() != null ) 296 { 297 continue; 298 } 299 } 300}