001: /*
002: *
003: *
004: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: */
026: package com.sun.midp.jsr82emul;
027:
028: import java.io.IOException;
029: import java.io.UnsupportedEncodingException;
030: import java.io.InputStream;
031: import java.io.OutputStream;
032:
033: /**
034: * Represents JSR 82 emulation protocol, namely messages and codes recognized
035: * by emulation client and/or server.
036: *
037: * It is not a part of JSR 82 implementation and is only used within JSR 82
038: * emulation mode. The emulation mode allows running tets without real native
039: * Bluetooth libraries or hardware.
040: *
041: * Emulation server and client communicate thru a socket by means of sending
042: * data packets of the following format:
043: * <table border>
044: * <tr>
045: * <td>1 byte</td>
046: * <td>1 byte</td>
047: * <td>as defined by the previous field</td>
048: * </tr><tr>
049: * <td>packet type code</td>
050: * <td>length of information in bytes</td>
051: * <td>information bytes</td>
052: * </tr>
053: * </table>
054: */
055: public final class Messenger {
056: /** Keeps encoding for messages. */
057: public static final String ENCODING = "ISO8859_1";
058:
059: /** Responce code that identifies a failure. */
060: public static final byte ERROR = -1;
061: /** Device registration request code. */
062: public static final byte REGISTER_DEVICE = 1;
063: /** Successfull registration response. */
064: public static final byte REGISTERED = 2;
065:
066: /** Notification that client does not require server any more. */
067: public static final byte DONE = 3;
068: /**
069: * Code for specific messages that are only recognized by specific
070: * handlers at server side.
071: */
072: public static final byte SPECIFIC_MESSAGE = 4;
073:
074: /** Code for starting advertising service in the ether. */
075: public static final byte REGISTER_SERVICE = 5;
076: /** Code for unregistering service. */
077: public static final byte UNREGISTER_SERVICE = 6;
078: /** Request for service connection. */
079: public static final byte CONNECT_TO_SERVICE = 7;
080: /** Respond that provides service connection details. */
081: public static final byte SERVICE_AT = 8;
082:
083: /** Request for inquiry start. */
084: public static final byte START_INQUIRY = 9;
085: /** Respond on inquiry completion. */
086: public static final byte INQUIRY_COMPLETED = 10;
087:
088: /**
089: * Command to update device state that includes discoverable mode and
090: * device class.
091: */
092: public static final byte UPDATE_DEVICE_STATE = 11;
093:
094: /** Keeps code value retrieved by last <code>receive()</code> invocation. */
095: private byte code = -1;
096: /** Keeps bytes retrieved by last <code>receive()</code> invocation. */
097: private byte bytes[] = null;
098:
099: /**
100: * Constructs an instance. Always use different instances for different
101: * clients/servers to make sure data stored in <code>message</code> and
102: * <code>code</code> is appropriate.
103: */
104: public Messenger() {
105: }
106:
107: /**
108: * Forms a packet with given code and message and sends it to given output
109: * stream.
110: *
111: * @param out the output stream to send to.
112: * @param code the code to send.
113: * @param message the message to send.
114: *
115: * @exception IOException if one is issued by <code>out</code> methods.
116: */
117: public void send(OutputStream out, byte code, String message)
118: throws IOException {
119: if (out == null) {
120: throw new IllegalArgumentException();
121: }
122:
123: if (message == null) {
124: message = "";
125: }
126:
127: byte[] messageBytes = message.getBytes(ENCODING);
128:
129: sendBytes(out, code, messageBytes);
130: }
131:
132: /**
133: * Forms a packet with given code and bytes that represent given integer,
134: * then sends it to given output stream.
135: *
136: * @param out the output stream to send to
137: * @param code the code to send
138: * @param value integer to send
139: *
140: * @exception IOException if one is issued by <code>out</code> methods.
141: */
142: public void sendInt(OutputStream out, byte code, int value)
143: throws IOException {
144:
145: byte[] intBytes = new byte[4];
146: for (int i = 0; i < 4; i++) {
147: intBytes[i] = (byte) (value & 0xff);
148: value >>= 8;
149: }
150:
151: sendBytes(out, code, intBytes);
152: }
153:
154: /**
155: * Forms a packet with given code and bytes to send and sends it to
156: * given output stream.
157: *
158: * @param out the output stream to send to
159: * @param code the code to send
160: * @param info byte array to be sent entirely
161: *
162: * @exception IOException if one is issued by <code>out</code> methods.
163: */
164: public void sendBytes(OutputStream out, byte code, byte[] info)
165: throws IOException {
166:
167: if (info.length > Byte.MAX_VALUE) {
168: throw new IllegalArgumentException();
169: }
170:
171: synchronized (out) {
172: out.write(code);
173: out.write((byte) info.length);
174: out.write(info);
175: out.flush();
176: }
177: }
178:
179: /**
180: * Receives a packet from input stream given saving retrieved data in
181: * <code>code</code> and <code>message</code>.
182: *
183: * @param in the input stream to read from.
184: * @exception IOException if one is issued by <code>in</code> methods.
185: */
186: public void receive(InputStream in) throws IOException {
187: code = -1;
188: bytes = null;
189:
190: if (in == null) {
191: throw new IllegalArgumentException();
192: }
193:
194: synchronized (in) {
195: code = (byte) in.read();
196: int length = in.read();
197:
198: if (length == -1) {
199: throw new IOException();
200: }
201:
202: bytes = new byte[length];
203:
204: if (length != in.read(bytes)) {
205: throw new IOException();
206: }
207: }
208: }
209:
210: /**
211: * Provides code read by the last <code>receive()</code> invocation.
212: * @return the code received last time, -1 if there is no valid value.
213: */
214: public byte getCode() {
215: return code;
216: }
217:
218: /**
219: * Provides message read by the last <code>receive()</code> invocation.
220: * @return string message received last time.
221: * @exception EmulationException if no valid value read
222: */
223: public String getMessage() {
224: try {
225: return new String(bytes, 0, bytes.length, ENCODING);
226: } catch (UnsupportedEncodingException e) {
227: throw new EmulationException();
228: }
229: }
230:
231: /**
232: * Retrieves integer represented by bytes read by the last
233: * <code>receive()</code> invocation. Throws IllegalArgument exception
234: * if those bytes do not represent an integer.
235: *
236: * @return integer represented by bytes received last time.
237: * @exception EmulationException if no valid value read
238: */
239: public int getInt() {
240: if (bytes == null || bytes.length != 4) {
241: throw new EmulationException();
242: }
243:
244: int res = 0;
245: for (int i = 3; i >= 0; i--) {
246: res = (res << 8) | (bytes[i] & 0xff);
247: }
248:
249: return res;
250: }
251:
252: /**
253: * Provides bytes read by the last <code>receive()</code> invocation.
254: * @return bytes received last time.
255: */
256: public byte[] getBytes() {
257: return bytes;
258: }
259: }
|