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