View Javadoc

1   /*
2    * Copyright (c) 1998-2002 The Jgroup Team.
3    *
4    * This program is free software; you can redistribute it and/or modify
5    * it under the terms of the GNU Lesser General Public License version 2 as
6    * published by the Free Software Foundation.
7    *
8    * This program is distributed in the hope that it will be useful,
9    * but WITHOUT ANY WARRANTY; without even the implied warranty of
10   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11   * GNU Lesser General Public License for more details.
12   *
13   * You should have received a copy of the GNU Lesser General Public License
14   * along with this program; if not, write to the Free Software
15   * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
16   *
17   */
18  
19  package jgroup.relacs.mss;
20  
21  import java.io.IOException;
22  
23  import jgroup.core.ConfigManager;
24  import jgroup.core.EndPoint;
25  import jgroup.core.JgroupException;
26  import jgroup.relacs.types.EndPointImpl;
27  import jgroup.relacs.types.Flag;
28  import jgroup.relacs.types.IncarnationId;
29  import jgroup.relacs.types.MessageId;
30  import jgroup.relacs.types.MessageTag;
31  import jgroup.util.InMessage;
32  import jgroup.util.Util;
33  
34  /**
35   *  This class contains the <i>mss</i> level fragment header data.
36   *
37   *  @author Hein Meling
38   *  @since Jgroup 1.2
39   */
40  public final class FragmentHeader
41    implements MssTag, MssConstants
42  {
43  
44    ////////////////////////////////////////////////////////////////////////////////////////////
45    // Constants
46    ////////////////////////////////////////////////////////////////////////////////////////////
47  
48    /** Size of this object in bytes */
49    private static final int SIZE = HEADER_SIZE;
50  
51    /** The position in the msg fragment where the tag byte can be set */
52    private static final short TAG_POSITION = 0;
53  
54    /** The position in the msg fragment where the broadcast bit can be set */
55    private static final short BROADCAST_POSITION = 1;
56  
57  
58    ////////////////////////////////////////////////////////////////////////////////////////////
59    // Message Header Fields
60    ////////////////////////////////////////////////////////////////////////////////////////////
61  
62    /** The tag associated with this message fragment */
63    private byte tag;
64  
65    /** True if the message fragment has to be broadcast in the cluster */
66    private boolean toBeBroadcast;
67  
68    /** The fragment identifier */
69    int fragId;
70  
71    /** The message sender (only the endpoint is transmitted, thus this field is transient) */
72    private transient MssHost sender;
73  
74    /** The incarnation identifier */
75    private int incarnationId;
76  
77  
78    ////////////////////////////////////////////////////////////////////////////////////////////
79    // Transient Fields
80    ////////////////////////////////////////////////////////////////////////////////////////////
81  
82    /** The message fragment associated with this header */
83    private transient byte[] msgFragment;
84  
85    /** The length of the fragment associated with this header */
86    private transient int fragLen;
87  
88  
89    ////////////////////////////////////////////////////////////////////////////////////////////
90    // Marshalling / Unmarshalling methods and Constructors
91    ////////////////////////////////////////////////////////////////////////////////////////////
92  
93    /**
94     *  Marshals the given <code>FragmentHeader</code> values into a byte
95     *  array and returns it.  The size of the array is equal to the
96     *  fragment header standard size.  This method is useful if we want
97     *  to send a single message fragment, in which only the tag reveals
98     *  the semantics of the message.  For example to notify others of
99     *  some event, that does not need additional data.
100    *
101    *  At the sender side, we don't keep any of the input parameters, we
102    *  just marshal it directly into the created <code>outstream</code>
103    *  byte array that is returned from this method.
104    */
105   public static byte[] marshal(byte tag, boolean broadcast, int fragId)
106   {
107     byte[] outstream = new byte[SIZE];
108     marshal(tag, broadcast, fragId, outstream);
109     return outstream;
110   }
111 
112 
113   /**
114    *  Marshals the given <code>FragmentHeader</code> values into the
115    *  specified <code>byte[] outstream</code>, without creating an
116    *  object.  This marshal method does not change the sender related
117    *  fields, such as the inet address, port and incarnation identifier.
118    *  It will only set the broadcast and fragment identifier values. <p>
119    *
120    *  At the sender side, we don't keep any of the input parameters, we
121    *  just marshal it directly into the <code>outstream</code> byte
122    *  array.
123    */
124   public static void marshal(boolean broadcast, int fragId, byte[] outstream)
125   {
126     int offset = BROADCAST_POSITION;
127     outstream[offset++] = (byte) (broadcast ? 1 : 0);
128 
129     outstream[offset++] = (byte) (fragId >>> 24);
130     outstream[offset++] = (byte) (fragId >>> 16);
131     outstream[offset++] = (byte) (fragId >>>  8);
132     outstream[offset]   = (byte) (fragId >>>  0);
133   }
134 
135 
136   /**
137    *  Marshals the given <code>FragmentHeader</code> values into the
138    *  specified <code>byte[] outstream</code>, without creating an
139    *  object. <p>
140    *
141    *  At the sender side, we don't keep any of the input parameters, we
142    *  just marshal it directly into the <code>outstream</code> byte
143    *  array.
144    */
145   public static void marshal(byte tag, boolean broadcast, int fragId, byte[] outstream)
146   {
147     /* At the sender side the local host is equal to the sender */
148     MssHost sender    = HostTable.getLocalHost();
149     int incId         = sender.getIncarnationId();
150     EndPoint endpoint = sender.getEndPoint();
151     int intAddress    = endpoint.getIntAddress();
152     int port          = endpoint.getPort();
153 
154     int offset = TAG_POSITION;
155     outstream[offset++] = tag;
156 
157     outstream[offset++] = (byte) (broadcast ? 1 : 0);
158 
159     outstream[offset++] = (byte) (fragId >>> 24);
160     outstream[offset++] = (byte) (fragId >>> 16);
161     outstream[offset++] = (byte) (fragId >>>  8);
162     outstream[offset++] = (byte) (fragId >>>  0);
163 
164     outstream[offset++] = (byte) (intAddress >>> 24);
165     outstream[offset++] = (byte) (intAddress >>> 16);
166     outstream[offset++] = (byte) (intAddress >>>  8);
167     outstream[offset++] = (byte) (intAddress >>>  0);
168 
169     outstream[offset++] = (byte) (port >>>  8);
170     outstream[offset++] = (byte) (port >>>  0);
171 
172     outstream[offset++] = (byte) (incId >>> 24);
173     outstream[offset++] = (byte) (incId >>> 16);
174     outstream[offset++] = (byte) (incId >>>  8);
175     outstream[offset]   = (byte) (incId >>>  0);
176   }
177 
178 
179   public static FragmentHeader unmarshal(MssDS mssds, byte[] instream, int fragLen)
180     throws IOException, ClassNotFoundException, JgroupException
181   {
182     return new FragmentHeader(mssds, instream, fragLen);
183   }
184 
185 
186   private FragmentHeader(MssDS mssds, byte[] instream, int fragLen)
187     throws IOException, ClassNotFoundException, JgroupException
188   {
189     /* Keep the message fragment for later reference */
190     this.msgFragment = instream;
191     this.fragLen = fragLen;
192     InMessage inmsg = new InMessage(SIZE, 0, 0, SIZE);
193     inmsg.insert(instream, SIZE);
194     tag = MessageTag.unmarshal(inmsg);
195     toBeBroadcast = Flag.unmarshal(inmsg);
196     fragId = MessageId.unmarshal(inmsg);
197     EndPoint endpoint = new EndPointImpl();
198     endpoint.readExternal(inmsg);
199     sender = mssds.hostLookup(endpoint);
200     if (sender == null) {
201       throw new JgroupException("Received a packet from an unknown host: " + endpoint);
202     }
203     incarnationId = IncarnationId.unmarshal(inmsg);
204   }
205 
206 
207   ////////////////////////////////////////////////////////////////////////////////////////////
208   // Access methods
209   ////////////////////////////////////////////////////////////////////////////////////////////
210 
211   /**
212    *  Returns the tag associated with this message.
213    */
214   public byte getTag() 
215   {
216     return tag;
217   }
218 
219 
220   /**
221    *  Set the tag associated with this message.
222    */
223   public void setTag(byte tag)
224   {
225     this.tag = tag;
226     msgFragment[TAG_POSITION] = tag;
227   }
228 
229 
230   /**
231    *  Returns the message fragment associated with this header.
232    */
233   public byte[] getFragment() 
234   {
235     return msgFragment;
236   }
237 
238 
239   /**
240    *  Returns the length of the fragment associated with this header.
241    */
242   public int getFragmentLength() 
243   {
244     return fragLen;
245   }
246 
247 
248   /**
249    *  Returns the sender of this message fragment.
250    */
251   public MssHost getSender()
252   {
253     return sender;
254   }
255 
256 
257   /**
258    *  Returns incarnation identifier for the sender of this message.
259    */
260   public int getIncarnationId()
261   {
262     return incarnationId;
263   }
264 
265 
266   /**
267    *  Returns true if the sender of this message is the local host.
268    */
269   public boolean isLocal()
270   {
271     return sender.isLocal();
272   }
273 
274 
275   /**
276    *  Returns true if this message is a broadcast message.  False is
277    *  returned otherwise.
278    */
279   public boolean isBroadcast()
280   {
281     return toBeBroadcast;
282   }
283 
284 
285   public void broadcastOff()
286   {
287     toBeBroadcast = false;
288     msgFragment[BROADCAST_POSITION] = 0;
289   }
290 
291 
292   /**
293    *  Returns true if this message represents the last fragment of a
294    *  message flow.
295    */
296   boolean isLastFragment()
297   {
298     return (tag != NOTLASTFRAGMENT);
299   }
300 
301 
302   ////////////////////////////////////////////////////////////////////////////////////////////
303   // Methods from Object
304   ////////////////////////////////////////////////////////////////////////////////////////////
305 
306   /**
307    *  Print the content of the <code>FragmentHeader</code>.
308    */
309   public String toString() {
310     StringBuilder buf = new StringBuilder("[FragmentHeader: tag=");
311     switch (tag) {
312     case IAMALIVE:
313       buf.append("IAMALIVE");
314       break;
315     case SENT:
316       buf.append("SENT");
317       break;
318     case ROUTING:
319       buf.append("ROUTING");
320       break;
321     case FWDROUTING:
322       buf.append("FWDROUTING");
323       break;
324     case SYN:
325       buf.append("SYN");
326       break;
327     case NACK:
328       buf.append("NACK");
329       break;
330     case JG:
331       buf.append("JG");
332       break;
333     case NOTLASTFRAGMENT:
334       buf.append("NLF");
335       break;
336     default:
337       buf.append("Unknown tag=");
338       buf.append(tag);
339       break;
340     }
341     buf.append(", fragId=");
342     buf.append(fragId);
343     buf.append(", sender=");
344     buf.append(sender);
345     buf.append(", incId=");
346     buf.append(incarnationId);
347     buf.append(", fragSize=");
348     buf.append(fragLen);
349     buf.append(", bcast=");
350     buf.append(toBeBroadcast);
351     if (ConfigManager.logMsgContent) {
352       buf.append(", packet=[");
353       for (int i = 0; i < fragLen; i++) {
354         buf.append(" ");
355         buf.append(Util.byte2str(msgFragment[i]));
356       }
357     }
358     buf.append("]");
359     return buf.toString();
360   }
361 
362 } // END FragmentHeader