| /* |
| * 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 |
| * |
| * http://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.shared.ldap.codec; |
| |
| |
| import java.nio.BufferOverflowException; |
| import java.nio.ByteBuffer; |
| import java.util.ArrayList; |
| import java.util.HashMap; |
| import java.util.List; |
| import java.util.Map; |
| |
| import org.apache.directory.shared.asn1.AbstractAsn1Object; |
| import org.apache.directory.shared.asn1.ber.tlv.TLV; |
| import org.apache.directory.shared.asn1.ber.tlv.UniversalTag; |
| import org.apache.directory.shared.asn1.ber.tlv.Value; |
| import org.apache.directory.shared.asn1.codec.EncoderException; |
| import org.apache.directory.shared.i18n.I18n; |
| import org.apache.directory.shared.ldap.codec.controls.CodecControl; |
| import org.apache.directory.shared.ldap.codec.controls.ManageDsaITControl; |
| import org.apache.directory.shared.ldap.codec.controls.replication.syncDoneValue.SyncDoneValueControl; |
| import org.apache.directory.shared.ldap.codec.controls.replication.syncInfoValue.SyncInfoValueControl; |
| import org.apache.directory.shared.ldap.codec.controls.replication.syncRequestValue.SyncRequestValueControl; |
| import org.apache.directory.shared.ldap.codec.controls.replication.syncStateValue.SyncStateValueControl; |
| import org.apache.directory.shared.ldap.codec.search.controls.pagedSearch.PagedResultsControl; |
| import org.apache.directory.shared.ldap.codec.search.controls.persistentSearch.PersistentSearchControl; |
| import org.apache.directory.shared.ldap.codec.search.controls.subentries.SubentriesControl; |
| import org.apache.directory.shared.ldap.message.control.Control; |
| import org.apache.directory.shared.ldap.message.control.replication.SynchronizationInfoEnum; |
| |
| |
| /** |
| * The main ldapObject : every Ldap Message are encapsulated in it. It contains |
| * a message Id, a operation (protocolOp) and one ore more Controls. |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| * @version $Rev$, $Date$, |
| */ |
| public abstract class LdapMessageCodec extends AbstractAsn1Object |
| { |
| // ~ Instance fields |
| // ---------------------------------------------------------------------------- |
| |
| /** The message ID */ |
| private int messageId; |
| |
| /** The controls */ |
| private List<Control> controls; |
| |
| /** The current control */ |
| private Control currentControl; |
| |
| /** The LdapMessage length */ |
| protected int ldapMessageLength; |
| |
| /** The controls length */ |
| private int controlsLength; |
| |
| /** The controls sequence length */ |
| private int controlsSequenceLength; |
| |
| private static Map<String, Control> codecControls = new HashMap<String, Control>(); |
| |
| static |
| { |
| // Initialize the different known Controls |
| Control control = new PersistentSearchControl(); |
| codecControls.put( control.getOid(), control ); |
| |
| control = new ManageDsaITControl(); |
| codecControls.put( control.getOid(), control ); |
| |
| control = new SubentriesControl(); |
| codecControls.put( control.getOid(), control ); |
| |
| control = new PagedResultsControl(); |
| codecControls.put( control.getOid(), control ); |
| |
| control = new SyncDoneValueControl(); |
| codecControls.put( control.getOid(), control ); |
| |
| control = new SyncInfoValueControl( SynchronizationInfoEnum.NEW_COOKIE ); |
| codecControls.put( control.getOid(), control ); |
| |
| control = new SyncInfoValueControl( SynchronizationInfoEnum.REFRESH_DELETE ); |
| codecControls.put( control.getOid(), control ); |
| |
| control = new SyncInfoValueControl( SynchronizationInfoEnum.REFRESH_PRESENT ); |
| codecControls.put( control.getOid(), control ); |
| |
| control = new SyncInfoValueControl( SynchronizationInfoEnum.SYNC_ID_SET ); |
| codecControls.put( control.getOid(), control ); |
| |
| control = new SyncRequestValueControl(); |
| codecControls.put( control.getOid(), control ); |
| |
| control = new SyncStateValueControl(); |
| codecControls.put( control.getOid(), control ); |
| } |
| |
| |
| // ~ Constructors |
| // ------------------------------------------------------------------------------- |
| |
| /** |
| * Creates a new LdapMessage object. |
| */ |
| public LdapMessageCodec() |
| { |
| // We should not create this kind of object directly |
| super(); |
| } |
| |
| |
| // ~ Methods |
| // ------------------------------------------------------------------------------------ |
| |
| /** |
| * Get the Control Object at a specific index |
| * |
| * @param i The index of the Control Object to get |
| * @return The selected Control Object |
| */ |
| public Control getControls( int i ) |
| { |
| if ( controls != null ) |
| { |
| return controls.get( i ); |
| } |
| else |
| { |
| return null; |
| } |
| } |
| |
| |
| /** |
| * Get the Control Objects |
| * |
| * @return The Control Objects |
| */ |
| public List<Control> getControls() |
| { |
| return controls; |
| } |
| |
| |
| /** |
| * Get the current Control Object |
| * |
| * @return The current Control Object |
| */ |
| public Control getCurrentControl() |
| { |
| return currentControl; |
| } |
| |
| |
| public Control getCodecControl( String oid ) |
| { |
| return codecControls.get( oid ); |
| } |
| |
| |
| /** |
| * Add a control to the Controls array |
| * |
| * @param control The Control to add |
| */ |
| public void addControl( Control control ) |
| { |
| currentControl = control; |
| |
| if ( controls == null ) |
| { |
| controls = new ArrayList<Control>(); |
| } |
| |
| controls.add( control ); |
| } |
| |
| |
| /** |
| * Set or add a list of controls to the Controls array. If the existing |
| * control array is not null then the given controls will be added |
| * |
| * @param controls The list of Controls to set or add |
| */ |
| public void addControls( List<Control> controls ) |
| { |
| if( this.controls == null ) |
| { |
| this.controls = controls; |
| } |
| else if( controls != null ) |
| { |
| this.controls.addAll( controls ); |
| } |
| } |
| |
| |
| /** |
| * Init the controls array |
| */ |
| public void initControls() |
| { |
| controls = new ArrayList<Control>(); |
| } |
| |
| |
| /** |
| * Get the message ID |
| * |
| * @return The message ID |
| */ |
| public int getMessageId() |
| { |
| return messageId; |
| } |
| |
| |
| /** |
| * Set the message ID |
| * |
| * @param messageId The message ID |
| */ |
| public void setMessageId( int messageId ) |
| { |
| this.messageId = messageId; |
| } |
| |
| |
| /** |
| * Get the message type |
| * |
| * @return The message type |
| */ |
| public abstract MessageTypeEnum getMessageType(); |
| |
| |
| /** |
| * Get the message type Name |
| * |
| * @return The message type name |
| */ |
| public abstract String getMessageTypeName(); |
| |
| |
| protected abstract int computeLengthProtocolOp(); |
| |
| |
| /** |
| * Compute the LdapMessage length LdapMessage : |
| * 0x30 L1 |
| * | |
| * +--> 0x02 0x0(1-4) [0..2^31-1] (MessageId) |
| * +--> protocolOp |
| * [+--> Controls] |
| * |
| * MessageId length = Length(0x02) + length(MessageId) + MessageId.length |
| * L1 = length(ProtocolOp) |
| * LdapMessage length = Length(0x30) + Length(L1) + MessageId length + L1 |
| */ |
| public int computeLength() |
| { |
| // The length of the MessageId. It's the sum of |
| // - the tag (0x02), 1 byte |
| // - the length of the Id length, 1 byte |
| // - the Id length, 1 to 4 bytes |
| ldapMessageLength = 1 + 1 + Value.getNbBytes( messageId ); |
| |
| // Get the protocolOp length |
| int protocolOpLength = computeLengthProtocolOp(); |
| |
| // Add the protocol length to the message length |
| ldapMessageLength += protocolOpLength; |
| |
| // Do the same thing for Controls, if any. |
| if ( controls != null ) |
| { |
| // Controls : |
| // 0xA0 L3 |
| // | |
| // +--> 0x30 L4 |
| // +--> 0x30 L5 |
| // +--> ... |
| // +--> 0x30 Li |
| // +--> ... |
| // +--> 0x30 Ln |
| // |
| // L3 = Length(0x30) + Length(L5) + L5 |
| // + Length(0x30) + Length(L6) + L6 |
| // + ... |
| // + Length(0x30) + Length(Li) + Li |
| // + ... |
| // + Length(0x30) + Length(Ln) + Ln |
| // |
| // LdapMessageLength = LdapMessageLength + Length(0x90) |
| // + Length(L3) + L3 |
| controlsSequenceLength = 0; |
| |
| // We may have more than one control. ControlsLength is L4. |
| for ( Control control:controls ) |
| { |
| controlsSequenceLength += ((CodecControl)control).computeLength(); |
| } |
| |
| // Computes the controls length |
| controlsLength = controlsSequenceLength; // 1 + Length.getNbBytes( |
| // controlsSequenceLength |
| // ) + controlsSequenceLength; |
| |
| // Now, add the tag and the length of the controls length |
| ldapMessageLength += 1 + TLV.getNbBytes( controlsSequenceLength ) + controlsSequenceLength; |
| } |
| |
| // finally, calculate the global message size : |
| // length(Tag) + Length(length) + length |
| |
| return 1 + ldapMessageLength + TLV.getNbBytes( ldapMessageLength ); |
| } |
| |
| |
| protected abstract void encodeProtocolOp( ByteBuffer buffer ) throws EncoderException; |
| |
| /** |
| * Generate the PDU which contains the encoded object. |
| * |
| * The generation is done in two phases : |
| * - first, we compute the length of each part and the |
| * global PDU length |
| * - second, we produce the PDU. |
| * |
| * <pre> |
| * 0x30 L1 |
| * | |
| * +--> 0x02 L2 MessageId |
| * +--> ProtocolOp |
| * +--> Controls |
| * |
| * L2 = Length(MessageId) |
| * L1 = Length(0x02) + Length(L2) + L2 + Length(ProtocolOp) + Length(Controls) |
| * LdapMessageLength = Length(0x30) + Length(L1) + L1 |
| * </pre> |
| * |
| * @param buffer The encoded PDU |
| * @return A ByteBuffer that contaons the PDU |
| * @throws EncoderException If anything goes wrong. |
| */ |
| public ByteBuffer encode() throws EncoderException |
| { |
| // Allocate the bytes buffer. |
| ByteBuffer bb = ByteBuffer.allocate( computeLength() ); |
| |
| try |
| { |
| // The LdapMessage Sequence |
| bb.put( UniversalTag.SEQUENCE_TAG ); |
| |
| // The length has been calculated by the computeLength method |
| bb.put( TLV.getBytes( ldapMessageLength ) ); |
| } |
| catch ( BufferOverflowException boe ) |
| { |
| throw new EncoderException( I18n.err( I18n.ERR_04005 ) ); |
| } |
| |
| // The message Id |
| Value.encode( bb, messageId ); |
| |
| // Add the protocolOp part |
| encodeProtocolOp( bb ); |
| |
| // Do the same thing for Controls, if any. |
| if ( controls != null ) |
| { |
| // Encode the controls |
| bb.put( ( byte ) LdapConstants.CONTROLS_TAG ); |
| bb.put( TLV.getBytes( controlsLength ) ); |
| |
| // Encode each control |
| for ( Control control:controls ) |
| { |
| ((CodecControl)control).encode( bb ); |
| } |
| } |
| |
| return bb; |
| } |
| |
| |
| /** |
| * Get a String representation of a LdapMessage |
| * |
| * @return A LdapMessage String |
| */ |
| protected String toString( String protocolOp ) |
| { |
| StringBuffer sb = new StringBuffer(); |
| |
| sb.append( "LdapMessage\n" ); |
| sb.append( " message Id : " ).append( messageId ).append( '\n' ); |
| |
| sb.append( protocolOp ).append( '\n' ); |
| |
| if ( controls != null ) |
| { |
| for ( Control control:controls ) |
| { |
| sb.append( control ); |
| } |
| } |
| |
| return sb.toString(); |
| } |
| } |