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}