/* * * * Copyright 1990-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License version * 2 only, as published by the Free Software Foundation. * * This program is distributed in the hope that it will be useful, but * WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License version 2 for more details (a copy is * included at /legal/license.txt). * * You should have received a copy of the GNU General Public License * version 2 along with this work; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa * Clara, CA 95054 or visit www.sun.com if you need additional * information or have any questions. */ package com.sun.midp.jsr82emul; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.io.InputStream; import java.io.OutputStream; /* * Represents JSR 82 emulation protocol, namely messages and codes recognized * by emulation client and/or server. * * It is not a part of JSR 82 implementation and is only used within JSR 82 * emulation mode. The emulation mode allows running tets without real native * Bluetooth libraries or hardware. * * Emulation server and client communicate thru a socket by means of sending * data packets of the following format: * <table border> * <tr> * <td>1 byte</td> * <td>1 byte</td> * <td>as defined by the previous field</td> * </tr><tr> * <td>packet type code</td> * <td>length of information in bytes</td> * <td>information bytes</td> * </tr> * </table> */ public final class Messenger { /* Keeps encoding for messages. */ public static final String ENCODING = "ISO8859_1"; /* Responce code that identifies a failure. */ public static final byte ERROR = -1; /* Device registration request code. */ public static final byte REGISTER_DEVICE = 1; /* Successfull registration response. */ public static final byte REGISTERED = 2; /* Notification that client does not require server any more. */ public static final byte DONE = 3; /* * Code for specific messages that are only recognized by specific * handlers at server side. */ public static final byte SPECIFIC_MESSAGE = 4; /* Code for starting advertising service in the ether. */ public static final byte REGISTER_SERVICE = 5; /* Code for unregistering service. */ public static final byte UNREGISTER_SERVICE = 6; /* Request for service connection. */ public static final byte CONNECT_TO_SERVICE = 7; /* Respond that provides service connection details. */ public static final byte SERVICE_AT = 8; /* Request for inquiry start. */ public static final byte START_INQUIRY = 9; /* Respond on inquiry completion. */ public static final byte INQUIRY_COMPLETED = 10; /* * Command to update device state that includes discoverable mode and * device class. */ public static final byte UPDATE_DEVICE_STATE = 11; /* Keeps code value retrieved by last <code>receive()</code> invocation. */ private byte code = -1; /* Keeps bytes retrieved by last <code>receive()</code> invocation. */ private byte bytes[] = null; /* * Constructs an instance. Always use different instances for different * clients/servers to make sure data stored in <code>message</code> and * <code>code</code> is appropriate. */ public Messenger() { } /* * Forms a packet with given code and message and sends it to given output * stream. * * @param out the output stream to send to. * @param code the code to send. * @param message the message to send. * * @exception IOException if one is issued by <code>out</code> methods. */ public void send(OutputStream out, byte code, String message) throws IOException { if (out == null) { throw new IllegalArgumentException(); } if (message == null) { message = ""; } byte[] messageBytes = message.getBytes(ENCODING); sendBytes(out, code, messageBytes); } /* * Forms a packet with given code and bytes that represent given integer, * then sends it to given output stream. * * @param out the output stream to send to * @param code the code to send * @param value integer to send * * @exception IOException if one is issued by <code>out</code> methods. */ public void sendInt(OutputStream out, byte code, int value) throws IOException { byte[] intBytes = new byte[4]; for (int i = 0; i < 4; i++) { intBytes[i] = (byte) (value & 0xff); value >>= 8; } sendBytes(out, code, intBytes); } /* * Forms a packet with given code and bytes to send and sends it to * given output stream. * * @param out the output stream to send to * @param code the code to send * @param info byte array to be sent entirely * * @exception IOException if one is issued by <code>out</code> methods. */ public void sendBytes(OutputStream out, byte code, byte[] info) throws IOException { if (info.length > Byte.MAX_VALUE) { throw new IllegalArgumentException(); } synchronized (out) { out.write(code); out.write((byte)info.length); out.write(info); out.flush(); } } /* * Receives a packet from input stream given saving retrieved data in * <code>code</code> and <code>message</code>. * * @param in the input stream to read from. * @exception IOException if one is issued by <code>in</code> methods. */ public void receive(InputStream in) throws IOException { code = -1; bytes = null; if (in == null) { throw new IllegalArgumentException(); } synchronized (in) { code = (byte) in.read(); int length = in.read(); if (length == -1) { throw new IOException(); } bytes = new byte[length]; if (length != in.read(bytes)) { throw new IOException(); } } } /* * Provides code read by the last <code>receive()</code> invocation. * @return the code received last time, -1 if there is no valid value. */ public byte getCode() { return code; } /* * Provides message read by the last <code>receive()</code> invocation. * @return string message received last time. * @exception EmulationException if no valid value read */ public String getMessage() { try { return new String(bytes, 0, bytes.length, ENCODING); } catch (UnsupportedEncodingException e) { throw new EmulationException(); } } /* * Retrieves integer represented by bytes read by the last * <code>receive()</code> invocation. Throws IllegalArgument exception * if those bytes do not represent an integer. * * @return integer represented by bytes received last time. * @exception EmulationException if no valid value read */ public int getInt() { if (bytes == null || bytes.length != 4) { throw new EmulationException(); } int res = 0; for (int i = 3; i >= 0; i--) { res = (res << 8) | (bytes[i] & 0xff); } return res; } /* * Provides bytes read by the last <code>receive()</code> invocation. * @return bytes received last time. */ public byte[] getBytes() { return bytes; } }