1 /*
2 * $HeadURL: /cvsroot/insight/Insight/remote-protocol/src/com/mindtree/insight/remoteprotocol/PacketDataSizeOverLimitsException.java,v $
3 * $Date: 2005/08/09 18:39:17 $
4 * $Revision: 1.1 $
5 * $Author: m1001025 $
6 *
7 * Copyright (c) 2005 MindTree Consulting Ltd.
8 *
9 * This file is part of Insight Remote Protocol Library.
10 *
11 * Insight Remote Protocol Library is free software: you can redistribute it
12 * and/or modify it under the terms of the GNU General Public License as
13 * published by the Free Software Foundation, either version 3 of the License,
14 * or (at your option) any later version.
15 *
16 * Insight Remote Protocol Library is distributed in the hope that it will be
17 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
19 * Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License along with
22 * Insight Remote Protocol Library. If not, see <http://www.gnu.org/licenses/>.
23 */
24
25 package com.mindtree.techworks.insight.remoteprotocol.spi;
26
27 import java.net.InetAddress;
28 import java.net.UnknownHostException;
29 import java.nio.charset.CharacterCodingException;
30
31 import com.mindtree.techworks.insight.remoteprotocol.PacketDataSizeOverLimitsException;
32 import com.mindtree.techworks.insight.remoteprotocol.RemoteProtocolException;
33 import com.mindtree.techworks.insight.remoteprotocol.util.ByteUtils;
34
35 /**
36 * The content type of a startup message. This message is transmitted before any
37 * LogMessage is transmitted from a particular source. This message is also
38 * retransmitted intermittently from the source.
39 *
40 * <pre>
41 * 0 8 16 24 32
42 * | . . . . . . . | . . . . . . . | . . . . . . . | . . . . . . . |
43 *
44 * +---------------+---------------+-------------------------------+
45 * |R| UNUSED (0) | VERSION | NAMESPACE (To End) |
46 * +-+-------------+---------------+-------------------------------+
47 *
48 * | . . . . . . . | . . . . . . . | . . . . . . . | . . . . . . . |
49 * 0 8 16 24 32
50 *
51 * R - Retransmission Indicator: 0 - First Transmission, 1 - Retransmission
52 * </pre>
53 *
54 * @see com.mindtree.techworks.insight.remoteprotocol.spi.PacketDataContent
55 * @author <a href="mailto:bindul_bhowmik@mindtree.com">Bindul Bhowmik</a>
56 * @version $Revision: 1.2 $ $Date: 2005/08/09 18:39:17 $
57 */
58 public class StartupMessageDataContent extends PacketDataContent {
59
60 // -------------------------------------------------------------------------
61 // Class variables
62 // -------------------------------------------------------------------------
63
64 /**
65 * The serial version UID for the serialized form
66 */
67 private static final long serialVersionUID = -5321147203534982253L;
68
69 /**
70 * Filter mask to identify the Retransmission Indicator. The filter used to
71 * check and set the Retransmission Indicator in the message. 256 is 2^8 or
72 * 10000000 binary.
73 */
74 private static final int RETRANSMISSION_INDICATOR_FILTER = 256;
75
76 // -------------------------------------------------------------------------
77 // Instance variables
78 // -------------------------------------------------------------------------
79
80 /**
81 * Indicates if the packet is a retransmission
82 */
83 private boolean retransmission;
84
85 /**
86 * The version of the message, currently 1.
87 */
88 private byte version = 1;
89
90 /**
91 * The namespace contained in the message
92 */
93 private String namespace;
94
95 // -------------------------------------------------------------------------
96 // Constructors
97 // -------------------------------------------------------------------------
98
99 /**
100 * Creates a new StartupMessageDataContent object.
101 *
102 * @see PacketDataContent#PacketDataContent()
103 */
104 public StartupMessageDataContent() {
105
106 super();
107 this.messageType = MessageType.STARTUP_MESSAGE;
108 this.version = 1;
109 }
110
111 /**
112 * Creates an instance of the StartupMessageDataContent
113 *
114 * @see PacketDataContent#PacketDataContent(byte[], PacketHeader)
115 * @param completePacketData
116 * The data for the complete packet.
117 * @param packetHeader
118 * The header for the packet
119 * @throws RemoteProtocolException
120 * If the message type in the PacketHeader is not
121 * <code>MessageType#STARTUP_MESSAGE_TYPE</code>
122 */
123 public StartupMessageDataContent(byte[] completePacketData,
124 PacketHeader packetHeader) throws RemoteProtocolException {
125
126 super(completePacketData, packetHeader);
127 if (!MessageType.STARTUP_MESSAGE.equals(this.messageType)) {
128 throw new RemoteProtocolException("Incompatible message type");
129 }
130 readFieldsFromData();
131 }
132
133 // -------------------------------------------------------------------------
134 // Methods overridden from PacketDataContent
135 // -------------------------------------------------------------------------
136
137 /**
138 * Sets the packet data. The fields in this class are updated right after
139 * setting the data.
140 *
141 * @throws RemoteProtocolException
142 * If the fields cannot be interpretted correctly.
143 * @see com.mindtree.techworks.insight.remoteprotocol.spi.PacketDataContent#setPacketData(byte[])
144 */
145 public void setPacketData(byte[] packetData) throws RemoteProtocolException {
146
147 super.setPacketData(packetData);
148 readFieldsFromData();
149 }
150
151 // -------------------------------------------------------------------------
152 // Accessors
153 // -------------------------------------------------------------------------
154
155 /**
156 * Returns the namespace
157 *
158 * @return Returns the namespace.
159 */
160 public String getNamespace() {
161
162 return namespace;
163 }
164
165 /**
166 * Sets the namespace
167 *
168 * @param namespace
169 * The namespace to set.
170 * @throws PacketDataSizeOverLimitsException
171 * If the packet data size is over limits
172 */
173 public void setNamespace(String namespace)
174 throws PacketDataSizeOverLimitsException, RemoteProtocolException {
175
176 this.namespace = namespace;
177 setDataFromFields();
178 }
179
180 /**
181 * Returns the retransmission
182 *
183 * @return Returns the retransmission.
184 */
185 public boolean isRetransmission() {
186
187 return retransmission;
188 }
189
190 /**
191 * Sets the retransmission
192 *
193 * @param retransmission
194 * The retransmission to set.
195 */
196 public void setRetransmission(boolean retransmission) {
197
198 this.retransmission = retransmission;
199 try {
200 setDataFromFields();
201 } catch (PacketDataSizeOverLimitsException e) {
202 // This exception should never come for setting a boolean. So
203 // consuming it
204 } catch (RemoteProtocolException e) {
205 // TODO Auto-generated catch block
206 e.printStackTrace();
207 }
208 }
209
210 /**
211 * Returns the version
212 *
213 * @return Returns the version.
214 */
215 public byte getVersion() {
216
217 return version;
218 }
219
220 // -------------------------------------------------------------------------
221 // Private Util methods
222 // -------------------------------------------------------------------------
223
224 /**
225 * Creates the data byte array for this instance from the fields. This
226 * method should be called after every 'set' operation on the fields of this
227 * class, except when the data is set as a byte array.
228 *
229 * @throws PacketDataSizeOverLimitsException
230 * If the data size is higher than the limit.
231 * @throws RemoteProtocolException
232 * If we have an error in the data
233 */
234 private void setDataFromFields() throws PacketDataSizeOverLimitsException,
235 RemoteProtocolException {
236
237 // Namespace cannot be sent as null
238 if (null == namespace || namespace.length() == 0) {
239 String localHost;
240 try {
241 localHost = InetAddress.getLocalHost().getCanonicalHostName();
242 } catch (UnknownHostException e) {
243 // Do nothing here
244 localHost = "localhost";
245 }
246 namespace = "insight://" + localHost + "/"
247 + System.currentTimeMillis();
248 }
249
250 byte[] dataBytes = new byte[2 + 2 * namespace.length()];
251
252 if (retransmission) {
253 dataBytes[0] = (byte) RETRANSMISSION_INDICATOR_FILTER;
254 } else {
255 dataBytes[0] = 0;
256 }
257
258 dataBytes[1] = 1;
259
260 byte[] namespaceBytes;
261 try {
262 namespaceBytes = ByteUtils.getByteArrayForString(namespace);
263 } catch (CharacterCodingException e) {
264 throw new RemoteProtocolException("Unable to encode data.", e);
265 }
266 System
267 .arraycopy(namespaceBytes, 0, dataBytes, 2,
268 namespaceBytes.length);
269
270 checkPacketDataSize(dataBytes);
271 this.packetData = dataBytes;
272 }
273
274 /**
275 * Interprets the fields of this instance from the data.
276 *
277 * @throws RemoteProtocolException
278 * If the fields cannot be interpretted.
279 */
280 private void readFieldsFromData() throws RemoteProtocolException {
281
282 if (getLength() < 4) {
283 throw new RemoteProtocolException("Too Short Data!");
284 }
285
286 // TODO Think about this
287 this.retransmission = ((packetData[0] & 0xFFFFFF00) & RETRANSMISSION_INDICATOR_FILTER) == RETRANSMISSION_INDICATOR_FILTER;
288 this.version = packetData[1];
289
290 if (this.version != 0x01) {
291 throw new RemoteProtocolException("Invalid Startup Message Version");
292 }
293
294 int dataSize = getLength();
295
296 try {
297 this.namespace = ByteUtils.readStringFromByteArray(packetData, 2, dataSize - 2);
298 } catch (CharacterCodingException e) {
299 throw new RemoteProtocolException("Unable to decode namespace", e);
300 }
301 }
302
303 }