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-2010 Sun Microsystems, Inc. 025 * Portions Copyright 2013-2015 ForgeRock AS. 026 */ 027package org.opends.server.replication.protocol; 028 029import static org.opends.server.util.StaticUtils.*; 030 031import java.util.zip.DataFormatException; 032 033import org.forgerock.i18n.LocalizableMessage; 034import org.forgerock.i18n.slf4j.LocalizedLogger; 035 036/** 037 * This message is part of the replication protocol. 038 * This message is sent by a server or a replication server when an error 039 * is detected in the context of a total update. 040 */ 041public class ErrorMsg extends RoutableMsg 042{ 043 /** The tracer object for the debug logger. */ 044 private static final LocalizedLogger logger = LocalizedLogger.getLoggerForThisClass(); 045 046 /** Specifies the messageID built from the error that was detected. */ 047 private final String msgID; 048 /** Specifies the complementary details about the error that was detected. */ 049 private final LocalizableMessage details; 050 051 /** 052 * The time of creation of this message. 053 * <p> 054 * protocol version previous to V4 055 */ 056 private long creationTime = System.currentTimeMillis(); 057 058 /** 059 * Creates an ErrorMsg providing the destination server. 060 * 061 * @param sender The server ID of the server that send this message. 062 * @param destination The destination server or servers of this message. 063 * @param details The message containing the details of the error. 064 */ 065 public ErrorMsg(int sender, int destination, LocalizableMessage details) 066 { 067 super(sender, destination); 068 this.msgID = getMessageId(details); 069 this.details = details; 070 this.creationTime = System.currentTimeMillis(); 071 072 if (logger.isTraceEnabled()) 073 { 074 logger.trace(" Creating error message" + this 075 + " " + stackTraceToSingleLineString(new Exception("trace"))); 076 } 077 } 078 079 /** 080 * Creates an ErrorMsg. 081 * 082 * @param destination replication server id 083 * @param details details of the error 084 */ 085 public ErrorMsg(int destination, LocalizableMessage details) 086 { 087 this(-2, destination, details); 088 } 089 090 /** Returns the unique message Id. */ 091 private String getMessageId(LocalizableMessage details) 092 { 093 return details.resourceName() + "-" + details.ordinal(); 094 } 095 096 /** 097 * Creates a new ErrorMsg by decoding the provided byte array. 098 * 099 * @param in A byte array containing the encoded information for the message 100 * @param version The protocol version to use to decode the msg. 101 * @throws DataFormatException If the in does not contain a properly 102 * encoded message. 103 */ 104 ErrorMsg(byte[] in, short version) throws DataFormatException 105 { 106 final ByteArrayScanner scanner = new ByteArrayScanner(in); 107 final byte msgType = scanner.nextByte(); 108 if (msgType != MSG_TYPE_ERROR) 109 { 110 throw new DataFormatException("input is not a valid " 111 + getClass().getCanonicalName()); 112 } 113 senderID = scanner.nextIntUTF8(); 114 destination = scanner.nextIntUTF8(); 115 msgID = scanner.nextString(); 116 details = LocalizableMessage.raw(scanner.nextString()); 117 118 if (version >= ProtocolVersion.REPLICATION_PROTOCOL_V4) 119 { 120 creationTime = scanner.nextLongUTF8(); 121 } 122 } 123 124 /** 125 * Get the details from this message. 126 * 127 * @return the details from this message. 128 */ 129 public LocalizableMessage getDetails() 130 { 131 return details; 132 } 133 134 /** 135 * Get the msgID from this message. 136 * 137 * @return the msgID from this message. 138 */ 139 public String getMsgID() 140 { 141 return msgID; 142 } 143 144 // ============ 145 // Msg encoding 146 // ============ 147 148 /** {@inheritDoc} */ 149 @Override 150 public byte[] getBytes(short version) 151 { 152 final ByteArrayBuilder builder = new ByteArrayBuilder(); 153 builder.appendByte(MSG_TYPE_ERROR); 154 builder.appendIntUTF8(senderID); 155 builder.appendIntUTF8(destination); 156 builder.appendString(msgID); 157 builder.appendString(details.toString()); 158 if (version >= ProtocolVersion.REPLICATION_PROTOCOL_V4) 159 { 160 builder.appendLongUTF8(creationTime); 161 } 162 return builder.toByteArray(); 163 } 164 165 /** 166 * Returns a string representation of the message. 167 * 168 * @return the string representation of this message. 169 */ 170 @Override 171 public String toString() 172 { 173 return "ErrorMessage=["+ 174 " sender=" + this.senderID + 175 " destination=" + this.destination + 176 " msgID=" + this.msgID + 177 " details=" + this.details + 178 " creationTime=" + this.creationTime + "]"; 179 } 180 181 /** 182 * Get the creation time of this message. 183 * When several attempts of initialization are done sequentially, it helps 184 * sorting the good ones, from the ones that relate to ended initialization 185 * when they are received. 186 * 187 * @return the creation time of this message. 188 */ 189 public long getCreationTime() 190 { 191 return creationTime; 192 } 193 194 /** 195 * Get the creation time of this message. 196 * @param creationTime the creation time of this message. 197 */ 198 public void setCreationTime(long creationTime) 199 { 200 this.creationTime = creationTime; 201 } 202}