FileDocCategorySizeDatePackage
ClientSessionImpl.javaAPI DocphoneME MR2 API (J2ME)8791Wed May 02 18:00:32 BST 2007com.sun.kvem.jsr082.obex

ClientSessionImpl.java

/*
 *
 * Copyright  1990-2007 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.kvem.jsr082.obex;

import javax.obex.ClientSession;
import javax.obex.HeaderSet;
import javax.obex.Operation;
import javax.obex.ResponseCodes;
import java.io.IOException;

/**
 * The class implements client side of session.
 */
public class ClientSessionImpl extends ObexPacketStream
        implements ClientSession {

    private boolean busy;
    private Object lockObject = new Object();
    private int owner;

    /** 
     * Current active operation. When not null, all method is ClientSession
     * is blocked.
     */
    Operation operation = null;

    private long connId = -1;

    public ClientSessionImpl(ObexTransport transport) throws IOException {
        super(transport);

        // owner field of all created HeaderSets
        owner = HeaderSetImpl.OWNER_CLIENT;
        isClient = true;
    }

    public HeaderSet createHeaderSet() {
        return new HeaderSetImpl(HeaderSetImpl.OWNER_CLIENT_USER);
    }

    private void lockCheckHeaders(HeaderSet headers) throws IOException {
        if (isClosed()) {
            throw new IOException("session closed");
        }

        if (operation != null) {
            throw new IOException("already in operation");
        }

        if (headers != null) {
            if (!(headers instanceof HeaderSetImpl)
                    || ((HeaderSetImpl)headers).owner == owner) {
                throw new IllegalArgumentException("wrong headerset class");
            }
        }
        synchronized (lockObject) {
            if (busy) {
                throw new IOException("already in operation");
            }
            busy = true;
        }
    }

    private void unlock() {
        synchronized (lockObject) {
            busy = false;
        }
    }

    void onAuthenticationFailure(byte[] username) throws IOException {
        if (operation != null) {
            operation.abort();
        }
        throw new IOException("server is not authenticated");
    }

    void onMissingAuthResponse() throws IOException {
        if (packetType != ResponseCodes.OBEX_HTTP_UNAUTHORIZED) {
            if (operation != null) {
                operation.abort();
            }
            throw new IOException("no auth response from server");
        }
    }

    public void setConnectionID(long id) {
        if (id < 0L || id > 0xFFFFFFFFL) {
            throw new IllegalArgumentException("invalid id");
        }
        connId = id;
    }

    public long getConnectionID() {
        return connId;
    }

    void headerTooLarge() throws IOException {
        throw new IOException("header too large");
    }

    public HeaderSet connect(HeaderSet headers) throws IOException {
        lockCheckHeaders(headers);
        try {
            if (isConnected) {
                throw new IOException("already connected");
            }
            byte[] head = {
                (byte)OPCODE_CONNECT,
                0, 0, // length will be here
                0x10, // obex protocol version 1.0
                0x00, // flags, all zero for this version of OBEX
                // maximum client supported packet length
                (byte) (OBEX_MAXIMUM_PACKET_LENGTH / 0x100),
                (byte) (OBEX_MAXIMUM_PACKET_LENGTH % 0x100),
            };

            sendPacket(head, -1, (HeaderSetImpl) headers, true);
            recvPacket();
            if (packetLength < 7 || buffer[3] != 0x10) {
		// IMPL_NOTE: It is not decided what the implementation should do
		// if the OBEX version does not match. For example, Windows
		// implementation uses version 1.2, Linux implementation
		// uses version 1.1. JSR-82 should probably work with both.
                // throw new IOException("unsupported server obex version");
            }
            HeaderSetImpl recvHeaders = new HeaderSetImpl(owner);
            parsePacketHeaders(recvHeaders, 7);

            if (shouldSendAuthResponse()) {
                // server ignores challenge before authenticating client
                authFailed = false;
                sendPacket(head, -1, (HeaderSetImpl) headers, true);
                recvPacket();
                if (packetLength < 7 || buffer[3] != 0x10) {
                    // IMPL_NOTE: See the comment above.
		    // throw new IOException("unsupported server obex version");
                }
                recvHeaders = new HeaderSetImpl(owner);
                parsePacketHeaders(recvHeaders, 7);
            }

            maxSendLength = decodeLength16(5);

            if (maxSendLength > OBEX_MAXIMUM_PACKET_LENGTH) {
                maxSendLength = OBEX_MAXIMUM_PACKET_LENGTH;
            }

            if (packetType == ResponseCodes.OBEX_HTTP_OK) {
                if (authFailed) {
                    throw new IOException("server is not authenticated");
                }
                isConnected = true;
            }
            return recvHeaders;
        } finally {
            unlock();
        }
    }

    public HeaderSet disconnect(HeaderSet headers) throws IOException {
        lockCheckHeaders(headers);
        try {
            if (!isConnected) {
                throw new IOException("not connected");
            }
            sendPacket(PACKET_DISCONNECT, connId,
                    (HeaderSetImpl) headers, true);
            recvPacket();
            HeaderSetImpl recvHeaders = new HeaderSetImpl(owner);
            parsePacketHeaders(recvHeaders, 3);
            if (packetType == ResponseCodes.OBEX_HTTP_OK) {
                isConnected = false;
            }
            return recvHeaders;
        } finally {
            unlock();
        }
    }

    public Operation put(HeaderSet headers) throws IOException {
        lockCheckHeaders(headers);
        try {
            if (!isConnected) {
                throw new IOException("not connected");
            }
            new ClientOperation(this,
                    (HeaderSetImpl) headers, false);
            return operation;
        } finally {
            unlock();
        }
    }

    public Operation get(HeaderSet headers) throws IOException {
        lockCheckHeaders(headers);
        try {
            if (!isConnected) {
                throw new IOException("not connected");
            }
            new ClientOperation(this, (HeaderSetImpl)headers, true);
            return operation;
        } finally {
            unlock();
        }
    }

    public HeaderSet setPath(HeaderSet headers, boolean backup,
        boolean create) throws IOException {
        lockCheckHeaders(headers);
        try {
            if (!isConnected) {
                throw new IOException("not connected");
            }
            byte[] head = {
                (byte)OPCODE_SETPATH,
                0, 0, // length will be here
                (byte)((backup ? 1 : 0) + (create ? 0 : 2)), // flags
                0x00, // constants
            };

            sendPacket(head, connId, (HeaderSetImpl) headers, true);
            recvPacket();
            HeaderSetImpl recvHeaders = new HeaderSetImpl(owner);
            parsePacketHeaders(recvHeaders, 3);
            return recvHeaders;
        } finally {
            unlock();
        }
    }

    public HeaderSet delete(HeaderSet headers) throws IOException {
        lockCheckHeaders(headers);
        try {
            if (!isConnected) {
                throw new IOException("not connected");
            }
            Operation op = new ClientOperation(this,
                    (HeaderSetImpl)headers, false);

            op.getResponseCode(); // indicates end of operation
            HeaderSet recvHeaders = op.getReceivedHeaders();
            op.close();
            return recvHeaders;
        } finally {
            unlock();
        }
    }
}