Source code: mobile/bearer/http/TalkingWithProxy.java
1 /**
2 * Following fields form http header are used:
3 * content-length - length of message.
4 * jms4j2me-code - an integer representing what is the message kind
5 * jms4j2me-owner - owner client application identifier
6 * jms4j2me-id - id message identifier
7 * jms4j2me-action - if set to "acknowledgesPlease" denotes that
8 * each field mentioned above is obligatory.
9 */
10
11
12 package mobile.bearer.http;
13
14 import java.io.IOException;
15 import java.io.InputStream;
16 import java.io.OutputStream;
17 import java.lang.String;
18 import javax.microedition.io.*;
19 import mobile.protocol.Reply;
20 import java.util.Date;
21 /**
22 * <p>
23 * The lowest level of communication,
24 * Makes connection with proxy using HTTP protocol.
25 * </p>
26 */
27 public class TalkingWithProxy {
28 public static final String MOBILEFIELD = "jms4j2me-mobile";
29 public static final String OWNERFIELD = "jms4j2me-owner";
30 public static final String CODEFIELD = "jms4j2me-code";
31 public static final String IDFIELD = "jms4j2me-id";
32 public static final String LENGTHFIELD = "jms4j2me-message-length";
33 public static final String ACTIONFIELD = "jms4j2me-action";
34
35 ///////////////////////////////////////
36 // attributes
37
38
39 /**
40 * <p>
41 * How many messages where sent since last succesful acknowledge.
42 * </p>
43 */
44 private int messagesSent;
45
46 /**
47 * <p>
48 * How many messages should be sent before asking if they arrived.
49 * </p>
50 */
51 private int messagesPerPack;
52
53 /**
54 * <p>
55 * My proxy's URL.
56 * </p>
57 */
58 private String proxyUrl;
59
60
61 /**
62 * <p>
63 * Connection representation.
64 * </p>
65 */
66 /* private public Connector myHttpConnection = 0;
67 */
68 // private HttpConnection myHttpConnection;
69
70
71 /**
72 * <p>
73 * Informations from proxy should appear on this stream.
74 * </p>
75 */
76 private InputStream myInputStream;
77
78 /**
79 * <p>
80 * Stream for sending informations to proxy.
81 * </p>
82 */
83 // private OutputStream myOutputStream;
84
85 /**
86 * <p>
87 * Mobile unique identifier. Imei if found, else random number.
88 * </p>
89 */
90 private String mobile;
91
92 ///////////////////////////////////////
93 // operations
94
95
96
97
98 /**
99 * adds the message to the console output logs - for debugging
100 * @param msg message with debugging information for printing
101 */
102 private void log(String msg){
103 System.out.println("TWP " + msg);
104 }
105
106 /**
107 * <p>
108 * Constructor.
109 * </p><p>
110 *
111 * </p><p>
112 * @param proxyUrl URL of my proxy
113 * @param msgPerPack amount of messages sent before asking for acknowledge.
114 * </p>
115 */
116 public TalkingWithProxy(String proxyUrl, int msgPerPack) {
117 this.proxyUrl = proxyUrl;
118 this.messagesPerPack = messagesPerPack;
119 messagesSent = 0;
120 // myInputStream = null;
121 // myOutputStream = null;
122 // myHttpConnection = null;
123
124 if ((mobile = System.getProperty("profiles.imei")) == null){
125 //oho, i'm involved from emulator
126 // TODO: do it better!
127 mobile = Long.toString(new Date().getTime());
128 };
129 } // end TalkingWithProxy
130
131 /**
132 * <p>
133 * Opens connection with its proxy.
134 * </p><p>
135 *
136 */
137 public void openConnection() {
138 // InputStream s;
139 // try{
140 // if (myHttpConnection == null)
141 // myHttpConnection = (HttpConnection)Connector.open(proxyUrl);
142 //
143 // myHttpConnection.setRequestProperty("User-Agent",
144 // "Profile/MIDP-1.0 Configuration/CLDC-1.0");
145 // myHttpConnection.setRequestProperty("Content-Language", "en-US");
146 //
147 // if (myOutputStream == null)
148 // myOutputStream = myHttpConnection.openOutputStream();
149 // if (myInputStream == null)
150 // myInputStream = myHttpConnection.openInputStream();
151 // } catch(IOException myExc){
152 // DOIT!
153 // }
154 } // end OpenConnection
155
156 /**
157 * <p>
158 * Sends given message.
159 * </p><p>
160 *
161 * @param code an integer representing what is the message kind
162 * </p><p>
163 * @param owner client application identifier
164 * </p><p>
165 * @param id message identifier
166 * </p><p>
167 * @param msg serialized (using own mechanism) frame body
168 * </p><p>
169 * @throws NoConnectionException when proxy is unreacheable
170 * @throws NoDataException when no data can be fetched from proxy
171 *
172 * </p>
173 */
174 public void putNext(int code, int owner, int id, byte[] msg) throws NoConnectionException, NoDataException{
175
176 log("sending: code = " + code + ", owner = " + owner + ", id = " + id + ", msg = " + new String(msg));
177
178 /* Connection should be used with care */
179 if (msg.length == 0)
180 throw new NoDataException();
181
182 try {
183 // openConnection();
184 HttpConnection c = null;
185 // log("po httpconection c = null");
186 try{
187 log("otwieram połączenie z " + proxyUrl);
188 c = (HttpConnection) Connector.open(proxyUrl);
189 } catch (IllegalArgumentException e){
190 log("złapałem illegalArgumentException");
191 }
192 c.setRequestMethod(HttpConnection.POST);
193
194 /* set fields in header */
195 c.setRequestProperty(MOBILEFIELD, mobile);
196 c.setRequestProperty(OWNERFIELD, new Integer(owner).toString());
197 c.setRequestProperty(CODEFIELD, new Integer(code).toString());
198 c.setRequestProperty(IDFIELD, new Integer(id).toString());
199 c.setRequestProperty(LENGTHFIELD, (new Integer(msg.length)).toString());
200 c.setRequestProperty("Content-Type", "application/octet-stream");
201 OutputStream os = c.openOutputStream();
202 // System.out.println("putNext: \"" + new String(msg) + "\"");
203
204 for (int i=0; i < msg.length; i++)
205 os.write(msg[i]);
206 os.flush();
207 // log("wysłałem");
208 os.close();
209 c.close();
210 } catch (NullPointerException e){
211 log("catched NullPointerException - THATS A HUGE PROBLEM!");
212 e.printStackTrace();
213 } catch (IOException anIOExc){
214 log("putNext: throwing NoConnectionException becouse of IOException: " + anIOExc.toString());
215 // anIOExc.printStackTrace();
216 throw new NoConnectionException();
217 }
218 } // end putNext
219
220 /**
221 * <p>
222 * Ask proxy if there are any messages and receive one if so.
223 * </p><p>
224 *
225 *
226 * @param owner owner identifier
227 *
228 * @return a Reply - ownserialized message received from proxy.
229 * @throws NoConnectionException when proxy is unreachable
230 * @throws NoDataException wnen no data can be fetched from proxy
231 * </p>
232 */
233 public Reply getNext(int owner) throws NoConnectionException, NoDataException{
234
235 /* what is received from the server */
236 StringBuffer b = new StringBuffer();
237
238 /* my connection with the server */
239 HttpConnection c = null;
240
241 /* values returned as a Reply */
242 int code, id;
243 byte data[];
244
245 try {
246 long len = 0;
247 int ch = 0;
248 long count = 0;
249
250 c = (HttpConnection) Connector.open(proxyUrl);
251 c.setRequestMethod(HttpConnection.GET);
252
253 c.setRequestProperty(MOBILEFIELD, mobile);
254 c.setRequestProperty(OWNERFIELD, new Integer(owner).toString());
255
256 /* read all header fields */
257 for (int a = 0; c.getHeaderFieldKey(a) != null; a++)
258 ;
259
260 code = Integer.parseInt(c.getHeaderField(CODEFIELD));
261 id = Integer.parseInt(c.getHeaderField(IDFIELD));
262
263 log("w getNext id = " + id);
264 InputStream is = c.openInputStream();
265 len = ( (HttpConnection) c).getLength();
266 /* content-length field is needed. */
267 if (len == 0) {
268 c.close();
269 is.close();
270 log("Server answers: no data.");
271 throw new NoDataException();
272 }
273
274 data = new byte[ (int) len];
275
276 int n = is.read(data, 0, data.length);
277 for (int i = 0; i < n; i++) {
278 ch = data[i] & 0x000000ff;
279 b.append( (char) ch);
280 // System.out.println(ch);
281 }
282 System.out.println("getNext: \"" + b.toString() + "\"");
283 is.close();
284 c.close();
285 }
286 catch (IOException ex) {
287 // log("złaapny ioexc. w getNext()");
288 // ex.printStackTrace();
289 throw new NoConnectionException();
290 }
291 log("getNext zwraca reply");
292 int[] idArr = new int [1];
293 idArr[0] = id;
294 // log("przed putAcknowledge w getNext");
295 putAcknowledge(idArr, owner);
296 // log("po putAcknowledge w getNext");
297 return new Reply(code, owner, id, data);
298 } // end getNext
299
300 /**
301 * <p>
302 * Sends to proxy numbers of messages that was properly received.
303 * </p><p>
304 * </p><p>
305 * @param arr Array of messages numbers for acknowledge.
306 * @param owner owner identifier
307 * @throws NoDataException when given parameters consists no data
308 * @throws NoConnectionException when proxy is unreachable
309 * </p>
310 */
311 private void putAcknowledge(int[] arr, int owner) throws NoDataException, NoConnectionException {
312 // log("doing putAcknowledge");
313 if (arr.length == 0)
314 throw new NoDataException();
315 if (arr.length != 1)
316 System.err.println("I can acknowledge one message at time only!");
317 try {
318 HttpConnection c = null;
319
320 c = (HttpConnection) Connector.open(proxyUrl);
321 c.setRequestMethod(HttpConnection.HEAD);
322
323 /* set fields in header */
324 c.setRequestProperty(MOBILEFIELD, mobile);
325 c.setRequestProperty(OWNERFIELD, new Integer(owner).toString());
326 log("putAcknowledge: id = " + arr[0]);
327 c.setRequestProperty(IDFIELD, new Integer(arr[0]).toString());
328 c.setRequestProperty("Content-Type", "application/octet-stream");
329 OutputStream os = c.openOutputStream();
330
331 os.flush();
332 os.close();
333 c.close();
334 }
335 catch (IOException anIOExc) {
336
337 log("putAcknowledge rzuca noConnectionExc");
338 anIOExc.printStackTrace();
339 // throw new NoConnectionException();
340 }
341 } // end putAcknowledge
342
343 /**
344 * <p>
345 * Ask server if there are any messages that I (mobile) had send and was properly delivered to proxy.
346 * </p><p>
347 *
348 * @param owner calling application id
349 *
350 * @return a int[] with numbers of message to acknowledge.
351 * @throws NoConnectionException when proxy is unreachable
352 * @throws NoDataException when proxy answers with no data
353 * </p>
354 */
355 public int[] getAcknowledge(int owner) throws NoConnectionException, NoDataException{
356
357 /* my connection with the server */
358 HttpConnection c = null;
359 int[] result;
360
361 try {
362 long len = 0;
363 int ch = 0;
364 long count = 0;
365
366 c = (HttpConnection) Connector.open(proxyUrl);
367 c.setRequestMethod(HttpConnection.GET);
368
369 c.setRequestProperty(MOBILEFIELD, mobile);
370 c.setRequestProperty(OWNERFIELD, new Integer(owner).toString());
371 c.setRequestProperty(ACTIONFIELD, "acknowledgesPlease");
372
373 /* read all header fields */
374 for (int a = 0; c.getHeaderFieldKey(a) != null; a++)
375 ;
376
377 InputStream is = c.openInputStream();
378 len = ( (HttpConnection) c).getLength();
379 /* content-length field is needed. */
380 if (len == 0) {
381 c.close();
382 is.close();
383 log("No content-length field");
384 throw new NoDataException();
385 }
386
387 byte data[];
388 data = new byte[ (int) len];
389 result = new int[ (int)len/4];
390 int n = is.read(data, 0, data.length);
391 int current = 0; /* message id counter */
392 int z; /* bytes counter */
393 int id; /* current id */
394 n/=4;
395 System.out.println("n =" + n);
396 for (int i = 0; i < n; i++) {
397 for (z = 0; z < 4; z++){
398 ch = data[4 * i + z] & 0x000000ff;
399 current = current << 8;
400 current += ch;
401 // System.out.println("getAckn zwraca:::");
402 // System.out.println(ch);
403 }
404 result[i]=current;
405 }
406 is.close();
407 c.close();
408 return result;
409 }
410 catch (IOException ex) {
411 log("złaapny ioexc. w getAcknowledge()");
412 ex.printStackTrace();
413 throw new NoConnectionException();
414 }
415 } // end getAcknowledge
416
417
418 /**
419 * <p>
420 * Check whether mobile has connection with server. This method gives information about potential state of connection. Answering true doesn't mean that something rather might than might not be sent/received. Answering false says that the chance is near zero.
421 * </p><p>
422 * @return a boolean that say if proxy is reachable at the moment.
423 * </p>
424 */
425 public boolean connectionExists() {
426 return true;
427 // return myHttpConnection != null;
428 } // end connectionExists
429
430 public void setUrl(String _url){
431 proxyUrl = _url;
432 }
433
434 } // end TalkingWithProxy
435
436
437
438
439