| | |
| | | package org.opends.server.synchronization; |
| | | |
| | | import static org.opends.server.synchronization.SynchMessages.SYNCHRONIZATION; |
| | | import static org.opends.server.protocols.ldap.LDAPConstants.*; |
| | | |
| | | import org.opends.server.core.ModifyOperation; |
| | | import org.opends.server.core.Operation; |
| | |
| | | import java.io.UnsupportedEncodingException; |
| | | import java.util.ArrayList; |
| | | import java.util.List; |
| | | import java.util.zip.DataFormatException; |
| | | |
| | | /** |
| | | * Message used to send Modify information. |
| | |
| | | public class ModifyMsg extends UpdateMessage |
| | | { |
| | | private static final long serialVersionUID = -4905520652801395185L; |
| | | private String dn; |
| | | private byte[] encodedMods; |
| | | private String dn = null; |
| | | private byte[] encodedMods = null; |
| | | private byte[] encodedMsg = null; |
| | | |
| | | /** |
| | | * Creates a new Modify message from a ModifyOperation. |
| | |
| | | * Creates a new Modify message from a byte[]. |
| | | * |
| | | * @param in The byte[] from which the operation must be read. |
| | | * @throws Exception The input byte[] is not a valid modifyMsg |
| | | * @throws DataFormatException If the input byte[] is not a valid modifyMsg |
| | | * @throws UnsupportedEncodingException If UTF8 is not supported by the JVM. |
| | | */ |
| | | public ModifyMsg(byte[] in) throws Exception |
| | | public ModifyMsg(byte[] in) throws DataFormatException, |
| | | UnsupportedEncodingException |
| | | { |
| | | /* first byte is the type */ |
| | | if (in[0] != OP_TYPE_MODIFY_REQUEST) |
| | | throw new Exception("byte[] is not a valid modify msg"); |
| | | encodedMsg = in; |
| | | decodeChangeNumber(in); |
| | | } |
| | | |
| | | private void decodeChangeNumber(byte[] in) throws DataFormatException, |
| | | UnsupportedEncodingException |
| | | { |
| | | /* read the changeNumber */ |
| | | int pos = 1; |
| | | int length = getNextLength(encodedMsg, pos); |
| | | String changenumberStr = new String(encodedMsg, pos, length, "UTF-8"); |
| | | pos += length +1; |
| | | changeNumber = new ChangeNumber(changenumberStr); |
| | | } |
| | | |
| | | /** |
| | | * Get the byte array representation of this Message. |
| | | * |
| | | * @return The byte array representation of this Message. |
| | | */ |
| | | @Override |
| | | public byte[] getBytes() |
| | | { |
| | | if (encodedMsg == null) |
| | | { |
| | | try |
| | | { |
| | | encode(); |
| | | } catch (UnsupportedEncodingException e) |
| | | { |
| | | // should never happens : TODO : log some error |
| | | return null; |
| | | } |
| | | } |
| | | return encodedMsg; |
| | | } |
| | | |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |
| | | public Operation createOperation(InternalClientConnection connection) |
| | | throws LDAPException, ASN1Exception, DataFormatException |
| | | { |
| | | if (encodedMods == null) |
| | | { |
| | | decode(); |
| | | } |
| | | |
| | | ArrayList<LDAPModification> ldapmods; |
| | | |
| | | ArrayList<ASN1Element> mods = null; |
| | | |
| | | mods = ASN1Element.decodeElements(encodedMods); |
| | | |
| | | ldapmods = new ArrayList<LDAPModification>(mods.size()); |
| | | for (ASN1Element elem : mods) |
| | | ldapmods.add(LDAPModification.decode(elem)); |
| | | |
| | | ModifyOperation mod = new ModifyOperation(connection, |
| | | InternalClientConnection.nextOperationID(), |
| | | InternalClientConnection.nextMessageID(), null, |
| | | new ASN1OctetString(dn), ldapmods); |
| | | mod.setAttachment(SYNCHRONIZATION, getChangeNumber()); |
| | | return mod; |
| | | } |
| | | |
| | | /** |
| | | * Encode the Msg information into a byte array. |
| | | * |
| | | * @throws UnsupportedEncodingException If utf8 is not suported. |
| | | */ |
| | | private void encode() throws UnsupportedEncodingException |
| | | { |
| | | byte[] byteDn = dn.getBytes("UTF-8"); |
| | | byte[] changeNumberByte = |
| | | this.getChangeNumber().toString().getBytes("UTF-8"); |
| | | |
| | | /* The Modify message is stored in the form : |
| | | * <operation type>changenumber><dn><<mods> |
| | | * the length of result byte array is therefore : |
| | | * 1 + dn length + 1 + 24 + mods length |
| | | */ |
| | | int length = 1 + changeNumberByte.length + 1 + byteDn.length + 1 |
| | | + encodedMods.length + 1; |
| | | encodedMsg = new byte[length]; |
| | | |
| | | /* put the type of the operation */ |
| | | encodedMsg[0] = MSG_TYPE_MODIFY_REQUEST; |
| | | int pos = 1; |
| | | |
| | | /* read the dn |
| | | * first calculate the length then construct the string |
| | | */ |
| | | int length = 0; |
| | | int offset = pos; |
| | | while (in[pos++] != 0) |
| | | { |
| | | if (pos > in.length) |
| | | throw new Exception("byte[] is not a valid modify msg"); |
| | | length++; |
| | | } |
| | | dn = new String(in, offset, length, "UTF-8"); |
| | | /* put the ChangeNumber */ |
| | | pos = addByteArray(changeNumberByte, encodedMsg, pos); |
| | | |
| | | /* read the changeNumber |
| | | * it is always 24 characters long |
| | | */ |
| | | String changenumberStr = new String(in, pos, 24, "UTF-8"); |
| | | changeNumber = new ChangeNumber(changenumberStr); |
| | | pos +=24; |
| | | /* put the DN and a terminating 0 */ |
| | | pos = addByteArray(byteDn, encodedMsg, pos); |
| | | |
| | | /* Read the mods : all the remaining bytes */ |
| | | encodedMods = new byte[in.length-pos]; |
| | | int i =0; |
| | | while (pos<in.length) |
| | | /* put the mods */ |
| | | pos = addByteArray(encodedMods, encodedMsg, pos); |
| | | } |
| | | |
| | | /** |
| | | * Decode the encodedMsg into mods and dn. |
| | | * |
| | | * @throws DataFormatException when the encodedMsg is no a valid modify. |
| | | */ |
| | | private void decode() throws DataFormatException |
| | | { |
| | | /* first byte is the type */ |
| | | if (encodedMsg[0] != MSG_TYPE_MODIFY_REQUEST) |
| | | throw new DataFormatException("byte[] is not a valid modify msg"); |
| | | |
| | | try |
| | | { |
| | | encodedMods[i++] = in[pos++]; |
| | | /* read the changeNumber */ |
| | | int pos = 1; |
| | | int length = getNextLength(encodedMsg, pos); |
| | | String changenumberStr = new String(encodedMsg, pos, length, "UTF-8"); |
| | | pos += length +1; |
| | | changeNumber = new ChangeNumber(changenumberStr); |
| | | |
| | | /* read the dn */ |
| | | length = getNextLength(encodedMsg, pos); |
| | | dn = new String(encodedMsg, pos, length, "UTF-8"); |
| | | pos += length +1; |
| | | |
| | | /* Read the mods : all the remaining bytes but the terminating 0 */ |
| | | encodedMods = new byte[encodedMsg.length-pos-1]; |
| | | int i =0; |
| | | while (pos<encodedMsg.length-1) |
| | | { |
| | | encodedMods[i++] = encodedMsg[pos++]; |
| | | } |
| | | } catch (UnsupportedEncodingException e) |
| | | { |
| | | throw new DataFormatException("UTF-8 is not supported by this jvm."); |
| | | } |
| | | } |
| | | |
| | |
| | | } |
| | | |
| | | /** |
| | | * Create an operation from this Modify message. |
| | | * |
| | | * @param connection The connection to use when creating the operation. |
| | | * @return The created operation. |
| | | * @throws LDAPException In case of ldap decoding exception. |
| | | * @throws ASN1Exception In case of ASN1 decoding exception. |
| | | */ |
| | | @Override |
| | | public Operation createOperation(InternalClientConnection connection) |
| | | throws LDAPException, ASN1Exception |
| | | { |
| | | ArrayList<LDAPModification> ldapmods; |
| | | |
| | | ArrayList<ASN1Element> mods = null; |
| | | |
| | | mods = ASN1Element.decodeElements(encodedMods); |
| | | |
| | | ldapmods = new ArrayList<LDAPModification>(mods.size()); |
| | | for (ASN1Element elem : mods) |
| | | ldapmods.add(LDAPModification.decode(elem)); |
| | | |
| | | ModifyOperation mod = new ModifyOperation(connection, |
| | | InternalClientConnection.nextOperationID(), |
| | | InternalClientConnection.nextMessageID(), null, |
| | | new ASN1OctetString(dn), ldapmods); |
| | | mod.setAttachment(SYNCHRONIZATION, getChangeNumber()); |
| | | return mod; |
| | | } |
| | | |
| | | /** |
| | | * Get the byte array representation of this Message. |
| | | * |
| | | * @return The byte array representation of this Message. |
| | | */ |
| | | @Override |
| | | public byte[] getByte() |
| | | { |
| | | byte[] byteDn; |
| | | try |
| | | { |
| | | byteDn = dn.getBytes("UTF-8"); |
| | | |
| | | /* The Modify message is stored in the form : |
| | | * <operation type><dn><changenumber><mods> |
| | | * the length of result byte array is therefore : |
| | | * 1 + dn length + 1 + 24 + mods length |
| | | */ |
| | | int length = 1 + byteDn.length + 1 + 24 + encodedMods.length; |
| | | byte[] resultByteArray = new byte[length]; |
| | | int pos = 1; |
| | | |
| | | /* put the type of the operation */ |
| | | resultByteArray[0] = OP_TYPE_MODIFY_REQUEST; |
| | | /* put the DN and a terminating 0 */ |
| | | for (int i = 0; i< byteDn.length; i++,pos++) |
| | | { |
| | | resultByteArray[pos] = byteDn[i]; |
| | | } |
| | | resultByteArray[pos++] = 0; |
| | | /* put the ChangeNumber */ |
| | | byte[] changeNumberByte = |
| | | this.getChangeNumber().toString().getBytes("UTF-8"); |
| | | for (int i=0; i<24; i++,pos++) |
| | | { |
| | | resultByteArray[pos] = changeNumberByte[i]; |
| | | } |
| | | |
| | | /* put the mods */ |
| | | for (int i=0; i<encodedMods.length; i++,pos++) |
| | | { |
| | | resultByteArray[pos] = encodedMods[i]; |
| | | } |
| | | return resultByteArray; |
| | | } catch (UnsupportedEncodingException e) |
| | | { |
| | | // should never happens : TODO : log some error |
| | | } |
| | | return null; |
| | | } |
| | | |
| | | /** |
| | | * {@inheritDoc} |
| | | */ |
| | | @Override |