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