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.daemon;
20
21 import java.io.IOException;
22 import java.io.ObjectInput;
23
24 import jgroup.relacs.mss.MssConstants;
25 import jgroup.relacs.types.GroupId;
26 import jgroup.relacs.types.GroupIndex;
27 import jgroup.relacs.types.MessageId;
28 import jgroup.relacs.types.ViewId;
29 import jgroup.util.MsgFactory;
30 import jgroup.util.OutMessage;
31
32 /**
33 * The <code>MsgAck</code> class contain methods to encode and decode
34 * ACK messages from remote hosts. The ACK message structure is the
35 * following:
36 * <p>
37 * <code>
38 * +-------+-------+-------+-------+-------+ ....... +-------+
39 * | GID | VID | HPOS | VLEN | ACK | | ACK |
40 * | | | | | 1 | | VLEN |
41 * +-------+-------+-------+-------+-------+ ....... +-------+
42 * </code>
43 *
44 * @author Alberto Montresor
45 * @since Jgroup 0.1
46 */
47 final class MsgAck
48 implements MssConstants, DaemonMsg
49 {
50
51 ////////////////////////////////////////////////////////////////////////////////////////////
52 // Position constants
53 ////////////////////////////////////////////////////////////////////////////////////////////
54
55 private static final int START = MSS_HEADER_SIZE;
56
57
58 ////////////////////////////////////////////////////////////////////////////////////////////
59 // Unique message instance
60 ////////////////////////////////////////////////////////////////////////////////////////////
61
62 /**
63 * As these messages are never stored by the daemon, a single message
64 * instance is sufficient. In this way, we save the costs of
65 * allocating and garbage collecting messages.
66 */
67 private static MsgAck msg = new MsgAck();
68
69 /** The marshalled message data (also static for same reason as above) */
70 private static OutMessage outmsg;
71
72
73 ////////////////////////////////////////////////////////////////////////////////////////////
74 // Fields
75 ////////////////////////////////////////////////////////////////////////////////////////////
76
77 /** View identifier */
78 long vid;
79
80 /** Host index in the view */
81 int hpos;
82
83 /** Acknowledgement numbers for each host in the current view */
84 int[] ack;
85
86
87 ////////////////////////////////////////////////////////////////////////////////////////////
88 // Methods
89 ////////////////////////////////////////////////////////////////////////////////////////////
90
91 /**
92 * Returns a <code>MsgAck</code> object that contains the decoding of
93 * the m-received input stream.
94 *
95 * @param stream the message input stream to decode
96 */
97 static MsgAck unmarshal(ObjectInput stream)
98 throws IOException
99 {
100 msg.vid = ViewId.unmarshal(stream);
101 msg.hpos = GroupIndex.unmarshal(stream);
102
103 /* Read length and content of the ack array */
104 int len = GroupIndex.unmarshal(stream);
105 msg.ack = new int[len];
106 for (int i=0; i < len; i++) // Read ack fields
107 msg.ack[i] = MessageId.unmarshal(stream);
108
109 return msg;
110 }
111
112
113 /**
114 * Returns a output stream containing the encoding of a
115 * <code>MsgAck</code> message.
116 *
117 * @param gid group identifier
118 * @param vid view identifier
119 * @param hpos host index in the view
120 */
121 static MsgAck marshal(int gid, long vid, int hpos, int[] acks, int nreceivers)
122 throws IOException
123 {
124 // Allocates data buffer
125 int size = START + GroupId.SIZE + ViewId.SIZE + GroupIndex.SIZE*2 + MessageId.SIZE*acks.length;
126 outmsg = MsgFactory.get(size, nreceivers);
127 outmsg.seek(START);
128
129 GroupId.marshal(outmsg, gid);
130 ViewId.marshal(outmsg, vid);
131 GroupIndex.marshal(outmsg, hpos);
132 GroupIndex.marshal(outmsg, acks.length);
133 for (int i=0; i < acks.length; i++)
134 MessageId.marshal(outmsg, acks[i]);
135
136 return msg;
137 }
138
139
140 ////////////////////////////////////////////////////////////////////////////////////////////
141 // Methods from DaemonMsg
142 ////////////////////////////////////////////////////////////////////////////////////////////
143
144 public int size()
145 {
146 /* Note; it is ok to use the outmsg size since MsgAck will never be
147 * forwarded or resent. */
148 return outmsg.size();
149 }
150
151 public OutMessage getOutMessage()
152 {
153 return outmsg;
154 }
155
156
157 ////////////////////////////////////////////////////////////////////////////////////////////
158 // Methods from Object
159 ////////////////////////////////////////////////////////////////////////////////////////////
160
161 /**
162 * Returns a string representation of this object
163 */
164 public String toString()
165 {
166 StringBuilder buffer = new StringBuilder();
167 buffer.append("[MsgAck: vid=");
168 buffer.append(vid);
169 buffer.append(", hpos=");
170 buffer.append(hpos);
171 buffer.append(", ack={");
172 for (int i=0; i < ack.length; i++) {
173 buffer.append(ack[i]);
174 if (i != ack.length-1)
175 buffer.append(", ");
176 }
177 buffer.append("}]");
178 return buffer.toString();
179 }
180
181 } // END MsgAck