blob: d004b3b9263182b4f77b919f5f5e50522479f657 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.api.ldap.extras.extended.ads_impl.endTransaction;
import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.SEQUENCE;
import java.util.List;
import org.apache.directory.api.asn1.DecoderException;
import org.apache.directory.api.asn1.ber.grammar.AbstractGrammar;
import org.apache.directory.api.asn1.ber.grammar.Grammar;
import org.apache.directory.api.asn1.ber.grammar.GrammarAction;
import org.apache.directory.api.asn1.ber.grammar.GrammarTransition;
import org.apache.directory.api.asn1.ber.tlv.BerValue;
import org.apache.directory.api.asn1.ber.tlv.IntegerDecoder;
import org.apache.directory.api.asn1.ber.tlv.IntegerDecoderException;
import org.apache.directory.api.i18n.I18n;
import org.apache.directory.api.ldap.extras.extended.endTransaction.UpdateControls;
import org.apache.directory.api.ldap.model.message.Control;
import org.apache.directory.api.util.Strings;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static org.apache.directory.api.asn1.ber.tlv.UniversalTag.INTEGER;
/**
* This class implements the EndTransactionResponse extended operation's ASN.1 grammar.
* All the actions are declared in this class. As it is a singleton,
* these declaration are only done once. The grammar is :
*
* <pre>
* txnEndRes ::= SEQUENCE {
* messageID MessageID OPTIONAL,
* -- msgid associated with non-success resultCode
* updatesControls SEQUENCE OF updateControl SEQUENCE {
* messageID MessageID,
* -- msgid associated with controls
* controls Controls
* } OPTIONAL
* }
* </pre>
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class EndTransactionResponseGrammar extends AbstractGrammar<EndTransactionResponseContainer>
{
/** logger */
private static final Logger LOG = LoggerFactory.getLogger( EndTransactionResponseGrammar.class );
/** The instance of grammar. EndTransactionResponseGrammar is a singleton */
private static Grammar<EndTransactionResponseContainer> instance = new EndTransactionResponseGrammar();
/**
* Creates a new EndTransactionResponseGrammar object.
*/
@SuppressWarnings("unchecked")
public EndTransactionResponseGrammar()
{
setName( EndTransactionResponseGrammar.class.getName() );
// Create the transitions table
super.transitions = new GrammarTransition[EndTransactionResponseStates.LAST_STATE
.ordinal()][256];
/**
* Transition from init state to EndTransactionResponse Sequence
*
* txnEndRes ::= SEQUENCE {
* ...
*
* Creates the EndTransactionResponse object
*/
super.transitions[EndTransactionResponseStates.START_STATE.ordinal()][SEQUENCE.getValue()] =
new GrammarTransition<EndTransactionResponseContainer>(
EndTransactionResponseStates.START_STATE,
EndTransactionResponseStates.END_TRANSACTION_SEQUENCE_STATE,
SEQUENCE,
new GrammarAction<EndTransactionResponseContainer>( "Init EndTransactionResponse" )
{
public void action( EndTransactionResponseContainer container )
{
// May be empty
if ( container.getCurrentTLV().getLength() == 0 )
{
container.setGrammarEndAllowed( true );
}
}
} );
/**
* Transition from Sequence to messageId
*
* txnEndReq ::= SEQUENCE {
* messageID MessageID OPTIONAL,
* -- msgid associated with non-success resultCode
* ...
*
* Set the messageId into the EndTransactionResponse instance, if it's not SUCCESS.
*/
super.transitions[EndTransactionResponseStates.END_TRANSACTION_SEQUENCE_STATE.ordinal()][INTEGER.getValue()] =
new GrammarTransition<EndTransactionResponseContainer>(
EndTransactionResponseStates.END_TRANSACTION_SEQUENCE_STATE,
EndTransactionResponseStates.FAILED_MESSAGE_ID_STATE,
INTEGER,
new GrammarAction<EndTransactionResponseContainer>( "Set EndTransactionResponse failed MessageID" )
{
public void action( EndTransactionResponseContainer container ) throws DecoderException
{
BerValue value = container.getCurrentTLV().getValue();
try
{
int failedMessageId = IntegerDecoder.parse( value );
if ( failedMessageId > 0 )
{
container.getEndTransactionResponse().setFailedMessageId( failedMessageId );
}
// We may have nothing left
container.setGrammarEndAllowed( true );
}
catch ( IntegerDecoderException ide )
{
LOG.error( I18n
.err( I18n.ERR_08221_BAD_END_TRANSACTION_COMMIT, Strings.dumpBytes( value.getData() ), ide.getMessage() ) );
// This will generate a PROTOCOL_ERROR
throw new DecoderException( ide.getMessage(), ide );
}
}
} );
/**
* Transition from Sequence to updateControls
*
* txnEndReq ::= SEQUENCE {
* ...
* updatesControls SEQUENCE OF updateControls SEQUENCE {
*
* Nothing to do, just transitionning
*/
super.transitions[EndTransactionResponseStates.END_TRANSACTION_SEQUENCE_STATE.ordinal()][SEQUENCE.getValue()] =
new GrammarTransition<EndTransactionResponseContainer>(
EndTransactionResponseStates.END_TRANSACTION_SEQUENCE_STATE,
EndTransactionResponseStates.UPDATE_CONTROLS_SEQ_STATE,
SEQUENCE );
/**
* Transition from updateControls to updateControl
*
* txnEndReq ::= SEQUENCE {
* ...updateControls SEQUENCE {
*
* Create a new UpdateControls instane
*/
super.transitions[EndTransactionResponseStates.UPDATE_CONTROLS_SEQ_STATE.ordinal()][SEQUENCE.getValue()] =
new GrammarTransition<EndTransactionResponseContainer>(
EndTransactionResponseStates.UPDATE_CONTROLS_SEQ_STATE,
EndTransactionResponseStates.UPDATE_CONTROL_SEQ_STATE,
SEQUENCE,
new GrammarAction<EndTransactionResponseContainer>( "Create an updateControl" )
{
public void action( EndTransactionResponseContainer container )
{
// Create the current UpdateControls
UpdateControls currentUpdateControls = new UpdateControls();
container.setCurrentControls( currentUpdateControls );
}
} );
/**
* Transition from updateControl to messageId
*
* txnEndReq ::= SEQUENCE {
* ...
* messageID MessageID,
*
* Set the messageId into the current updateControl
*/
super.transitions[EndTransactionResponseStates.UPDATE_CONTROL_SEQ_STATE.ordinal()][INTEGER.getValue()] =
new GrammarTransition<EndTransactionResponseContainer>(
EndTransactionResponseStates.UPDATE_CONTROL_SEQ_STATE,
EndTransactionResponseStates.CONTROL_MESSAGE_ID_STATE,
INTEGER,
new GrammarAction<EndTransactionResponseContainer>( "Get the updateControl messageId" )
{
public void action( EndTransactionResponseContainer container ) throws DecoderException
{
UpdateControls currentUpdateControls = container.getCurrentUpdateControls();
BerValue value = container.getCurrentTLV().getValue();
try
{
int messageId = IntegerDecoder.parse( value );
currentUpdateControls.setMessageId( messageId );
// Make the container gather the following bytes
container.setGathering( true );
}
catch ( IntegerDecoderException ide )
{
LOG.error( I18n
.err( I18n.ERR_08222_BAD_END_TRANSACTION_MESSAGE_ID, Strings.dumpBytes( value.getData() ),
ide.getMessage() ) );
// This will generate a PROTOCOL_ERROR
throw new DecoderException( ide.getMessage(), ide );
}
}
} );
/**
* ...
* messageID MessageID,
* -- msgid associated with controls
* controls Controls
* ...
*
* Process the controls
*/
super.transitions[EndTransactionResponseStates.CONTROL_MESSAGE_ID_STATE.ordinal()][SEQUENCE.getValue()] =
new GrammarTransition<EndTransactionResponseContainer>(
EndTransactionResponseStates.CONTROL_MESSAGE_ID_STATE,
EndTransactionResponseStates.CONTROLS_STATE,
SEQUENCE,
new GrammarAction<EndTransactionResponseContainer>( "Process the controls" )
{
public void action( EndTransactionResponseContainer container ) throws DecoderException
{
BerValue value = container.getCurrentTLV().getValue();
container.setGathering( false );
try
{
List<Control> controls = EndTransactionResponseContainer.decode( value.getData() );
// Add the updateControls to the list of updateControls
UpdateControls currentUpdateControls = container.getCurrentUpdateControls();
// Add the decoder controls
currentUpdateControls.setControls( controls );
// And add the decoded updateControls to the list of updateControls
container.getEndTransactionResponse().getUpdateControls().add( currentUpdateControls );
}
catch ( DecoderException de )
{
// Add an error
LOG.error( I18n
.err( I18n.ERR_08223_INVALID_CONTROL_LIST, Strings.dumpBytes( value.getData() ),
de.getMessage() ) );
// This will generate a PROTOCOL_ERROR
throw new DecoderException( de.getMessage(), de );
}
// We may have nothing left
container.setGrammarEndAllowed( true );
}
} );
/**
* Transition from controls to updateControl
*
* txnEndReq ::= SEQUENCE {
* ...
* messageID MessageID,
*
* Loop on the updateControl
*/
super.transitions[EndTransactionResponseStates.CONTROLS_STATE.ordinal()][SEQUENCE.getValue()] =
new GrammarTransition<EndTransactionResponseContainer>(
EndTransactionResponseStates.CONTROLS_STATE,
EndTransactionResponseStates.UPDATE_CONTROL_SEQ_STATE,
SEQUENCE,
new GrammarAction<EndTransactionResponseContainer>( "Get the updateControl messageId" )
{
public void action( EndTransactionResponseContainer container )
{
// Create a new current UpdateControl
UpdateControls currentUpdateControls = new UpdateControls();
container.setCurrentControls( currentUpdateControls );
}
} );
}
/**
* This class is a singleton.
*
* @return An instance on this grammar
*/
public static Grammar<EndTransactionResponseContainer> getInstance()
{
return instance;
}
}