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    
029    import java.io.UnsupportedEncodingException;
030    import java.util.zip.DataFormatException;
031    
032    /**
033     * Abstract class that must be used when defining messages that can
034     * be sent for replication purpose between servers.
035     *
036     * When extending this class one should also create a new MSG_TYPE
037     * and should update the generateMsg() method.
038     */
039    public abstract class ReplicationMessage
040    {
041      static final byte MSG_TYPE_MODIFY_REQUEST = 1;
042      static final byte MSG_TYPE_ADD_REQUEST = 2;
043      static final byte MSG_TYPE_DELETE_REQUEST = 3;
044      static final byte MSG_TYPE_MODIFYDN_REQUEST = 4;
045      static final byte MSG_TYPE_ACK = 5;
046      static final byte MSG_TYPE_SERVER_START = 6;
047      static final byte MSG_TYPE_REPL_SERVER_START = 7;
048      static final byte MSG_TYPE_WINDOW = 8;
049      static final byte MSG_TYPE_HEARTBEAT = 9;
050      static final byte MSG_TYPE_INITIALIZE_REQUEST = 10;
051      static final byte MSG_TYPE_INITIALIZE_TARGET = 11;
052      static final byte MSG_TYPE_ENTRY = 12;
053      static final byte MSG_TYPE_DONE = 13;
054      static final byte MSG_TYPE_ERROR = 14;
055      static final byte MSG_TYPE_WINDOW_PROBE = 15;
056      static final byte MSG_TYPE_REPL_SERVER_INFO = 16;
057      static final byte MSG_TYPE_RESET_GENERATION_ID = 17;
058      static final byte MSG_TYPE_REPL_SERVER_MONITOR_REQUEST = 18;
059      static final byte MSG_TYPE_REPL_SERVER_MONITOR = 19;
060    
061      // Adding a new type of message here probably requires to
062      // change accordingly generateMsg method below
063    
064      /**
065       * Return the byte[] representation of this message.
066       * Depending on the message type, the first byte of the byte[] must be.
067       * MSG_TYPE_MODIFY_REQUEST
068       * MSG_TYPE_ADD_REQUEST
069       * MSG_TYPE_DELETE_REQUEST
070       * MSG_TYPE_MODIFY_DN_REQUEST
071       * MSG_TYPE_ACK
072       * MSG_TYPE_SERVER_START
073       * MSG_TYPE_REPL_SERVER_START
074       * MSG_TYPE_WINDOW
075       * MSG_TYPE_HEARTBEAT
076       * MSG_TYPE_INITIALIZE
077       * MSG_TYPE_INITIALIZE_TARGET
078       * MSG_TYPE_ENTRY
079       * MSG_TYPE_DONE
080       * MSG_TYPE_ERROR
081       * MSG_TYPE_WINDOW_PROBE
082       * MSG_TYPE_REPL_SERVER_INFO
083       * MSG_TYPE_RESET_GENERATION_ID
084       * MSG_TYPE_REPL_SERVER_MONITOR_REQUEST
085       * MSG_TYPE_REPL_SERVER_MONITOR
086       *
087       * @return the byte[] representation of this message.
088       * @throws UnsupportedEncodingException  When the encoding of the message
089       *         failed because the UTF-8 encoding is not supported.
090       */
091      public abstract byte[] getBytes() throws UnsupportedEncodingException;
092    
093    
094      /**
095       * Generates a ReplicationMessage from its encoded form.
096       *
097       * @param buffer The encode form of the ReplicationMessage.
098       * @return the generated SycnhronizationMessage.
099       * @throws DataFormatException if the encoded form was not a valid msg.
100       * @throws UnsupportedEncodingException if UTF8 is not supported.
101       */
102      public static ReplicationMessage generateMsg(byte[] buffer)
103                    throws DataFormatException, UnsupportedEncodingException
104      {
105        ReplicationMessage msg = null;
106        switch (buffer[0])
107        {
108          case MSG_TYPE_MODIFY_REQUEST:
109              msg = new ModifyMsg(buffer);
110          break;
111          case MSG_TYPE_ADD_REQUEST:
112              msg = new AddMsg(buffer);
113          break;
114          case MSG_TYPE_DELETE_REQUEST:
115              msg = new DeleteMsg(buffer);
116          break;
117          case MSG_TYPE_MODIFYDN_REQUEST:
118              msg = new ModifyDNMsg(buffer);
119          break;
120          case MSG_TYPE_ACK:
121            msg = new AckMessage(buffer);
122          break;
123          case MSG_TYPE_SERVER_START:
124            msg = new ServerStartMessage(buffer);
125          break;
126          case MSG_TYPE_REPL_SERVER_START:
127            msg = new ReplServerStartMessage(buffer);
128          break;
129          case MSG_TYPE_WINDOW:
130            msg = new WindowMessage(buffer);
131          break;
132          case MSG_TYPE_HEARTBEAT:
133            msg = new HeartbeatMessage(buffer);
134          break;
135          case MSG_TYPE_INITIALIZE_REQUEST:
136            msg = new InitializeRequestMessage(buffer);
137          break;
138          case MSG_TYPE_INITIALIZE_TARGET:
139            msg = new InitializeTargetMessage(buffer);
140          break;
141          case MSG_TYPE_ENTRY:
142            msg = new EntryMessage(buffer);
143          break;
144          case MSG_TYPE_DONE:
145            msg = new DoneMessage(buffer);
146          break;
147          case MSG_TYPE_ERROR:
148            msg = new ErrorMessage(buffer);
149          break;
150          case MSG_TYPE_RESET_GENERATION_ID:
151            msg = new ResetGenerationId(buffer);
152          break;
153          case MSG_TYPE_WINDOW_PROBE:
154            msg = new WindowProbe(buffer);
155          break;
156          case MSG_TYPE_REPL_SERVER_INFO:
157            msg = new ReplServerInfoMessage(buffer);
158          break;
159          case MSG_TYPE_REPL_SERVER_MONITOR_REQUEST:
160            msg = new MonitorRequestMessage(buffer);
161          break;
162          case MSG_TYPE_REPL_SERVER_MONITOR:
163            msg = new MonitorMessage(buffer);
164          break;
165          default:
166            throw new DataFormatException("received message with unknown type");
167        }
168        return msg;
169      }
170    
171      /**
172       * Concatenate the tail byte array into the resultByteArray.
173       * The resultByteArray must be large enough before calling this method.
174       *
175       * @param tail the byte array to concatenate.
176       * @param resultByteArray The byte array to concatenate to.
177       * @param pos the position where to concatenate.
178       * @return the next position to use in the resultByteArray.
179       */
180      protected int addByteArray(byte[] tail, byte[] resultByteArray, int pos)
181      {
182        for (int i=0; i<tail.length; i++,pos++)
183        {
184          resultByteArray[pos] = tail[i];
185        }
186        resultByteArray[pos++] = 0;
187        return pos;
188      }
189    
190      /**
191       * Get the length of the next String encoded in the in byte array.
192       *
193       * @param in the byte array where to calculate the string.
194       * @param pos the position whre to start from in the byte array.
195       * @return the length of the next string.
196       * @throws DataFormatException If the byte array does not end with null.
197       */
198      protected int getNextLength(byte[] in, int pos) throws DataFormatException
199      {
200        int offset = pos;
201        int length = 0;
202        while (in[offset++] != 0)
203        {
204          if (offset >= in.length)
205            throw new DataFormatException("byte[] is not a valid msg");
206          length++;
207        }
208        return length;
209      }
210    }