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 = new ByteArrayBuilder(bytes(6) + csnsUTF8(1)); 223 builder.appendByte(msgType); 224 builder.appendByte(ProtocolVersion.getCurrentVersion()); 225 builder.appendCSNUTF8(getCSN()); 226 builder.appendBoolean(assuredFlag); 227 builder.appendByte(assuredMode.getValue()); 228 builder.appendByte(safeDataLevel); 229 return builder; 230 } 231 232 /** 233 * Decode the Header part of this Update message, and check its type. 234 * 235 * @param allowedType The allowed type of this Update Message. 236 * @param scanner The encoded form of the UpdateMsg. 237 * @throws DataFormatException 238 * if the scanner does not contain a valid common header. 239 */ 240 protected void decodeHeader(byte allowedType, ByteArrayScanner scanner) 241 throws DataFormatException 242 { 243 /* The message header is stored in the form : 244 * <operation type><protocol version><CSN><assured> 245 * <assured mode> <safe data level> 246 */ 247 final byte msgType = scanner.nextByte(); 248 if (allowedType != msgType) 249 { 250 throw new DataFormatException("byte[] is not a valid update msg: " 251 + msgType); 252 } 253 254 protocolVersion = scanner.nextByte(); 255 csn = scanner.nextCSNUTF8(); 256 assuredFlag = scanner.nextBoolean(); 257 assuredMode = AssuredMode.valueOf(scanner.nextByte()); 258 safeDataLevel = scanner.nextByte(); 259 } 260 261 /** 262 * Returns the encoded representation of this update message using the current 263 * protocol version. 264 * 265 * @return The encoded representation of this update message. 266 */ 267 public byte[] getBytes() 268 { 269 return getBytes(ProtocolVersion.getCurrentVersion()); 270 } 271 272 /** 273 * This implementation is only called during unit testing, so we are free to 274 * force the protocol version. Underlying implementations override this method 275 * in order to provide version specific encodings. 276 * 277 * {@inheritDoc} 278 */ 279 @Override 280 public byte[] getBytes(short protocolVersion) 281 { 282 final ByteArrayBuilder builder = encodeHeader(MSG_TYPE_GENERIC_UPDATE, 283 ProtocolVersion.getCurrentVersion()); 284 builder.appendByteArray(payload); 285 return builder.toByteArray(); 286 } 287 288 /** 289 * Get the payload of the UpdateMsg. 290 * 291 * @return The payload of the UpdateMsg. 292 */ 293 public byte[] getPayload() 294 { 295 return payload; 296 } 297 298 /** 299 * Whether the current message can update the "ds-sync-state" attribute. 300 * 301 * @return true if current message can update the "ds-sync-state" attribute, false otherwise. 302 */ 303 public boolean contributesToDomainState() 304 { 305 return true; 306 } 307}