| /* |
| * 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.extras.controls.syncrepl_impl; |
| |
| |
| import java.nio.ByteBuffer; |
| |
| import org.apache.directory.shared.asn1.Asn1Object; |
| import org.apache.directory.shared.asn1.DecoderException; |
| import org.apache.directory.shared.asn1.EncoderException; |
| import org.apache.directory.shared.asn1.ber.Asn1Decoder; |
| 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.util.Asn1StringUtils; |
| import org.apache.directory.shared.i18n.I18n; |
| import org.apache.directory.shared.ldap.codec.api.LdapCodecService; |
| import org.apache.directory.shared.ldap.codec.controls.ControlDecorator; |
| import org.apache.directory.shared.ldap.extras.controls.SyncModifyDn; |
| import org.apache.directory.shared.ldap.extras.controls.SyncModifyDnImpl; |
| import org.apache.directory.shared.ldap.extras.controls.SyncModifyDnType; |
| |
| |
| /** |
| * A SyncModifyDnControl object, to send the parameters used in a MODIFYDN operation |
| * that was carried out on a syncrepl provider server. |
| * |
| * The consumer will use the values present in this control to perform the same operation |
| * on its local data, which helps in avoiding huge number of updates to the consumer. |
| * |
| * NOTE: syncrepl, defined in RFC 4533, doesn't mention about this approach, this is a special |
| * extension provided by Apache Directory Server |
| * |
| * @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a> |
| */ |
| public class SyncModifyDnDecorator extends ControlDecorator<SyncModifyDn> implements SyncModifyDn |
| { |
| /** the entry's Dn to be changed */ |
| private String entryDn; |
| |
| /** target entry's new parent Dn */ |
| private String newSuperiorDn; |
| |
| /** the new Rdn */ |
| private String newRdn; |
| |
| /** flag to indicate whether to delete the old Rdn */ |
| private boolean deleteOldRdn = false; |
| |
| private SyncModifyDnType modDnType; |
| |
| /** global length for the control */ |
| private int syncModDnSeqLength; |
| |
| private int renameLen = 0; |
| private int moveAndRenameLen = 0; |
| |
| /** An instance of this decoder */ |
| private Asn1Decoder decoder = new Asn1Decoder(); |
| |
| |
| public SyncModifyDnDecorator( LdapCodecService codec ) |
| { |
| super( codec, new SyncModifyDnImpl() ); |
| } |
| |
| |
| public SyncModifyDnDecorator( LdapCodecService codec, SyncModifyDnType type ) |
| { |
| this( codec ); |
| this.modDnType = type; |
| } |
| |
| |
| public SyncModifyDnDecorator( LdapCodecService codec, SyncModifyDn control ) |
| { |
| super( codec, control ); |
| } |
| |
| |
| /** |
| * Compute the SyncStateValue length. |
| * |
| * SyncStateValue : |
| * 0x30 L1 |
| * | |
| * +--> 0x04 L2 uid=jim... (entryDn) |
| * [+--> 0x04 L3 ou=system... (newSuperior) |
| * [+--> 0x04 L4 uid=jack... (newRdn) |
| * [+--> 0x04 0x01 [0x00|0x01]... (deleteOldRdn) |
| * |
| */ |
| @Override |
| public int computeLength() |
| { |
| syncModDnSeqLength = 1 + TLV.getNbBytes( entryDn.length() ) + entryDn.length(); |
| |
| switch ( modDnType ) |
| { |
| case MOVE: |
| int moveLen = 1 + TLV.getNbBytes( newSuperiorDn.length() ) + newSuperiorDn.length(); |
| syncModDnSeqLength += moveLen; //1 + TLV.getNbBytes( moveLen ) + moveLen; |
| break; |
| |
| case RENAME: |
| renameLen = 1 + TLV.getNbBytes( newRdn.length() ) + newRdn.length(); |
| |
| // deleteOldRdn |
| renameLen += 1 + 1 + 1; |
| |
| syncModDnSeqLength += 1 + TLV.getNbBytes( renameLen ) + renameLen; |
| break; |
| |
| case MOVEANDRENAME: |
| moveAndRenameLen = 1 + TLV.getNbBytes( newSuperiorDn.length() ) + newSuperiorDn.length(); |
| moveAndRenameLen += 1 + TLV.getNbBytes( newRdn.length() ) + newRdn.length(); |
| // deleteOldRdn |
| moveAndRenameLen += 1 + 1 + 1; |
| |
| syncModDnSeqLength += 1 + TLV.getNbBytes( moveAndRenameLen ) + moveAndRenameLen; |
| break; |
| } |
| |
| valueLength = 1 + TLV.getNbBytes( syncModDnSeqLength ) + syncModDnSeqLength; |
| |
| return valueLength; |
| } |
| |
| |
| /** |
| * Encode the SyncStateValue control |
| * |
| * @param buffer The encoded sink |
| * @return A ByteBuffer that contains the encoded PDU |
| * @throws EncoderException If anything goes wrong. |
| */ |
| @Override |
| public ByteBuffer encode( ByteBuffer buffer ) throws EncoderException |
| { |
| if ( buffer == null ) |
| { |
| throw new EncoderException( I18n.err( I18n.ERR_04023 ) ); |
| } |
| |
| // Encode the SEQ |
| buffer.put( UniversalTag.SEQUENCE.getValue() ); |
| buffer.put( TLV.getBytes( syncModDnSeqLength ) ); |
| |
| // the entryDn |
| Value.encode( buffer, entryDn ); |
| |
| switch ( modDnType ) |
| { |
| case MOVE: |
| buffer.put( ( byte ) SyncModifyDnTags.MOVE_TAG.getValue() ); |
| buffer.put( TLV.getBytes( newSuperiorDn.length() ) ); |
| buffer.put( Asn1StringUtils.getBytesUtf8( newSuperiorDn ) ); |
| break; |
| |
| case RENAME: |
| buffer.put( ( byte ) SyncModifyDnTags.RENAME_TAG.getValue() ); |
| buffer.put( TLV.getBytes( renameLen ) ); |
| Value.encode( buffer, newRdn ); |
| Value.encode( buffer, deleteOldRdn ); |
| break; |
| |
| case MOVEANDRENAME: |
| buffer.put( ( byte ) SyncModifyDnTags.MOVEANDRENAME_TAG.getValue() ); |
| buffer.put( TLV.getBytes( moveAndRenameLen ) ); |
| Value.encode( buffer, newSuperiorDn ); |
| Value.encode( buffer, newRdn ); |
| Value.encode( buffer, deleteOldRdn ); |
| break; |
| } |
| |
| return buffer; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| @Override |
| public byte[] getValue() |
| { |
| if ( value == null ) |
| { |
| try |
| { |
| computeLength(); |
| ByteBuffer buffer = ByteBuffer.allocate( valueLength ); |
| |
| // Encode the SEQ |
| buffer.put( UniversalTag.SEQUENCE.getValue() ); |
| buffer.put( TLV.getBytes( syncModDnSeqLength ) ); |
| |
| // the entryDn |
| Value.encode( buffer, entryDn ); |
| |
| switch ( modDnType ) |
| { |
| case MOVE: |
| buffer.put( ( byte ) SyncModifyDnTags.MOVE_TAG.getValue() ); |
| buffer.put( TLV.getBytes( newSuperiorDn.length() ) ); |
| buffer.put( Asn1StringUtils.getBytesUtf8( newSuperiorDn ) ); |
| break; |
| |
| case RENAME: |
| buffer.put( ( byte ) SyncModifyDnTags.RENAME_TAG.getValue() ); |
| buffer.put( TLV.getBytes( renameLen ) ); |
| Value.encode( buffer, newRdn ); |
| Value.encode( buffer, deleteOldRdn ); |
| break; |
| |
| case MOVEANDRENAME: |
| buffer.put( ( byte ) SyncModifyDnTags.MOVEANDRENAME_TAG.getValue() ); |
| buffer.put( TLV.getBytes( moveAndRenameLen ) ); |
| Value.encode( buffer, newSuperiorDn ); |
| Value.encode( buffer, newRdn ); |
| Value.encode( buffer, deleteOldRdn ); |
| break; |
| } |
| |
| value = buffer.array(); |
| } |
| catch ( Exception e ) |
| { |
| return null; |
| } |
| } |
| |
| return value; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public String getEntryDn() |
| { |
| return entryDn; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setEntryDn( String entryDn ) |
| { |
| this.entryDn = entryDn; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public String getNewSuperiorDn() |
| { |
| return newSuperiorDn; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setNewSuperiorDn( String newSuperiorDn ) |
| { |
| this.newSuperiorDn = newSuperiorDn; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public String getNewRdn() |
| { |
| return newRdn; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setNewRdn( String newRdn ) |
| { |
| this.newRdn = newRdn; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public boolean isDeleteOldRdn() |
| { |
| return deleteOldRdn; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setDeleteOldRdn( boolean deleteOldRdn ) |
| { |
| this.deleteOldRdn = deleteOldRdn; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public SyncModifyDnType getModDnType() |
| { |
| return modDnType; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public void setModDnType( SyncModifyDnType modDnType ) |
| { |
| if( this.modDnType != null ) |
| { |
| throw new IllegalStateException( "cannot overwrite the existing modDnType value" ); |
| } |
| this.modDnType = modDnType; |
| } |
| |
| |
| /** |
| * {@inheritDoc} |
| */ |
| public Asn1Object decode( byte[] controlBytes ) throws DecoderException |
| { |
| ByteBuffer bb = ByteBuffer.wrap( controlBytes ); |
| SyncModifyDnContainer container = new SyncModifyDnContainer( this ); |
| decoder.decode( bb, container ); |
| return this; |
| } |
| } |