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
010     * trunk/opends/resource/legal-notices/OpenDS.LICENSE
011     * or https://OpenDS.dev.java.net/OpenDS.LICENSE.
012     * See the License for the specific language governing permissions
013     * and limitations under the License.
014     *
015     * When distributing Covered Code, include this CDDL HEADER in each
016     * file and include the License file at
017     * trunk/opends/resource/legal-notices/OpenDS.LICENSE.  If applicable,
018     * add the following below this CDDL HEADER, with the fields enclosed
019     * by brackets "[]" replaced with your own identifying information:
020     *      Portions Copyright [yyyy] [name of copyright owner]
021     *
022     * CDDL HEADER END
023     *
024     *
025     *      Copyright 2006-2008 Sun Microsystems, Inc.
026     */
027    package org.opends.server.replication.protocol;
028    import org.opends.messages.Message;
029    
030    import static org.opends.server.loggers.debug.DebugLogger.debugEnabled;
031    import static org.opends.server.loggers.debug.DebugLogger.getTracer;
032    
033    import java.io.Serializable;
034    import java.io.UnsupportedEncodingException;
035    import java.util.zip.DataFormatException;
036    
037    import org.opends.server.loggers.debug.DebugTracer;
038    
039    /**
040     * This message is part of the replication protocol.
041     * This message is sent by a server or a replication server when an error
042     * is detected in the context of a total update.
043     */
044    public class ErrorMessage extends RoutableMessage implements
045        Serializable
046    {
047      private static final long serialVersionUID = 2726389860247088266L;
048    
049      // The tracer object for the debug logger
050      private static final DebugTracer TRACER = getTracer();
051    
052      // Specifies the messageID built from the error that was detected
053      private int msgID;
054    
055      // Specifies the complementary details about the error that was detected
056      private Message details = null;
057    
058      /**
059       * Creates an ErrorMessage 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 ErrorMessage(short sender, short destination,
066                          Message details)
067      {
068        super(sender, destination);
069        this.msgID  = details.getDescriptor().getId();
070        this.details = details;
071    
072        if (debugEnabled())
073          TRACER.debugInfo(" Creating error message" + this.toString());
074      }
075    
076      /**
077       * Creates an ErrorMessage.
078       *
079       * @param destination replication server id
080       * @param details details of the error
081       */
082      public ErrorMessage(short destination, Message details)
083      {
084        super((short)-2, destination);
085        this.msgID  = details.getDescriptor().getId();
086        this.details = details;
087    
088        if (debugEnabled())
089          TRACER.debugInfo(this.toString());
090      }
091    
092      /**
093       * Creates a new ErrorMessage by decoding the provided byte array.
094       *
095       * @param  in A byte array containing the encoded information for the Message
096       * @throws DataFormatException If the in does not contain a properly
097       *                             encoded message.
098       */
099      public ErrorMessage(byte[] in) throws DataFormatException
100      {
101        super();
102        try
103        {
104          /* first byte is the type */
105          if (in[0] != MSG_TYPE_ERROR)
106            throw new DataFormatException("input is not a valid InitializeMessage");
107          int pos = 1;
108    
109          // sender
110          int length = getNextLength(in, pos);
111          String senderString = new String(in, pos, length, "UTF-8");
112          senderID = Short.valueOf(senderString);
113          pos += length +1;
114    
115          // destination
116          length = getNextLength(in, pos);
117          String serverIdString = new String(in, pos, length, "UTF-8");
118          destination = Short.valueOf(serverIdString);
119          pos += length +1;
120    
121          // MsgID
122          length = getNextLength(in, pos);
123          String msgIdString = new String(in, pos, length, "UTF-8");
124          msgID = Integer.valueOf(msgIdString);
125          pos += length +1;
126    
127          // Details
128          length = getNextLength(in, pos);
129          details = Message.raw(new String(in, pos, length, "UTF-8"));
130          pos += length +1;
131    
132        }
133        catch (UnsupportedEncodingException e)
134        {
135          throw new DataFormatException("UTF-8 is not supported by this jvm.");
136        }
137      }
138    
139      /**
140       * Get the base DN from this InitializeMessage.
141       *
142       * @return the base DN from this InitializeMessage.
143       */
144      public Message getDetails()
145      {
146        return details;
147      }
148    
149      /**
150       * Get the base DN from this InitializeMessage.
151       *
152       * @return the base DN from this InitializeMessage.
153       */
154      public int getMsgID()
155      {
156        return msgID;
157      }
158    
159      /**
160       * {@inheritDoc}
161       */
162      @Override
163      public byte[] getBytes()
164      {
165        /* The InitializeMessage is stored in the form :
166         * <operation type><basedn><serverid>
167         */
168        try {
169          byte[] byteSender = String.valueOf(senderID).getBytes("UTF-8");
170          byte[] byteDestination = String.valueOf(destination).getBytes("UTF-8");
171          byte[] byteErrMsgId = String.valueOf(msgID).getBytes("UTF-8");
172          byte[] byteDetails = details.toString().getBytes("UTF-8");
173    
174          int length = 1 + byteSender.length + 1
175                         + byteDestination.length + 1
176                         + byteErrMsgId.length + 1
177                         + byteDetails.length + 1;
178    
179          byte[] resultByteArray = new byte[length];
180    
181          // put the type of the operation
182          resultByteArray[0] = MSG_TYPE_ERROR;
183          int pos = 1;
184    
185          // sender
186          pos = addByteArray(byteSender, resultByteArray, pos);
187    
188          // destination
189          pos = addByteArray(byteDestination, resultByteArray, pos);
190    
191          // MsgId
192          pos = addByteArray(byteErrMsgId, resultByteArray, pos);
193    
194          // details
195          pos = addByteArray(byteDetails, resultByteArray, pos);
196    
197          return resultByteArray;
198        }
199        catch (UnsupportedEncodingException e)
200        {
201          return null;
202        }
203      }
204    
205      /**
206       * Returns a string representation of the message.
207       *
208       * @return the string representation of this message.
209       */
210      public String toString()
211      {
212        return "ErrorMessage=["+
213          " sender=" + this.senderID +
214          " destination=" + this.destination +
215          " msgID=" + this.msgID +
216          " details=" + this.details + "]";
217      }
218    }