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.Serializable;
030    import java.io.UnsupportedEncodingException;
031    import java.net.InetAddress;
032    import java.net.UnknownHostException;
033    import java.util.zip.DataFormatException;
034    
035    import org.opends.server.replication.common.ServerState;
036    import org.opends.server.types.DN;
037    import org.opends.server.types.DirectoryException;
038    
039    /**
040     * This message is used by LDAP server when they first connect.
041     * to a replication server to let them know who they are and what is their state
042     * (their RUV)
043     */
044    public class ServerStartMessage extends StartMessage implements
045        Serializable
046    {
047      private static final long serialVersionUID = 8649393307038290287L;
048    
049      private short serverId; // Id of the LDAP server that sent this message
050      private String serverURL;
051      private String baseDn;
052      private int maxReceiveQueue;
053      private int maxSendQueue;
054      private int maxReceiveDelay;
055      private int maxSendDelay;
056      private int windowSize;
057      private boolean handshakeOnly;
058      private ServerState serverState = null;
059    
060      /**
061       * The time in milliseconds between heartbeats from the replication
062       * server.  Zero means heartbeats are off.
063       */
064      private long heartbeatInterval = 0;
065    
066      /**
067       * Whether to continue using SSL to encrypt messages after the start
068       * messages have been exchanged.
069       */
070      private boolean sslEncryption;
071    
072      /**
073       * Creates a new ServerStartMessage. This message is to be sent by an LDAP
074       * Server after being connected to a replication server for a given
075       * replication domain.
076       *
077       * @param serverId The serverId of the server for which the ServerStartMessage
078       *                 is created.
079       * @param baseDn   The base DN.
080       * @param maxReceiveDelay The max receive delay for this server.
081       * @param maxReceiveQueue The max receive Queue for this server.
082       * @param maxSendDelay The max Send Delay from this server.
083       * @param maxSendQueue The max send Queue from this server.
084       * @param windowSize   The window size used by this server.
085       * @param heartbeatInterval The requested heartbeat interval.
086       * @param serverState  The state of this server.
087       * @param protocolVersion The replication protocol version of the creator.
088       * @param generationId The generationId for this server.
089       * @param sslEncryption Whether to continue using SSL to encrypt messages
090       *                      after the start messages have been exchanged.
091       * @param handshakeOnly Whether this message is only to get an handshake
092       *                      with the server or not.
093       */
094      public ServerStartMessage(short serverId, DN baseDn, int maxReceiveDelay,
095                                int maxReceiveQueue, int maxSendDelay,
096                                int maxSendQueue, int windowSize,
097                                long heartbeatInterval,
098                                ServerState serverState,
099                                short protocolVersion,
100                                long generationId,
101                                boolean sslEncryption,
102                                boolean handshakeOnly)
103      {
104        super(protocolVersion, generationId);
105    
106        this.serverId = serverId;
107        this.baseDn = baseDn.toString();
108        this.maxReceiveDelay = maxReceiveDelay;
109        this.maxReceiveQueue = maxReceiveQueue;
110        this.maxSendDelay = maxSendDelay;
111        this.maxSendQueue = maxSendQueue;
112        this.windowSize = windowSize;
113        this.heartbeatInterval = heartbeatInterval;
114        this.sslEncryption = sslEncryption;
115        this.serverState = serverState;
116        this.handshakeOnly = handshakeOnly;
117    
118        try
119        {
120          /* TODO : find a better way to get the server URL */
121          this.serverURL = InetAddress.getLocalHost().getHostName();
122        } catch (UnknownHostException e)
123        {
124          this.serverURL = "Unknown host";
125        }
126      }
127    
128      /**
129       * Creates a new ServerStartMessage from its encoded form.
130       *
131       * @param in The byte array containing the encoded form of the
132       *           ServerStartMessage.
133       * @throws DataFormatException If the byte array does not contain a valid
134       *                             encoded form of the ServerStartMessage.
135       */
136      public ServerStartMessage(byte[] in) throws DataFormatException
137      {
138        super(MSG_TYPE_SERVER_START, in);
139    
140        try
141        {
142          /* first bytes are the header */
143          int pos = headerLength;
144    
145          /*
146           * read the dn
147           * first calculate the length then construct the string
148           */
149          int length = getNextLength(in, pos);
150          baseDn = new String(in, pos, length, "UTF-8");
151          pos += length +1;
152    
153          /*
154           * read the ServerId
155           */
156          length = getNextLength(in, pos);
157          String serverIdString = new String(in, pos, length, "UTF-8");
158          serverId = Short.valueOf(serverIdString);
159          pos += length +1;
160    
161          /*
162           * read the ServerURL
163           */
164          length = getNextLength(in, pos);
165          serverURL = new String(in, pos, length, "UTF-8");
166          pos += length +1;
167    
168          /*
169           * read the maxReceiveDelay
170           */
171          length = getNextLength(in, pos);
172          maxReceiveDelay = Integer.valueOf(new String(in, pos, length, "UTF-8"));
173          pos += length +1;
174    
175          /*
176           * read the maxReceiveQueue
177           */
178          length = getNextLength(in, pos);
179          maxReceiveQueue = Integer.valueOf(new String(in, pos, length, "UTF-8"));
180          pos += length +1;
181    
182          /*
183           * read the maxSendDelay
184           */
185          length = getNextLength(in, pos);
186          maxSendDelay = Integer.valueOf(new String(in, pos, length, "UTF-8"));
187          pos += length +1;
188    
189          /*
190           * read the maxSendQueue
191           */
192          length = getNextLength(in, pos);
193          maxSendQueue = Integer.valueOf(new String(in, pos, length, "UTF-8"));
194          pos += length +1;
195    
196          /*
197           * read the windowSize
198           */
199          length = getNextLength(in, pos);
200          windowSize = Integer.valueOf(new String(in, pos, length, "UTF-8"));
201          pos += length +1;
202    
203          /*
204           * read the heartbeatInterval
205           */
206          length = getNextLength(in, pos);
207          heartbeatInterval = Integer.valueOf(new String(in, pos, length, "UTF-8"));
208          pos += length +1;
209    
210          /*
211           * read the sslEncryption setting
212           */
213          length = getNextLength(in, pos);
214          sslEncryption = Boolean.valueOf(new String(in, pos, length, "UTF-8"));
215          pos += length +1;
216    
217    
218          /*
219           * read the handshakeOnly flag
220           */
221          length = getNextLength(in, pos);
222          handshakeOnly = Boolean.valueOf(new String(in, pos, length, "UTF-8"));
223          pos += length +1;
224    
225          /*
226          * read the ServerState
227          */
228          serverState = new ServerState(in, pos, in.length-1);
229    
230        } catch (UnsupportedEncodingException e)
231        {
232          throw new DataFormatException("UTF-8 is not supported by this jvm.");
233        }
234      }
235    
236      /**
237       * Get the ServerID from the message.
238       * @return the server ID
239       */
240      public short getServerId()
241      {
242        return serverId;
243      }
244    
245      /**
246       * get the Server URL from the message.
247       * @return the server URL
248       */
249      public String getServerURL()
250      {
251        return serverURL;
252      }
253    
254      /**
255       * Get the baseDn.
256       * @return Returns the baseDn.
257       */
258      public DN getBaseDn()
259      {
260        try
261        {
262          return DN.decode(baseDn);
263        } catch (DirectoryException e)
264        {
265          return null;
266        }
267      }
268    
269      /**
270       * Get the maxReceiveDelay.
271       * @return Returns the maxReceiveDelay.
272       */
273      public int getMaxReceiveDelay()
274      {
275        return maxReceiveDelay;
276      }
277    
278      /**
279       * Get the maxReceiveQueue.
280       * @return Returns the maxReceiveQueue.
281       */
282      public int getMaxReceiveQueue()
283      {
284        return maxReceiveQueue;
285      }
286    
287      /**
288       * Get the maxSendDelay.
289       * @return Returns the maxSendDelay.
290       */
291      public int getMaxSendDelay()
292      {
293        return maxSendDelay;
294      }
295    
296      /**
297       * Get the maxSendQueue.
298       * @return Returns the maxSendQueue.
299       */
300      public int getMaxSendQueue()
301      {
302        return maxSendQueue;
303      }
304    
305      /**
306       * Get the ServerState.
307       * @return The ServerState.
308       */
309      public ServerState getServerState()
310      {
311        return serverState;
312      }
313    
314      /**
315       * {@inheritDoc}
316       */
317      @Override
318      public byte[] getBytes()
319      {
320        try {
321          byte[] byteDn = baseDn.getBytes("UTF-8");
322          byte[] byteServerId = String.valueOf(serverId).getBytes("UTF-8");
323          byte[] byteServerUrl = serverURL.getBytes("UTF-8");
324          byte[] byteMaxRecvDelay =
325                         String.valueOf(maxReceiveDelay).getBytes("UTF-8");
326          byte[] byteMaxRecvQueue =
327                         String.valueOf(maxReceiveQueue).getBytes("UTF-8");
328          byte[] byteMaxSendDelay =
329                         String.valueOf(maxSendDelay).getBytes("UTF-8");
330          byte[] byteMaxSendQueue =
331                         String.valueOf(maxSendQueue).getBytes("UTF-8");
332          byte[] byteWindowSize =
333                         String.valueOf(windowSize).getBytes("UTF-8");
334          byte[] byteHeartbeatInterval =
335                         String.valueOf(heartbeatInterval).getBytes("UTF-8");
336          byte[] byteSSLEncryption =
337                         String.valueOf(sslEncryption).getBytes("UTF-8");
338          byte[] byteServerState = serverState.getBytes();
339          byte[] byteHandshakeOnly =
340            String.valueOf(handshakeOnly).getBytes("UTF-8");
341    
342          int length = byteDn.length + 1 + byteServerId.length + 1 +
343                       byteServerUrl.length + 1 +
344                       byteMaxRecvDelay.length + 1 +
345                       byteMaxRecvQueue.length + 1 +
346                       byteMaxSendDelay.length + 1 +
347                       byteMaxSendQueue.length + 1 +
348                       byteWindowSize.length + 1 +
349                       byteHeartbeatInterval.length + 1 +
350                       byteSSLEncryption.length + 1 +
351                       byteHandshakeOnly.length + 1 +
352                       byteServerState.length + 1;
353    
354          /* encode the header in a byte[] large enough to also contain the mods */
355          byte resultByteArray[] = encodeHeader(MSG_TYPE_SERVER_START, length);
356          int pos = headerLength;
357    
358          pos = addByteArray(byteDn, resultByteArray, pos);
359    
360          pos = addByteArray(byteServerId, resultByteArray, pos);
361    
362          pos = addByteArray(byteServerUrl, resultByteArray, pos);
363    
364          pos = addByteArray(byteMaxRecvDelay, resultByteArray, pos);
365    
366          pos = addByteArray(byteMaxRecvQueue, resultByteArray, pos);
367    
368          pos = addByteArray(byteMaxSendDelay, resultByteArray, pos);
369    
370          pos = addByteArray(byteMaxSendQueue, resultByteArray, pos);
371    
372          pos = addByteArray(byteWindowSize, resultByteArray, pos);
373    
374          pos = addByteArray(byteHeartbeatInterval, resultByteArray, pos);
375    
376          pos = addByteArray(byteSSLEncryption, resultByteArray, pos);
377    
378          pos = addByteArray(byteHandshakeOnly, resultByteArray, pos);
379    
380          pos = addByteArray(byteServerState, resultByteArray, pos);
381    
382          return resultByteArray;
383        }
384        catch (UnsupportedEncodingException e)
385        {
386          return null;
387        }
388      }
389    
390      /**
391       * Get the window size for the ldap server that created the message.
392       *
393       * @return The window size for the ldap server that created the message.
394       */
395      public int getWindowSize()
396      {
397        return windowSize;
398      }
399    
400      /**
401       * Get the heartbeat interval requested by the ldap server that created the
402       * message.
403       *
404       * @return The heartbeat interval requested by the ldap server that created
405       * the message.
406       */
407      public long getHeartbeatInterval()
408      {
409        return heartbeatInterval;
410      }
411    
412      /**
413       * Get the SSL encryption value for the ldap server that created the
414       * message.
415       *
416       * @return The SSL encryption value for the ldap server that created the
417       *         message.
418       */
419      public boolean getSSLEncryption()
420      {
421        return sslEncryption;
422      }
423    
424      /**
425       * Get the SSL encryption value for the ldap server that created the
426       * message.
427       *
428       * @return The SSL encryption value for the ldap server that created the
429       *         message.
430       */
431      public boolean isHandshakeOnly()
432      {
433        return handshakeOnly;
434      }
435    }