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