View Javadoc

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 }