001: /*
002: *
003: * Copyright (c) 2007, Sun Microsystems, Inc.
004: *
005: * All rights reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * * Redistributions of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: * * Redistributions in binary form must reproduce the above copyright
014: * notice, this list of conditions and the following disclaimer in the
015: * documentation and/or other materials provided with the distribution.
016: * * Neither the name of Sun Microsystems nor the names of its contributors
017: * may be used to endorse or promote products derived from this software
018: * without specific prior written permission.
019: *
020: * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
021: * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
022: * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
023: * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
024: * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
025: * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
026: * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
027: * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
028: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
029: * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
030: * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
031: */
032: package example.obex.demo;
033:
034: import java.io.IOException;
035: import java.io.InputStream;
036:
037: import javax.microedition.io.Connection;
038: import javax.microedition.io.Connector;
039:
040: import javax.obex.HeaderSet;
041: import javax.obex.Operation;
042: import javax.obex.ResponseCodes;
043: import javax.obex.ServerRequestHandler;
044: import javax.obex.SessionNotifier;
045:
046: /**
047: * @version
048: */
049: final class ObexImageReceiver implements Runnable {
050: /** Shows if debug prints should be done. */
051: private static final boolean DEBUG = false;
052:
053: /** DEBUG only: keeps the class name for debug. */
054: private static final String cn = "ObexImageReceiver";
055:
056: /** List of supported states. */
057: private static final byte NONE = 0x00;
058: private static final byte OPENED = 0x01;
059: private static final byte CONNECTED = 0x02;
060: private static final byte STARTED = 0x03;
061: private static final byte STOPED = 0x4;
062: private static final byte CLOSED = 0x5;
063:
064: /** Max quantity of processing senders. */
065: private static final int MAX_PROCESSING_LENGTH = 2;
066:
067: /** Current state of receiver. */
068: private byte current_state = NONE;
069:
070: /** Handler to process OBEX operation. */
071: private Handler handler = new Handler();
072:
073: /** Indicate the length of connection request queue. */
074: private int processingLength = 0;
075:
076: /** Session to receive an image. */
077: private SessionNotifier session = null;
078:
079: /** Put Operation of image downloading process. */
080: private Operation operation = null;
081:
082: /** Input stream of OBEX. */
083: private InputStream inputStream = null;
084:
085: /** Reference to GUI part of sender */
086: private GUIImageReceiver gui = null;
087:
088: ObexImageReceiver(GUIImageReceiver gui) {
089: this .gui = gui;
090: }
091:
092: /**
093: * Used to accept connection and download an image.
094: */
095: public void run() {
096: try {
097: // synchronized to prevent loss of opened session
098: synchronized (this ) {
099: //String url = "tcpobex://:5010";
100: String url = "irdaobex://localhost.0010;ias=ImageExchange";
101: session = (SessionNotifier) Connector.open(url);
102: current_state = OPENED;
103: }
104:
105: while (current_state != CLOSED) {
106: session.acceptAndOpen(handler);
107: preventOverloading();
108: }
109: } catch (IOException ioe) {
110: synchronized (this ) {
111: if (current_state != CLOSED) {
112: ioe.printStackTrace();
113: }
114: }
115: }
116:
117: synchronized (this ) {
118: if (current_state != CLOSED) {
119: current_state = CLOSED;
120: gui.canNotConnectMessage();
121: }
122: }
123:
124: closeAll(true);
125: }
126:
127: /**
128: * Prevents connection more than MAX_PROCESSING_LENGTH senders.
129: */
130: private void preventOverloading() {
131: synchronized (handler) {
132: while (processingLength >= MAX_PROCESSING_LENGTH) {
133: processingLength++;
134:
135: try {
136: handler.wait();
137: } catch (InterruptedException ie) {
138: // don't wait then
139: }
140:
141: processingLength--;
142:
143: if (processingLength > 0) {
144: handler.notify();
145: }
146: }
147: }
148: }
149:
150: /**
151: * Starts synchronized process of image receiving.
152: */
153: private void startSynchReceiving(Operation operation)
154: throws IOException {
155: synchronized (handler) {
156: processingLength++;
157:
158: if (processingLength > 1) {
159: try {
160: handler.wait();
161: } catch (InterruptedException ie) {
162: // don't wait then
163: }
164: }
165: }
166:
167: synchronized (this ) {
168: if (current_state == CLOSED) {
169: throw new IOException();
170: }
171:
172: this .operation = operation;
173: current_state = CONNECTED;
174: }
175: }
176:
177: /**
178: * Stops synchronized process of image receiving.
179: */
180: private void stopSynchReceiving() {
181: synchronized (handler) {
182: processingLength--;
183:
184: if (processingLength > 0) {
185: handler.notify();
186: }
187: }
188: }
189:
190: /**
191: * Tries to receive.
192: */
193: private int imageReceive(Operation operation) {
194: HeaderSet headers = null;
195: String imageName = null;
196: int imageLength = 0;
197: int responseCode;
198:
199: try {
200: startSynchReceiving(operation);
201:
202: // download information about image
203: headers = operation.getReceivedHeaders();
204: imageName = (String) headers.getHeader(HeaderSet.NAME);
205: imageLength = (int) ((Long) headers
206: .getHeader(HeaderSet.LENGTH)).longValue();
207:
208: // ask permission to download image
209: if (gui.askPermission(imageName, imageLength)) {
210: // download and show image
211: gui.showImage(downloadImage(imageLength));
212: responseCode = ResponseCodes.OBEX_HTTP_OK;
213: } else {
214: responseCode = ResponseCodes.OBEX_HTTP_FORBIDDEN;
215: }
216: } catch (IOException ioe) {
217: if (current_state == STOPED) {
218: gui.showWaiting();
219: closeAll(false);
220: responseCode = ResponseCodes.OBEX_HTTP_RESET;
221: } else if (current_state == CONNECTED) {
222: gui.canNotConnectMessage();
223: closeAll(false);
224: responseCode = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
225: } else if (current_state == STARTED) {
226: gui.stopMessage();
227: gui.showWaiting();
228: closeAll(false);
229: responseCode = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
230: } else { // CLOSED, OPENED ?, NONE ???
231:
232: synchronized (this ) {
233: current_state = CLOSED;
234: }
235:
236: closeAll(true);
237: responseCode = ResponseCodes.OBEX_HTTP_INTERNAL_ERROR;
238: }
239: }
240:
241: stopSynchReceiving();
242:
243: return responseCode;
244: }
245:
246: /** Download image. */
247: private byte[] downloadImage(int imageLength) throws IOException {
248: byte[] imageData = new byte[imageLength];
249: int position = 0;
250: int length = 0;
251: checkStopSignal();
252: gui.showProgress(imageLength);
253:
254: synchronized (this ) {
255: current_state = STARTED;
256: inputStream = operation.openInputStream();
257: }
258:
259: while (position < imageLength) {
260: InputStream inputStream = this .inputStream;
261:
262: if (inputStream == null) {
263: throw new IOException();
264: }
265:
266: checkStopSignal();
267:
268: if (position < (imageLength - 256)) {
269: length = inputStream.read(imageData, position, 256);
270: } else {
271: length = inputStream.read(imageData, position,
272: imageLength - position);
273: }
274:
275: if (length < 0) {
276: throw new IOException();
277: }
278:
279: position += length;
280: gui.updateProgress(position);
281: }
282:
283: synchronized (this ) {
284: current_state = CLOSED;
285: }
286:
287: closeAll(true);
288:
289: return imageData;
290: }
291:
292: /** Throws IOException if current_state is STOPED. */
293: private void checkStopSignal() throws IOException {
294: synchronized (this ) {
295: if ((current_state == STOPED) || (current_state == CLOSED)) {
296: throw new IOException();
297: }
298: }
299: }
300:
301: /** Stops downloading process. */
302: void stop(boolean stopSession) {
303: synchronized (this ) {
304: if (stopSession) {
305: current_state = CLOSED;
306: } else {
307: current_state = STOPED;
308:
309: synchronized (handler) {
310: handler.notifyAll();
311: }
312: }
313:
314: closeAll(stopSession);
315: }
316: }
317:
318: /** Closes all connections. */
319: private void closeAll(boolean closeSession) {
320: synchronized (this ) {
321: if (inputStream != null) {
322: try {
323: inputStream.close();
324: } catch (IOException ioe) {
325: }
326:
327: inputStream = null;
328: }
329:
330: if (operation != null) {
331: try {
332: operation.close();
333: } catch (IOException ioe) {
334: }
335:
336: operation = null;
337: }
338:
339: if ((session != null) && (closeSession)) {
340: if (DEBUG) {
341: System.out.println(cn
342: + ".closeAll: closing session");
343: }
344:
345: try {
346: session.close();
347: } catch (IOException ioe) {
348: if (DEBUG) {
349: System.out.println(cn + ".closeAll: got exc: "
350: + ioe);
351: }
352: }
353:
354: if (DEBUG) {
355: System.out.println(cn
356: + ".closeAll: session is closed");
357: }
358:
359: session = null;
360: }
361: }
362: }
363:
364: class Handler extends ServerRequestHandler {
365: public Handler() {
366: }
367:
368: public int onPut(Operation operation) {
369: return imageReceive(operation);
370: }
371: }
372: }
|