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 * https://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.ldap.extras.extended.ads_impl.endTransaction; 021 022 023import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.SEQUENCE; 024 025import java.util.List; 026 027import org.apache.directory.api.asn1.DecoderException; 028import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar; 029import org.apache.directory.api.asn1.ber.grammar.Grammar; 030import org.apache.directory.api.asn1.ber.grammar.GrammarAction; 031import org.apache.directory.api.asn1.ber.grammar.GrammarTransition; 032import org.apache.directory.api.asn1.ber.tlv.BerValue; 033import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder; 034import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException; 035import org.apache.directory.api.i18n.I18n; 036import org.apache.directory.api.ldap.extras.extended.endTransaction.UpdateControls; 037import org.apache.directory.api.ldap.model.message.Control; 038import org.apache.directory.api.util.Strings; 039import org.slf4j.Logger; 040import org.slf4j.LoggerFactory; 041 042import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.INTEGER; 043 044/** 045 * This class implements the EndTransactionResponse extended operation's ASN.1 grammar. 046 * All the actions are declared in this class. As it is a singleton, 047 * these declaration are only done once. The grammar is : 048 * 049 * <pre> 050 * txnEndRes ::= SEQUENCE { 051 * messageID MessageID OPTIONAL, 052 * -- msgid associated with non-success resultCode 053 * updatesControls SEQUENCE OF updateControl SEQUENCE { 054 * messageID MessageID, 055 * -- msgid associated with controls 056 * controls Controls 057 * } OPTIONAL 058 * } 059 * </pre> 060 * 061 * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> 062 */ 063public class EndTransactionResponseGrammar extends AbstractGrammar<EndTransactionResponseContainer> 064{ 065 /** logger */ 066 private static final Logger LOG = LoggerFactory.getLogger( EndTransactionResponseGrammar.class ); 067 068 /** The instance of grammar. EndTransactionResponseGrammar is a singleton */ 069 private static Grammar<EndTransactionResponseContainer> instance = new EndTransactionResponseGrammar(); 070 071 072 /** 073 * Creates a new EndTransactionResponseGrammar object. 074 */ 075 @SuppressWarnings("unchecked") 076 public EndTransactionResponseGrammar() 077 { 078 setName( EndTransactionResponseGrammar.class.getName() ); 079 080 // Create the transitions table 081 super.transitions = new GrammarTransition[EndTransactionResponseStates.LAST_STATE 082 .ordinal()][256]; 083 084 /** 085 * Transition from init state to EndTransactionResponse Sequence 086 * 087 * txnEndRes ::= SEQUENCE { 088 * ... 089 * 090 * Creates the EndTransactionResponse object 091 */ 092 super.transitions[EndTransactionResponseStates.START_STATE.ordinal()][SEQUENCE.getValue()] = 093 new GrammarTransition<EndTransactionResponseContainer>( 094 EndTransactionResponseStates.START_STATE, 095 EndTransactionResponseStates.END_TRANSACTION_SEQUENCE_STATE, 096 SEQUENCE, 097 new GrammarAction<EndTransactionResponseContainer>( "Init EndTransactionResponse" ) 098 { 099 public void action( EndTransactionResponseContainer container ) 100 { 101 // May be empty 102 if ( container.getCurrentTLV().getLength() == 0 ) 103 { 104 container.setGrammarEndAllowed( true ); 105 } 106 } 107 } ); 108 109 /** 110 * Transition from Sequence to messageId 111 * 112 * txnEndReq ::= SEQUENCE { 113 * messageID MessageID OPTIONAL, 114 * -- msgid associated with non-success resultCode 115 * ... 116 * 117 * Set the messageId into the EndTransactionResponse instance, if it's not SUCCESS. 118 */ 119 super.transitions[EndTransactionResponseStates.END_TRANSACTION_SEQUENCE_STATE.ordinal()][INTEGER.getValue()] = 120 new GrammarTransition<EndTransactionResponseContainer>( 121 EndTransactionResponseStates.END_TRANSACTION_SEQUENCE_STATE, 122 EndTransactionResponseStates.FAILED_MESSAGE_ID_STATE, 123 INTEGER, 124 new GrammarAction<EndTransactionResponseContainer>( "Set EndTransactionResponse failed MessageID" ) 125 { 126 public void action( EndTransactionResponseContainer container ) throws DecoderException 127 { 128 BerValue value = container.getCurrentTLV().getValue(); 129 130 try 131 { 132 int failedMessageId = IntegerDecoder.parse( value ); 133 134 if ( failedMessageId > 0 ) 135 { 136 container.getEndTransactionResponse().setFailedMessageId( failedMessageId ); 137 } 138 139 // We may have nothing left 140 container.setGrammarEndAllowed( true ); 141 } 142 catch ( IntegerDecoderException ide ) 143 { 144 LOG.error( I18n 145 .err( I18n.ERR_08221_BAD_END_TRANSACTION_COMMIT, Strings.dumpBytes( value.getData() ), ide.getMessage() ) ); 146 147 // This will generate a PROTOCOL_ERROR 148 throw new DecoderException( ide.getMessage(), ide ); 149 } 150 } 151 } ); 152 153 154 /** 155 * Transition from Sequence to updateControls 156 * 157 * txnEndReq ::= SEQUENCE { 158 * ... 159 * updatesControls SEQUENCE OF updateControls SEQUENCE { 160 * 161 * Nothing to do, just transitionning 162 */ 163 super.transitions[EndTransactionResponseStates.END_TRANSACTION_SEQUENCE_STATE.ordinal()][SEQUENCE.getValue()] = 164 new GrammarTransition<EndTransactionResponseContainer>( 165 EndTransactionResponseStates.END_TRANSACTION_SEQUENCE_STATE, 166 EndTransactionResponseStates.UPDATE_CONTROLS_SEQ_STATE, 167 SEQUENCE ); 168 169 170 /** 171 * Transition from updateControls to updateControl 172 * 173 * txnEndReq ::= SEQUENCE { 174 * ...updateControls SEQUENCE { 175 * 176 * Create a new UpdateControls instane 177 */ 178 super.transitions[EndTransactionResponseStates.UPDATE_CONTROLS_SEQ_STATE.ordinal()][SEQUENCE.getValue()] = 179 new GrammarTransition<EndTransactionResponseContainer>( 180 EndTransactionResponseStates.UPDATE_CONTROLS_SEQ_STATE, 181 EndTransactionResponseStates.UPDATE_CONTROL_SEQ_STATE, 182 SEQUENCE, 183 new GrammarAction<EndTransactionResponseContainer>( "Create an updateControl" ) 184 { 185 public void action( EndTransactionResponseContainer container ) 186 { 187 // Create the current UpdateControls 188 UpdateControls currentUpdateControls = new UpdateControls(); 189 190 container.setCurrentControls( currentUpdateControls ); 191 } 192 } ); 193 194 195 /** 196 * Transition from updateControl to messageId 197 * 198 * txnEndReq ::= SEQUENCE { 199 * ... 200 * messageID MessageID, 201 * 202 * Set the messageId into the current updateControl 203 */ 204 super.transitions[EndTransactionResponseStates.UPDATE_CONTROL_SEQ_STATE.ordinal()][INTEGER.getValue()] = 205 new GrammarTransition<EndTransactionResponseContainer>( 206 EndTransactionResponseStates.UPDATE_CONTROL_SEQ_STATE, 207 EndTransactionResponseStates.CONTROL_MESSAGE_ID_STATE, 208 INTEGER, 209 new GrammarAction<EndTransactionResponseContainer>( "Get the updateControl messageId" ) 210 { 211 public void action( EndTransactionResponseContainer container ) throws DecoderException 212 { 213 UpdateControls currentUpdateControls = container.getCurrentUpdateControls(); 214 BerValue value = container.getCurrentTLV().getValue(); 215 216 try 217 { 218 int messageId = IntegerDecoder.parse( value ); 219 220 currentUpdateControls.setMessageId( messageId ); 221 222 // Make the container gather the following bytes 223 container.setGathering( true ); 224 } 225 catch ( IntegerDecoderException ide ) 226 { 227 LOG.error( I18n 228 .err( I18n.ERR_08222_BAD_END_TRANSACTION_MESSAGE_ID, Strings.dumpBytes( value.getData() ), 229 ide.getMessage() ) ); 230 231 // This will generate a PROTOCOL_ERROR 232 throw new DecoderException( ide.getMessage(), ide ); 233 } 234 } 235 } ); 236 237 238 /** 239 * ... 240 * messageID MessageID, 241 * -- msgid associated with controls 242 * controls Controls 243 * ... 244 * 245 * Process the controls 246 */ 247 super.transitions[EndTransactionResponseStates.CONTROL_MESSAGE_ID_STATE.ordinal()][SEQUENCE.getValue()] = 248 new GrammarTransition<EndTransactionResponseContainer>( 249 EndTransactionResponseStates.CONTROL_MESSAGE_ID_STATE, 250 EndTransactionResponseStates.CONTROLS_STATE, 251 SEQUENCE, 252 new GrammarAction<EndTransactionResponseContainer>( "Process the controls" ) 253 { 254 public void action( EndTransactionResponseContainer container ) throws DecoderException 255 { 256 BerValue value = container.getCurrentTLV().getValue(); 257 258 container.setGathering( false ); 259 260 try 261 { 262 List<Control> controls = EndTransactionResponseContainer.decode( value.getData() ); 263 264 // Add the updateControls to the list of updateControls 265 UpdateControls currentUpdateControls = container.getCurrentUpdateControls(); 266 267 // Add the decoder controls 268 currentUpdateControls.setControls( controls ); 269 270 // And add the decoded updateControls to the list of updateControls 271 container.getEndTransactionResponse().getUpdateControls().add( currentUpdateControls ); 272 } 273 catch ( DecoderException de ) 274 { 275 // Add an error 276 LOG.error( I18n 277 .err( I18n.ERR_08223_INVALID_CONTROL_LIST, Strings.dumpBytes( value.getData() ), 278 de.getMessage() ) ); 279 280 // This will generate a PROTOCOL_ERROR 281 throw new DecoderException( de.getMessage(), de ); 282 } 283 284 // We may have nothing left 285 container.setGrammarEndAllowed( true ); 286 } 287 } ); 288 289 290 /** 291 * Transition from controls to updateControl 292 * 293 * txnEndReq ::= SEQUENCE { 294 * ... 295 * messageID MessageID, 296 * 297 * Loop on the updateControl 298 */ 299 super.transitions[EndTransactionResponseStates.CONTROLS_STATE.ordinal()][SEQUENCE.getValue()] = 300 new GrammarTransition<EndTransactionResponseContainer>( 301 EndTransactionResponseStates.CONTROLS_STATE, 302 EndTransactionResponseStates.UPDATE_CONTROL_SEQ_STATE, 303 SEQUENCE, 304 new GrammarAction<EndTransactionResponseContainer>( "Get the updateControl messageId" ) 305 { 306 public void action( EndTransactionResponseContainer container ) 307 { 308 // Create a new current UpdateControl 309 UpdateControls currentUpdateControls = new UpdateControls(); 310 311 container.setCurrentControls( currentUpdateControls ); 312 } 313 } ); 314 } 315 316 317 /** 318 * This class is a singleton. 319 * 320 * @return An instance on this grammar 321 */ 322 public static Grammar<EndTransactionResponseContainer> getInstance() 323 { 324 return instance; 325 } 326}