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 031/** 032 * This abstract message class is the superclass for start messages used 033 * by LDAP servers and Replication servers to initiate their communications. 034 * This class specifies a message header that contains the Replication 035 * Protocol version. 036 */ 037public abstract class StartMsg extends ReplicationMsg 038{ 039 /** Protocol version. */ 040 protected short protocolVersion; 041 /** Generation id of data set we want to work with. */ 042 protected long generationId; 043 /** Group id of the replicated domain. */ 044 protected byte groupId = -1; 045 046 /** 047 * Create a new StartMsg. 048 */ 049 protected StartMsg() 050 { 051 // Nothing to do. 052 } 053 054 /** 055 * Create a new StartMsg. 056 * 057 * @param protocolVersion The Replication Protocol version of the server 058 * for which the StartMsg is created. 059 * @param generationId The generationId for this server. 060 * 061 */ 062 StartMsg(short protocolVersion, long generationId) 063 { 064 this.protocolVersion = protocolVersion; 065 this.generationId = generationId; 066 } 067 068 /** 069 * Encode the header for the start message. 070 * 071 * @param msgType The type of the message to create. 072 * @param builder Additional length needed to encode the remaining 073 * part of the UpdateMessage. 074 * @param protocolVersion The version to use when encoding the header. 075 */ 076 void encodeHeader(byte msgType, ByteArrayBuilder builder, short protocolVersion) 077 { 078 /* The message header is stored in the form : 079 * <message type><protocol version><generation id><group id> 080 */ 081 builder.appendByte(msgType); 082 builder.appendByte(protocolVersion); 083 builder.appendLongUTF8(generationId); 084 builder.appendByte(groupId); 085 } 086 087 /** 088 * Encode the header for the start message. This uses the version 1 of the 089 * replication protocol (used for compatibility purpose). 090 * 091 * @param msgType The type of the message to create. 092 * @param builder The builder where to append the remaining part of the 093 * UpdateMessage. 094 */ 095 void encodeHeader_V1(byte msgType, ByteArrayBuilder builder) 096 { 097 /* The message header is stored in the form : 098 * <message type><protocol version><generation id> 099 */ 100 builder.appendByte(msgType); 101 builder.appendByte(ProtocolVersion.REPLICATION_PROTOCOL_V1_REAL); 102 builder.appendByte(0); 103 builder.appendLongUTF8(generationId); 104 } 105 106 /** 107 * Decode the Header part of this message, and check its type. 108 * 109 * @param scanner where to read the message from. 110 * @param allowedTypes The allowed types of this message. 111 * @throws DataFormatException if the encodedMsg does not contain a valid 112 * common header. 113 */ 114 void decodeHeader(final ByteArrayScanner scanner, byte... allowedTypes) 115 throws DataFormatException 116 { 117 final byte msgType = scanner.nextByte(); 118 if (!isTypeAllowed(allowedTypes, msgType)) 119 { 120 throw new DataFormatException("byte[] is not a valid start msg: " 121 + msgType); 122 } 123 124 final byte version = scanner.nextByte(); 125 126 // Filter for supported old versions PDUs 127 if (msgType == MSG_TYPE_REPL_SERVER_START_V1) 128 { 129 if (version != ProtocolVersion.REPLICATION_PROTOCOL_V1_REAL) 130 { 131 throw new DataFormatException("Not a valid message: type is " + msgType 132 + " but protocol version byte is " + version + " instead of " 133 + ProtocolVersion.REPLICATION_PROTOCOL_V1_REAL); 134 } 135 136 // Force version to V1 137 // We need to translate the MSG_TYPE_REPL_SERVER_START_V1 version 138 // into REPLICATION_PROTOCOL_V1 so that we only see V1 everywhere. 139 protocolVersion = ProtocolVersion.REPLICATION_PROTOCOL_V1; 140 141 // In V1, version was 1 (49) in string, so with a null 142 // terminating string. Let's position the cursor at the next byte 143 scanner.skipZeroSeparator(); 144 generationId = scanner.nextLongUTF8(); 145 } 146 else 147 { 148 if (version < ProtocolVersion.REPLICATION_PROTOCOL_V2) 149 { 150 throw new DataFormatException("Not a valid message: type is " + msgType 151 + " but protocol version byte is " + version + " instead of " 152 + ProtocolVersion.getCurrentVersion()); 153 } 154 protocolVersion = version; 155 generationId = scanner.nextLongUTF8(); 156 groupId = scanner.nextByte(); 157 } 158 } 159 160 private boolean isTypeAllowed(byte[] allowedTypes, final byte msgType) 161 { 162 for (byte allowedType : allowedTypes) 163 { 164 if (msgType == allowedType) 165 { 166 return true; 167 } 168 } 169 return false; 170 } 171 172 /** 173 * Get the version included in the Start message mean the replication 174 * protocol version used by the server that created the message. 175 * 176 * @return The version used by the server that created the message. 177 */ 178 public short getVersion() 179 { 180 return protocolVersion; 181 } 182 183 /** 184 * Get the generationId from this message. 185 * @return The generationId. 186 */ 187 public long getGenerationId() 188 { 189 return generationId; 190 } 191 192 /** 193 * Get the group id in this message. 194 * @return The group id in this message 195 */ 196 public byte getGroupId() 197 { 198 return groupId; 199 } 200 201 /** 202 * Set the group id in this message (For test purpose). 203 * @param groupId The group id to set. 204 */ 205 public void setGroupId(byte groupId) 206 { 207 this.groupId = groupId; 208 } 209}