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:
027: package com.sun.tck.wma.cbs;
028:
029: import com.sun.tck.wma.PropLoader;
030: import com.sun.tck.wma.Message;
031: import com.sun.tck.wma.MessageConnection;
032: import com.sun.tck.wma.MessageTransportConstants;
033: import com.sun.tck.wma.BinaryMessage;
034: import com.sun.tck.wma.TextMessage;
035: import com.sun.tck.wma.sms.BinaryObject;
036: import com.sun.tck.wma.sms.TextObject;
037: import com.sun.midp.io.j2me.sms.TextEncoder;
038: import java.net.DatagramPacket;
039: import java.net.DatagramSocket;
040: import java.net.InetAddress;
041: import java.util.Properties;
042:
043: import java.io.IOException;
044:
045: /**
046: * CBS message connection handler.
047: */
048: public class CBSMessageConnection extends PropLoader implements
049: MessageConnection {
050:
051: /** Machine name - the parsed target address from the URL. */
052: protected String host = null;
053:
054: /** Message ID from the URL connection string. */
055: protected String msgID = null;
056:
057: /** Datagram host for sending CBS messages. */
058: protected String clientHost;
059:
060: /** Datagram transport for sending. */
061: protected int portOut;
062:
063: /** Phone number of the message sender. */
064: protected String phoneNumber;
065:
066: /** Datagram server connection. */
067: DatagramSocket dgc;
068:
069: /** Datagram buffer. */
070: byte[] buf = new byte[MessageTransportConstants.DATAGRAM_PACKET_SIZE];
071:
072: /** Datagram envelope for sending or receiving messages. */
073: DatagramPacket mess = new DatagramPacket(buf,
074: MessageTransportConstants.DATAGRAM_PACKET_SIZE);
075:
076: /**
077: * Open flag indicates when the connection is closed. When a connection is
078: * closed, subsequent operations throw an exception.
079: */
080: protected boolean open;
081:
082: /**
083: * Construct a new CBS message connection handler.
084: */
085: public CBSMessageConnection() {
086:
087: /*
088: * Configurable parameters for low level transport.
089: * e.g. cbs://:11100 maps to datagram://129.148.70.80:123
090: */
091:
092: clientHost = "localhost";
093: portOut = 22200;
094: phoneNumber = "+5551234";
095:
096: /*
097: * Check for overrides in the "connections.prop"
098: * configuration file.
099: */
100:
101: clientHost = getProp("localhost", "JSR_205_DATAGRAM_HOST",
102: "connections.prop", "DatagramHost");
103:
104: portOut = getIntProp(22200, "JSR_205_CBS_OUT_PORT",
105: "connections.prop", "CBSDatagramPortOut");
106:
107: phoneNumber = getProp("+5551234", "JSR_205_PHONE_NUMBER",
108: "connections.prop", "PhoneNumber");
109:
110: }
111:
112: /**
113: * Opens a connection. This method is called from
114: * <code>Connector.open()</code> method to obtain the destination address
115: * given in the <code>name</code> parameter.
116: * <p>
117: * The format for the <code>name</code> string for this method is:
118: * <code>cbs://<em>phone_number</em>:<em>port</em></code> where the
119: * <em>phone_number:</em> is optional. If the <em>phone_number</em>
120: * parameter is present, the connection is being opened in "client" mode.
121: * This means that messages can be sent. If the parameter is absent, the
122: * connection is being opened in "server" mode. This means that messages
123: * can be sent and received.
124: * <p>
125: * The connection that is opened is to a low-level transport mechanism
126: * which can be any of the following:
127: * <ul>
128: * <li>A datagram Short Message Peer to Peer (SMPP) to a service
129: * center.
130: * <li>A <code>comm</code> connection to a phone device with AT-commands.
131: * <li>a native CBS stack.
132: * </ul>
133: *
134: * @param name The target of the connection.
135: *
136: * @return This connection.
137: *
138: * @throws IOException if the connection is closed or unavailable.
139: */
140: public MessageConnection openPrim(String name) throws IOException {
141:
142: /*
143: * If <code>host == null</code>, then we are a server endpoint at
144: * the supplied <code>port</code>.
145: *
146: * If <code>host != null</code> we are a client endpoint at a port
147: * decided by the system and the default address for
148: * CBS messages to be sent is <code>cbs://host:port</code> .
149: */
150:
151: if (name.charAt(0) != '/' || name.charAt(1) != '/') {
152: throw new IllegalArgumentException(
153: "Missing protocol separator.");
154: }
155:
156: int colon = name.indexOf(':');
157: if (colon > 0) {
158: if (colon != 2) {
159: host = name.substring(2, colon);
160: }
161: msgID = name.substring(colon + 1);
162: } else {
163: if (name.length() > 2) {
164: host = name.substring(2);
165: }
166: }
167:
168: open = true;
169: return this ;
170: }
171:
172: /**
173: * Constructs a new message object of a text or binary type. When the
174: * <code>TEXT_MESSAGE</code> constant is passed in, the created
175: * object implements the <code>TextMessage</code> interface.
176: * When the <code>BINARY_MESSAGE</code> constant is passed in, the
177: * created object implements the <code>BinaryMessage</code>
178: * interface.
179: * <p>
180: * If this method is called in a sending mode, a new <code>Message</code>
181: * object is requested from the connection. For example:
182: * <p>
183: * <code>Message msg = conn.newMessage(TEXT_MESSAGE);</code>
184: * <p>
185: * The newly created <code>Message</code> does not have the destination
186: * address set. It must be set by the application before
187: * the message is sent.
188: * <p>
189: * If it is called in receiving mode, the <code>Message</code> object does
190: * have its address set. The application can act on the object to extract
191: * the address and message data.
192: * <p>
193: * <!-- The <code>type</code> parameter indicates the number of bytes
194: * that should be
195: * allocated for the message. No restrictions are placed on the application
196: * for the value of <code>size</code>.
197: * A value of <code>null</code> is permitted and creates a
198: * <code>Message</code> object
199: * with a 0-length message. -->
200: *
201: * @param type either TEXT_MESSAGE or BINARY_MESSAGE.
202: * @return a new message
203: */
204: public Message newMessage(String type) {
205: return newMessage(type, null);
206: }
207:
208: /**
209: * Constructs a new message object of a text or binary type and specifies
210: * a destination address.
211: * When the
212: * <code>TEXT_MESSAGE</code> constant is passed in, the created
213: * object implements the <code>TextMessage</code> interface.
214: * When the <code>BINARY_MESSAGE</code> constant is passed in, the
215: * created object implements the <code>BinaryMessage</code>
216: * interface.
217: * <p>
218: * The destination address <code>addr</code> has the following format:
219: * <code>cbs://</code><em>phone_number</em>:<em>port</em>.
220: *
221: * @param type either TEXT_MESSAGE or BINARY_MESSAGE.
222: * @param addr the destination address of the message.
223: * @return a new <code>Message</code> object.
224: */
225: public Message newMessage(String type, String addr) {
226: /* Return the appropriate type of sub message. */
227: if (type == MessageConnection.TEXT_MESSAGE) {
228: return new TextObject(addr);
229: } else if (type == MessageConnection.BINARY_MESSAGE) {
230: return new BinaryObject(addr);
231: }
232: return null; /* message type not supported */
233: }
234:
235: /**
236: * Sends a message over the connection. This method extracts
237: * the data payload from
238: * the <code>Message</code> object so that it
239: * can be sent as a datagram.
240: *
241: * @param dmsg a <code>Message</code> object.
242: * @exception ConnectionNotFoundException if the address is
243: * invalid or if no address is found in the message.
244: * @exception IOException if an I/O error occurs.
245: */
246: public void send(Message dmsg) throws IOException {
247:
248: byte[] buffer = null;
249: String type = null;
250: if (dmsg instanceof TextMessage) {
251: type = MessageConnection.TEXT_MESSAGE;
252: buffer = ((TextObject) dmsg).getPayloadData();
253: } else if (dmsg instanceof BinaryMessage) {
254: type = MessageConnection.BINARY_MESSAGE;
255: buffer = ((BinaryObject) dmsg).getPayloadData();
256: }
257:
258: /*
259: * For text messages choose between UCS-2 or GSM 7-bit
260: * encoding.
261: */
262: int encodingType = MessageTransportConstants.GSM_BINARY;
263: if (type.equals(MessageConnection.TEXT_MESSAGE)) {
264: byte[] gsm7bytes = TextEncoder.encode(buffer);
265: if (gsm7bytes != null) {
266: encodingType = MessageTransportConstants.GSM_TEXT;
267: buffer = gsm7bytes;
268: } else {
269: encodingType = MessageTransportConstants.GSM_UCS2;
270: }
271: }
272:
273: /* Datagram envelope for sending messages. */
274: mess = new DatagramPacket(buf,
275: MessageTransportConstants.DATAGRAM_PACKET_SIZE);
276:
277: /* Set the address and port to which the datagram is being sent. */
278: mess.setAddress(InetAddress.getByName(clientHost));
279: mess.setPort(portOut);
280:
281: /* Create the special CBS packet. */
282: CBSPacket cbsPacket = new CBSPacket();
283: cbsPacket.setEncodingType(encodingType);
284: if (msgID != null) {
285: cbsPacket.setMessageID(Integer.parseInt(msgID));
286: } else {
287: cbsPacket.setMessageID(0);
288: }
289: cbsPacket.setMessageLength(buffer.length);
290: cbsPacket.setMessage(buffer);
291:
292: debug("CBS PACKET: encoding type = " + encodingType);
293: debug("CBS PACKET: msgID = " + msgID);
294: debug("CBS PACKET: address = " + dmsg.getAddress());
295: debug("CBS PACKET: message length = " + buffer.length);
296: debug("CBS PACKET: message:" + new String(buffer));
297:
298: /* Make the CBS packet the payload for the datagram, and send it. */
299: byte[] buf = cbsPacket.getData();
300: mess.setData(buf, 0, buf.length);
301:
302: /* Open the outbound datagram connection. */
303: dgc = new DatagramSocket();
304: dgc.send(mess);
305: dgc.close();
306: dgc = null;
307: }
308:
309: /**
310: * Not supported. Normally, this would receive bytes that have been sent
311: * over the connection.
312: *
313: * @exception IOException Always thrown to indicate that this features is
314: * not supported.
315: *
316: * @return Message This object is never returned.
317: */
318: public synchronized Message receive() throws IOException {
319: throw new IOException("Server-Side receive not supported.");
320: }
321:
322: /**
323: * Closes the connection. Reset the connection is open flag
324: * so methods can be checked to throws an appropriate exception
325: * for operations on a closed connection.
326: *
327: * @exception IOException if an I/O error occurs.
328: */
329: public void close() throws IOException {
330:
331: if (open) {
332: open = false;
333: }
334: }
335:
336: /**
337: * Show a debug message.
338: *
339: * @param text The text to be displayed after a mandatory prefix.
340: */
341: private void debug(String text) {
342: System.out.println("CBSMessageConnection: " + text);
343: }
344:
345: }
|