001: /*
002: *
003: * Copyright 1990-2007 Sun Microsystems, Inc. All Rights Reserved.
004: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
005: *
006: * This program is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU General Public License version
008: * 2 only, as published by the Free Software Foundation.
009: *
010: * This program is distributed in the hope that it will be useful, but
011: * WITHOUT ANY WARRANTY; without even the implied warranty of
012: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
013: * General Public License version 2 for more details (a copy is
014: * included at /legal/license.txt).
015: *
016: * You should have received a copy of the GNU General Public License
017: * version 2 along with this work; if not, write to the Free Software
018: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
019: * 02110-1301 USA
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
022: * Clara, CA 95054 or visit www.sun.com if you need additional
023: * information or have any questions.
024: */
025: package com.sun.kvem.jsr082.obex;
026:
027: import javax.obex.ClientSession;
028: import javax.obex.HeaderSet;
029: import javax.obex.Operation;
030: import javax.obex.ResponseCodes;
031: import java.io.IOException;
032:
033: /**
034: * The class implements client side of session.
035: */
036: public class ClientSessionImpl extends ObexPacketStream implements
037: ClientSession {
038:
039: private boolean busy;
040: private Object lockObject = new Object();
041: private int owner;
042:
043: /**
044: * Current active operation. When not null, all method is ClientSession
045: * is blocked.
046: */
047: Operation operation = null;
048:
049: private long connId = -1;
050:
051: public ClientSessionImpl(ObexTransport transport)
052: throws IOException {
053: super (transport);
054:
055: // owner field of all created HeaderSets
056: owner = HeaderSetImpl.OWNER_CLIENT;
057: isClient = true;
058: }
059:
060: public HeaderSet createHeaderSet() {
061: return new HeaderSetImpl(HeaderSetImpl.OWNER_CLIENT_USER);
062: }
063:
064: private void lockCheckHeaders(HeaderSet headers) throws IOException {
065: if (isClosed()) {
066: throw new IOException("session closed");
067: }
068:
069: if (operation != null) {
070: throw new IOException("already in operation");
071: }
072:
073: if (headers != null) {
074: if (!(headers instanceof HeaderSetImpl)
075: || ((HeaderSetImpl) headers).owner == owner) {
076: throw new IllegalArgumentException(
077: "wrong headerset class");
078: }
079: }
080: synchronized (lockObject) {
081: if (busy) {
082: throw new IOException("already in operation");
083: }
084: busy = true;
085: }
086: }
087:
088: private void unlock() {
089: synchronized (lockObject) {
090: busy = false;
091: }
092: }
093:
094: void onAuthenticationFailure(byte[] username) throws IOException {
095: if (operation != null) {
096: operation.abort();
097: }
098: throw new IOException("server is not authenticated");
099: }
100:
101: void onMissingAuthResponse() throws IOException {
102: if (packetType != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
103: if (operation != null) {
104: operation.abort();
105: }
106: throw new IOException("no auth response from server");
107: }
108: }
109:
110: public void setConnectionID(long id) {
111: if (id < 0L || id > 0xFFFFFFFFL) {
112: throw new IllegalArgumentException("invalid id");
113: }
114: connId = id;
115: }
116:
117: public long getConnectionID() {
118: return connId;
119: }
120:
121: void headerTooLarge() throws IOException {
122: throw new IOException("header too large");
123: }
124:
125: public HeaderSet connect(HeaderSet headers) throws IOException {
126: lockCheckHeaders(headers);
127: try {
128: if (isConnected) {
129: throw new IOException("already connected");
130: }
131: byte[] head = { (byte) OPCODE_CONNECT, 0,
132: 0, // length will be here
133: 0x10, // obex protocol version 1.0
134: 0x00, // flags, all zero for this version of OBEX
135: // maximum client supported packet length
136: (byte) (OBEX_MAXIMUM_PACKET_LENGTH / 0x100),
137: (byte) (OBEX_MAXIMUM_PACKET_LENGTH % 0x100), };
138:
139: sendPacket(head, -1, (HeaderSetImpl) headers, true);
140: recvPacket();
141: if (packetLength < 7 || buffer[3] != 0x10) {
142: // IMPL_NOTE: It is not decided what the implementation should do
143: // if the OBEX version does not match. For example, Windows
144: // implementation uses version 1.2, Linux implementation
145: // uses version 1.1. JSR-82 should probably work with both.
146: // throw new IOException("unsupported server obex version");
147: }
148: HeaderSetImpl recvHeaders = new HeaderSetImpl(owner);
149: parsePacketHeaders(recvHeaders, 7);
150:
151: if (shouldSendAuthResponse()) {
152: // server ignores challenge before authenticating client
153: authFailed = false;
154: sendPacket(head, -1, (HeaderSetImpl) headers, true);
155: recvPacket();
156: if (packetLength < 7 || buffer[3] != 0x10) {
157: // IMPL_NOTE: See the comment above.
158: // throw new IOException("unsupported server obex version");
159: }
160: recvHeaders = new HeaderSetImpl(owner);
161: parsePacketHeaders(recvHeaders, 7);
162: }
163:
164: maxSendLength = decodeLength16(5);
165:
166: if (maxSendLength > OBEX_MAXIMUM_PACKET_LENGTH) {
167: maxSendLength = OBEX_MAXIMUM_PACKET_LENGTH;
168: }
169:
170: if (packetType == ResponseCodes.OBEX_HTTP_OK) {
171: if (authFailed) {
172: throw new IOException("server is not authenticated");
173: }
174: isConnected = true;
175: }
176: return recvHeaders;
177: } finally {
178: unlock();
179: }
180: }
181:
182: public HeaderSet disconnect(HeaderSet headers) throws IOException {
183: lockCheckHeaders(headers);
184: try {
185: if (!isConnected) {
186: throw new IOException("not connected");
187: }
188: sendPacket(PACKET_DISCONNECT, connId,
189: (HeaderSetImpl) headers, true);
190: recvPacket();
191: HeaderSetImpl recvHeaders = new HeaderSetImpl(owner);
192: parsePacketHeaders(recvHeaders, 3);
193: if (packetType == ResponseCodes.OBEX_HTTP_OK) {
194: isConnected = false;
195: }
196: return recvHeaders;
197: } finally {
198: unlock();
199: }
200: }
201:
202: public Operation put(HeaderSet headers) throws IOException {
203: lockCheckHeaders(headers);
204: try {
205: if (!isConnected) {
206: throw new IOException("not connected");
207: }
208: new ClientOperation(this , (HeaderSetImpl) headers, false);
209: return operation;
210: } finally {
211: unlock();
212: }
213: }
214:
215: public Operation get(HeaderSet headers) throws IOException {
216: lockCheckHeaders(headers);
217: try {
218: if (!isConnected) {
219: throw new IOException("not connected");
220: }
221: new ClientOperation(this , (HeaderSetImpl) headers, true);
222: return operation;
223: } finally {
224: unlock();
225: }
226: }
227:
228: public HeaderSet setPath(HeaderSet headers, boolean backup,
229: boolean create) throws IOException {
230: lockCheckHeaders(headers);
231: try {
232: if (!isConnected) {
233: throw new IOException("not connected");
234: }
235: byte[] head = { (byte) OPCODE_SETPATH, 0, 0, // length will be here
236: (byte) ((backup ? 1 : 0) + (create ? 0 : 2)), // flags
237: 0x00, // constants
238: };
239:
240: sendPacket(head, connId, (HeaderSetImpl) headers, true);
241: recvPacket();
242: HeaderSetImpl recvHeaders = new HeaderSetImpl(owner);
243: parsePacketHeaders(recvHeaders, 3);
244: return recvHeaders;
245: } finally {
246: unlock();
247: }
248: }
249:
250: public HeaderSet delete(HeaderSet headers) throws IOException {
251: lockCheckHeaders(headers);
252: try {
253: if (!isConnected) {
254: throw new IOException("not connected");
255: }
256: Operation op = new ClientOperation(this ,
257: (HeaderSetImpl) headers, false);
258:
259: op.getResponseCode(); // indicates end of operation
260: HeaderSet recvHeaders = op.getReceivedHeaders();
261: op.close();
262: return recvHeaders;
263: } finally {
264: unlock();
265: }
266: }
267: }
|