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-2009 Sun Microsystems, Inc. 025 * Portions Copyright 2013-2015 ForgeRock AS. 026 */ 027package org.opends.server.replication.protocol; 028 029import java.util.zip.DataFormatException; 030 031import org.opends.server.replication.common.AssuredMode; 032import org.opends.server.replication.common.CSN; 033 034import static org.opends.server.replication.protocol.ByteArrayBuilder.*; 035 036/** 037 * Abstract class that must be extended to define a message 038 * used for sending Updates between servers. 039 */ 040public class UpdateMsg extends ReplicationMsg 041 implements Comparable<UpdateMsg> 042{ 043 /** Protocol version. */ 044 protected short protocolVersion; 045 046 /** The CSN of this update. */ 047 protected CSN csn; 048 049 /** True when the update must use assured replication. */ 050 protected boolean assuredFlag; 051 052 /** When assuredFlag is true, defines the requested assured mode. */ 053 protected AssuredMode assuredMode = AssuredMode.SAFE_DATA_MODE; 054 055 /** When assured mode is safe data, gives the requested level. */ 056 protected byte safeDataLevel = 1; 057 058 /** The payload that must be encoded in this message. */ 059 private final byte[] payload; 060 061 /** 062 * Creates a new empty UpdateMsg. 063 */ 064 protected UpdateMsg() 065 { 066 payload = null; 067 } 068 069 /** 070 * Creates a new UpdateMsg with the given information. 071 * 072 * @param bytes A Byte Array with the encoded form of the message. 073 * 074 * @throws DataFormatException If bytes is not valid. 075 */ 076 UpdateMsg(byte[] bytes) throws DataFormatException 077 { 078 final ByteArrayScanner scanner = new ByteArrayScanner(bytes); 079 decodeHeader(MSG_TYPE_GENERIC_UPDATE, scanner); 080 // Read the payload : all the remaining bytes but the terminating 0 081 payload = scanner.remainingBytes(); 082 } 083 084 /** 085 * Creates a new UpdateMsg with the given informations. 086 * <p> 087 * This constructor is only used for testing. 088 * 089 * @param csn The CSN associated with the change encoded in this message. 090 * @param payload The payload that must be encoded in this message. 091 */ 092 public UpdateMsg(CSN csn, byte[] payload) 093 { 094 this.payload = payload; 095 this.protocolVersion = ProtocolVersion.getCurrentVersion(); 096 this.csn = csn; 097 } 098 099 /** 100 * Get the CSN from the message. 101 * @return the CSN 102 */ 103 public CSN getCSN() 104 { 105 return csn; 106 } 107 108 /** 109 * Get a boolean indicating if the Update must be processed as an 110 * Asynchronous or as an assured replication. 111 * 112 * @return Returns the assuredFlag. 113 */ 114 public boolean isAssured() 115 { 116 return assuredFlag; 117 } 118 119 /** 120 * Set the Update message as an assured message. 121 * 122 * @param assured If the message is assured or not. Using true implies 123 * setAssuredMode method must be called. 124 */ 125 public void setAssured(boolean assured) 126 { 127 assuredFlag = assured; 128 } 129 130 /** {@inheritDoc} */ 131 @Override 132 public boolean equals(Object obj) 133 { 134 return obj != null 135 && obj.getClass() == getClass() 136 && csn.equals(((UpdateMsg) obj).csn); 137 } 138 139 /** {@inheritDoc} */ 140 @Override 141 public int hashCode() 142 { 143 return csn.hashCode(); 144 } 145 146 /** {@inheritDoc} */ 147 @Override 148 public int compareTo(UpdateMsg msg) 149 { 150 return csn.compareTo(msg.getCSN()); 151 } 152 153 /** 154 * Get the assured mode in this message. 155 * @return The assured mode in this message 156 */ 157 public AssuredMode getAssuredMode() 158 { 159 return assuredMode; 160 } 161 162 /** 163 * Get the safe data level in this message. 164 * @return The safe data level in this message 165 */ 166 public byte getSafeDataLevel() 167 { 168 return safeDataLevel; 169 } 170 171 /** 172 * Set the assured mode. Assured boolean must be set to true for this field 173 * to mean something. 174 * @param assuredMode The chosen assured mode. 175 */ 176 public void setAssuredMode(AssuredMode assuredMode) 177 { 178 this.assuredMode = assuredMode; 179 } 180 181 /** 182 * Set the safe data level. Assured mode should be set to safe data for this 183 * field to mean something. 184 * @param safeDataLevel The chosen safe data level. 185 */ 186 public void setSafeDataLevel(byte safeDataLevel) 187 { 188 this.safeDataLevel = safeDataLevel; 189 } 190 191 /** 192 * Get the version included in the update message. Means the replication 193 * protocol version with which this update message was instantiated. 194 * 195 * @return The version with which this update message was instantiated. 196 */ 197 public short getVersion() 198 { 199 return protocolVersion; 200 } 201 202 /** 203 * Return the number of bytes used by this message. 204 * 205 * @return The number of bytes used by this message. 206 */ 207 public int size() 208 { 209 return 10 + payload.length; 210 } 211 212 /** 213 * Encode the common header for all the UpdateMsg. This uses the current 214 * protocol version. 215 * 216 * @param msgType The type of UpdateMsg to encode. 217 * @param protocolVersion The ProtocolVersion to use when encoding. 218 * @return a byte array builder containing the common header 219 */ 220 protected ByteArrayBuilder encodeHeader(byte msgType, short protocolVersion) 221 { 222 final ByteArrayBuilder builder = 223 new ByteArrayBuilder(bytes(6) + csnsUTF8(1)); 224 builder.appendByte(msgType); 225 builder.appendByte((byte) ProtocolVersion.getCurrentVersion()); 226 builder.appendCSNUTF8(getCSN()); 227 builder.appendBoolean(assuredFlag); 228 builder.appendByte(assuredMode.getValue()); 229 builder.appendByte(safeDataLevel); 230 return builder; 231 } 232 233 /** 234 * Decode the Header part of this Update message, and check its type. 235 * 236 * @param allowedType The allowed type of this Update Message. 237 * @param scanner The encoded form of the UpdateMsg. 238 * @throws DataFormatException 239 * if the scanner does not contain a valid common header. 240 */ 241 protected void decodeHeader(byte allowedType, ByteArrayScanner scanner) 242 throws DataFormatException 243 { 244 /* The message header is stored in the form : 245 * <operation type><protocol version><CSN><assured> 246 * <assured mode> <safe data level> 247 */ 248 final byte msgType = scanner.nextByte(); 249 if (allowedType != msgType) 250 { 251 throw new DataFormatException("byte[] is not a valid update msg: " 252 + msgType); 253 } 254 255 protocolVersion = scanner.nextByte(); 256 csn = scanner.nextCSNUTF8(); 257 assuredFlag = scanner.nextBoolean(); 258 assuredMode = AssuredMode.valueOf(scanner.nextByte()); 259 safeDataLevel = scanner.nextByte(); 260 } 261 262 /** 263 * Returns the encoded representation of this update message using the current 264 * protocol version. 265 * 266 * @return The encoded representation of this update message. 267 */ 268 public byte[] getBytes() 269 { 270 return getBytes(ProtocolVersion.getCurrentVersion()); 271 } 272 273 /** 274 * This implementation is only called during unit testing, so we are free to 275 * force the protocol version. Underlying implementations override this method 276 * in order to provide version specific encodings. 277 * 278 * {@inheritDoc} 279 */ 280 @Override 281 public byte[] getBytes(short protocolVersion) 282 { 283 final ByteArrayBuilder builder = encodeHeader(MSG_TYPE_GENERIC_UPDATE, 284 ProtocolVersion.getCurrentVersion()); 285 builder.appendByteArray(payload); 286 return builder.toByteArray(); 287 } 288 289 /** 290 * Get the payload of the UpdateMsg. 291 * 292 * @return The payload of the UpdateMsg. 293 */ 294 public byte[] getPayload() 295 { 296 return payload; 297 } 298 299 /** 300 * Whether the current message can update the "ds-sync-state" attribute. 301 * 302 * @return true if current message can update the "ds-sync-state" attribute, false otherwise. 303 */ 304 public boolean contributesToDomainState() 305 { 306 return true; 307 } 308}