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