001/* 002 * CDDL HEADER START 003 * 004 * The contents of this file are subject to the terms of the 005 * Common Development and Distribution License, Version 1.0 only 006 * (the "License"). You may not use this file except in compliance 007 * with the License. 008 * 009 * You can obtain a copy of the license at legal-notices/CDDLv1_0.txt 010 * or http://forgerock.org/license/CDDLv1.0.html. 011 * See the License for the specific language governing permissions 012 * and limitations under the License. 013 * 014 * When distributing Covered Code, include this CDDL HEADER in each 015 * file and include the License file at legal-notices/CDDLv1_0.txt. 016 * If applicable, add the following below this CDDL HEADER, with the 017 * fields enclosed by brackets "[]" replaced with your own identifying 018 * information: 019 * Portions Copyright [yyyy] [name of copyright owner] 020 * 021 * CDDL HEADER END 022 * 023 * 024 * Copyright 2006-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2011-2015 ForgeRock AS 026 */ 027package org.opends.server.replication.protocol; 028 029import java.io.IOException; 030import java.util.List; 031import java.util.zip.DataFormatException; 032 033import org.opends.server.core.ModifyOperation; 034import org.opends.server.core.ModifyOperationBasis; 035import org.opends.server.protocols.internal.InternalClientConnection; 036import org.opends.server.replication.common.CSN; 037import org.opends.server.types.DN; 038import org.opends.server.types.LDAPException; 039import org.opends.server.types.Modification; 040import org.opends.server.types.RawModification; 041import org.forgerock.opendj.ldap.ByteString; 042import org.opends.server.types.operation.PostOperationModifyOperation; 043 044import static org.opends.server.replication.protocol.OperationContext.*; 045 046/** 047 * Message used to send Modify information. 048 */ 049public class ModifyMsg extends ModifyCommonMsg 050{ 051 /** 052 * Creates a new Modify message from a ModifyOperation. 053 * 054 * @param op The operation to use for building the message 055 */ 056 ModifyMsg(PostOperationModifyOperation op) 057 { 058 super((OperationContext) op.getAttachment(OperationContext.SYNCHROCONTEXT), 059 op.getEntryDN()); 060 encodedMods = encodeMods(op.getModifications()); 061 } 062 063 /** 064 * Creates a new Modify message using the provided information. 065 * 066 * @param csn The CSN for the operation. 067 * @param dn The baseDN of the operation. 068 * @param mods The mod of the operation. 069 * @param entryUUID The unique id of the entry on which the modification 070 * needs to apply. 071 */ 072 public ModifyMsg(CSN csn, DN dn, List<Modification> mods, String entryUUID) 073 { 074 super(new ModifyContext(csn, entryUUID), dn); 075 this.encodedMods = encodeMods(mods); 076 } 077 078 /** 079 * Creates a new Modify message from a byte[]. 080 * 081 * @param in The byte[] from which the operation must be read. 082 * @throws DataFormatException If the input byte[] is not a valid ModifyMsg 083 */ 084 ModifyMsg(byte[] in) throws DataFormatException 085 { 086 final ByteArrayScanner scanner = new ByteArrayScanner(in); 087 decodeHeader(scanner, MSG_TYPE_MODIFY, MSG_TYPE_MODIFY_V1); 088 089 if (protocolVersion <= 3) 090 { 091 decodeBody_V123(scanner); 092 } 093 else 094 { 095 decodeBody_V4(scanner); 096 } 097 098 if (protocolVersion==ProtocolVersion.getCurrentVersion()) 099 { 100 bytes = in; 101 } 102 } 103 104 /** 105 * Creates a new Modify message from a V1 byte[]. 106 * 107 * @param in The byte[] from which the operation must be read. 108 * @return The created ModifyMsg. 109 * @throws DataFormatException If the input byte[] is not a valid ModifyMsg 110 */ 111 static ModifyMsg createV1(byte[] in) throws DataFormatException 112 { 113 ModifyMsg msg = new ModifyMsg(in); 114 115 // bytes is only for current version (of the protocol) bytes ! 116 msg.bytes = null; 117 118 return msg; 119 } 120 121 /** {@inheritDoc} */ 122 @Override 123 public ModifyOperation createOperation(InternalClientConnection connection, 124 DN newDN) throws LDAPException, IOException, DataFormatException 125 { 126 if (newDN == null) 127 { 128 newDN = getDN(); 129 } 130 131 List<RawModification> ldapmods = decodeRawMods(encodedMods); 132 133 ModifyOperation mod = new ModifyOperationBasis(connection, 134 InternalClientConnection.nextOperationID(), 135 InternalClientConnection.nextMessageID(), null, 136 ByteString.valueOfUtf8(newDN.toString()), ldapmods); 137 ModifyContext ctx = new ModifyContext(getCSN(), getEntryUUID()); 138 mod.setAttachment(SYNCHROCONTEXT, ctx); 139 return mod; 140 } 141 142 /** {@inheritDoc} */ 143 @Override 144 public String toString() 145 { 146 if (protocolVersion >= ProtocolVersion.REPLICATION_PROTOCOL_V1) 147 { 148 return "ModifyMsg content: " + 149 " protocolVersion: " + protocolVersion + 150 " dn: " + dn + 151 " csn: " + csn + 152 " uniqueId: " + entryUUID + 153 " assuredFlag: " + assuredFlag + 154 (protocolVersion >= ProtocolVersion.REPLICATION_PROTOCOL_V2 ? 155 " assuredMode: " + assuredMode + 156 " safeDataLevel: " + safeDataLevel + 157 " size: " + encodedMods.length 158 : ""); 159 /* Do not append mods, they can be too long */ 160 } 161 return "!!! Unknown version: " + protocolVersion + "!!!"; 162 } 163 164 /** {@inheritDoc} */ 165 @Override 166 public int size() 167 { 168 // The ModifyMsg can be very large when added or deleted attribute 169 // values are very large. 170 // We therefore need to count the whole encoded msg. 171 return encodedMods.length + encodedEclIncludes.length + headerSize(); 172 } 173 174 // ============ 175 // Msg Encoding 176 // ============ 177 178 /** {@inheritDoc} */ 179 @Override 180 public byte[] getBytes_V1() 181 { 182 final ByteArrayBuilder builder = encodeHeader_V1(MSG_TYPE_MODIFY_V1); 183 builder.appendByteArray(encodedMods); 184 return builder.toByteArray(); 185 } 186 187 /** {@inheritDoc} */ 188 @Override 189 public byte[] getBytes_V23() 190 { 191 final ByteArrayBuilder builder = 192 encodeHeader(MSG_TYPE_MODIFY, ProtocolVersion.REPLICATION_PROTOCOL_V3); 193 builder.appendByteArray(encodedMods); 194 return builder.toByteArray(); 195 } 196 197 /** {@inheritDoc} */ 198 @Override 199 public byte[] getBytes_V45(short protocolVersion) 200 { 201 final ByteArrayBuilder builder = 202 encodeHeader(MSG_TYPE_MODIFY, protocolVersion); 203 builder.appendIntUTF8(encodedMods.length); 204 builder.appendZeroTerminatedByteArray(encodedMods); 205 builder.appendIntUTF8(encodedEclIncludes.length); 206 builder.appendZeroTerminatedByteArray(encodedEclIncludes); 207 return builder.toByteArray(); 208 } 209 210 // ============ 211 // Msg decoding 212 // ============ 213 214 private void decodeBody_V123(ByteArrayScanner scanner) 215 throws DataFormatException 216 { 217 encodedMods = scanner.remainingBytes(); 218 } 219 220 private void decodeBody_V4(ByteArrayScanner scanner) 221 throws DataFormatException 222 { 223 final int modsLen = scanner.nextIntUTF8(); 224 this.encodedMods = scanner.nextByteArray(modsLen); 225 scanner.skipZeroSeparator(); 226 227 final int eclAttrLen = scanner.nextIntUTF8(); 228 encodedEclIncludes = scanner.nextByteArray(eclAttrLen); 229 } 230}