blob: de514b4196f5e441b6ef354a2c50447e4063239c [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.codec.api;
import org.apache.directory.api.asn1.DecoderException;
import org.apache.directory.api.asn1.ber.AbstractContainer;
import org.apache.directory.api.asn1.ber.tlv.TLV;
import org.apache.directory.api.ldap.codec.LdapMessageGrammar;
import org.apache.directory.api.ldap.codec.LdapStatesEnum;
import org.apache.directory.api.ldap.codec.search.ConnectorFilter;
import org.apache.directory.api.ldap.codec.search.Filter;
import org.apache.directory.api.ldap.codec.search.PresentFilter;
import org.apache.directory.api.ldap.model.entry.Attribute;
import org.apache.directory.api.ldap.model.entry.Modification;
import org.apache.directory.api.ldap.model.message.Control;
import org.apache.directory.api.ldap.model.message.ExtendedResponse;
import org.apache.directory.api.ldap.model.message.LdapResult;
import org.apache.directory.api.ldap.model.message.Message;
import org.apache.directory.api.ldap.model.message.ResultResponse;
/**
* The LdapMessage container stores all the messages decoded by the Asn1Decoder.
* When dealing with an encoding PDU, we will obtain a LdapMessage in the
* container.
*
* @param <E> The decorated message
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
*/
public class LdapMessageContainer<E extends Message> extends AbstractContainer
{
/** The Message being decoded */
private E message;
/** checks if attribute is binary */
private BinaryAttributeDetector binaryAttributeDetector;
/** The message ID */
private int messageId;
/** The current control */
private Control currentControl;
/** The current control factory, if any */
private ControlFactory<?> controlFactory;
/** The current Intermediate response factory */
private IntermediateOperationFactory intermediateFactory;
/** The current Extended operation factory */
private ExtendedOperationFactory extendedFactory;
/** The codec service */
private final LdapApiService codec;
/** The current LdapResult for a response */
private LdapResult ldapResult;
/** The current attribute being decoded */
private Attribute currentAttribute;
/** A local storage for the MODIFY operation */
private Modification currentModification;
/** The SearchRequest TLV id */
private int tlvId;
/** A temporary storage for a terminal Filter */
private Filter terminalFilter;
/** The current filter. This is used while decoding a PDU */
private Filter currentFilter;
/** The global filter. This is used while decoding a PDU */
private Filter topFilter;
/**
* Creates a new LdapMessageContainer object. We will store ten grammars,
* it's enough ...
*
* @param codec The LDAP service instance
*/
public LdapMessageContainer( LdapApiService codec )
{
this( codec, new DefaultConfigurableBinaryAttributeDetector() );
}
/**
* Creates a new LdapMessageContainer object.
*
* @param codec The LDAP service instance
* @param binaryAttributeDetector checks if an attribute is binary
*/
public LdapMessageContainer( LdapApiService codec, BinaryAttributeDetector binaryAttributeDetector )
{
super();
this.codec = codec;
setGrammar( LdapMessageGrammar.getInstance() );
this.binaryAttributeDetector = binaryAttributeDetector;
setTransition( LdapStatesEnum.START_STATE );
}
/**
* Gets the {@link LdapApiService} associated with this Container.
*
* @return The LDAP service instance
*/
public LdapApiService getLdapCodecService()
{
return codec;
}
/**
* @return Returns the ldapMessage.
*/
public E getMessage()
{
return message;
}
/**
* Set a Message Object into the container. It will be completed by the
* ldapDecoder.
*
* @param message The message to set.
*/
public void setMessage( E message )
{
this.message = message;
}
/**
* {@inheritDoc}
*/
@Override
public void clean()
{
super.clean();
messageId = -1;
tlvId = -1;
message = null;
ldapResult = null;
currentControl = null;
currentAttribute = null;
currentFilter = null;
terminalFilter = null;
topFilter = null;
controlFactory = null;
intermediateFactory = null;
extendedFactory = null;
setDecodedBytes( 0 );
}
/**
* @return Returns true if the attribute is binary.
* @param id checks if an attribute id is binary
*/
public boolean isBinary( String id )
{
return binaryAttributeDetector.isBinary( id );
}
/**
* @return The message ID
*/
public int getMessageId()
{
return messageId;
}
/**
* Set the message ID
* @param messageId the id of the message
*/
public void setMessageId( int messageId )
{
this.messageId = messageId;
}
/**
* @return the current control being created
*/
public Control getCurrentControl()
{
return currentControl;
}
/**
* Store a newly created control
* @param currentControl The control to store
*/
public void setCurrentControl( Control currentControl )
{
this.currentControl = currentControl;
}
/**
* Sets the binary attribute detector
*
* @param binaryAttributeDetector the binary attribute detector
*/
public void setBinaryAttributeDetector( BinaryAttributeDetector binaryAttributeDetector )
{
this.binaryAttributeDetector = binaryAttributeDetector;
}
/**
* @return the binary attribute detector
*/
public BinaryAttributeDetector getBinaryAttributeDetector()
{
return binaryAttributeDetector;
}
/**
* @return the ldapResult
*/
public LdapResult getLdapResult()
{
return ldapResult;
}
/**
* @param ldapResult the ldapResult to set
*/
public void setLdapResult( LdapResult ldapResult )
{
this.ldapResult = ldapResult;
}
/**
* @return the controlFactory
*/
public ControlFactory<?> getControlFactory()
{
return controlFactory;
}
/**
* @param controlFactory the controlFactory to set
*/
public void setControlFactory( ControlFactory<?> controlFactory )
{
this.controlFactory = controlFactory;
}
/**
* @return the currentAttribute
*/
public Attribute getCurrentAttribute()
{
return currentAttribute;
}
/**
* @param currentAttribute the currentAttribute to set
*/
public void setCurrentAttribute( Attribute currentAttribute )
{
this.currentAttribute = currentAttribute;
}
/**
* @return the currentModification
*/
public Modification getCurrentModification()
{
return currentModification;
}
/**
* @param currentModification the currentModification to set
*/
public void setCurrentModification( Modification currentModification )
{
this.currentModification = currentModification;
}
/**
* Set the SearchRequest PDU TLV's Id
* @param tlvId The TLV id
*/
public void setTlvId( int tlvId )
{
this.tlvId = tlvId;
}
/**
* @return the terminalFilter
*/
public Filter getTerminalFilter()
{
return terminalFilter;
}
/**
* @param terminalFilter the terminalFilter to set
*/
public void setTerminalFilter( Filter terminalFilter )
{
this.terminalFilter = terminalFilter;
}
/**
* @return the currentFilter
*/
public Filter getCurrentFilter()
{
return currentFilter;
}
/**
* @param currentFilter the currentFilter to set
*/
public void setCurrentFilter( Filter currentFilter )
{
this.currentFilter = currentFilter;
}
/**
* Add a current filter. We have two cases :
* - there is no previous current filter : the filter
* is the top level filter
* - there is a previous current filter : the filter is added
* to the currentFilter set, and the current filter is changed
*
* In any case, the previous current filter will always be a
* ConnectorFilter when this method is called.
*
* @param localFilter The filter to set.
* @throws DecoderException If the filter is invalid
*/
public void addCurrentFilter( Filter localFilter ) throws DecoderException
{
if ( currentFilter != null )
{
// Ok, we have a parent. The new Filter will be added to
// this parent, and will become the currentFilter if it's a connector.
( ( ConnectorFilter ) currentFilter ).addFilter( localFilter );
localFilter.setParent( currentFilter, currentFilter.getTlvId() );
if ( localFilter instanceof ConnectorFilter )
{
currentFilter = localFilter;
}
}
else
{
// No parent. This Filter will become the root.
currentFilter = localFilter;
currentFilter.setParent( null, tlvId );
topFilter = localFilter;
}
}
/**
* This method is used to clear the filter's stack for terminated elements. An element
* is considered as terminated either if :
* - it's a final element (ie an element which cannot contains a Filter)
* - its current length equals its expected length.
*/
public void unstackFilters()
{
TLV tlv = getCurrentTLV();
TLV localParent = tlv.getParent();
Filter localFilter = terminalFilter;
// The parent has been completed, so fold it
while ( ( localParent != null ) && ( localParent.getExpectedLength() == 0 ) )
{
int parentTlvId = localFilter.getParent() != null ? localFilter.getParent().getTlvId() : localFilter
.getParentTlvId();
if ( localParent.getId() != parentTlvId )
{
localParent = localParent.getParent();
}
else
{
Filter filterParent = localFilter.getParent();
// We have a special case with PresentFilter, which has not been
// pushed on the stack, so we need to get its parent's parent
if ( localFilter instanceof PresentFilter )
{
if ( filterParent == null )
{
// We don't have parent, get out
break;
}
filterParent = filterParent.getParent();
}
else
{
filterParent = filterParent.getParent();
}
if ( filterParent != null )
{
// The parent is a filter ; it will become the new currentFilter
// and we will loop again.
localFilter = currentFilter;
currentFilter = filterParent;
localParent = localParent.getParent();
}
else
{
// We can stop the recursion, we have reached the searchResult Object
break;
}
}
}
}
/**
* Copy the LdapResult element from a opaque response to a newly created
* extendedResponse
*
* @param resultResponse The original response
* @param extendedResponse The newly created ExtendedResponse
*/
public static void copyLdapResult( ResultResponse resultResponse, ExtendedResponse extendedResponse )
{
extendedResponse.getLdapResult().setDiagnosticMessage( resultResponse.getLdapResult().getDiagnosticMessage() );
extendedResponse.getLdapResult().setMatchedDn( resultResponse.getLdapResult().getMatchedDn() );
extendedResponse.getLdapResult().setReferral( resultResponse.getLdapResult().getReferral() );
extendedResponse.getLdapResult().setResultCode( resultResponse.getLdapResult().getResultCode() );
}
/**
* @return the topFilter
*/
public Filter getTopFilter()
{
return topFilter;
}
/**
* @param topFilter the topFilter to set
*/
public void setTopFilter( Filter topFilter )
{
this.topFilter = topFilter;
}
/**
* @return the tlvId
*/
public int getTlvId()
{
return tlvId;
}
/**
* @return the intermediateFactory
*/
public IntermediateOperationFactory getIntermediateFactory()
{
return intermediateFactory;
}
/**
* @param intermediateFactory the intermediateFactory to set
*/
public void setIntermediateFactory( IntermediateOperationFactory intermediateFactory )
{
this.intermediateFactory = intermediateFactory;
}
/**
* @return the extendedFactory
*/
public ExtendedOperationFactory getExtendedFactory()
{
return extendedFactory;
}
/**
* @param extendedFactory the extendedFactory to set
*/
public void setExtendedFactory( ExtendedOperationFactory extendedFactory )
{
this.extendedFactory = extendedFactory;
}
}