2009-06-30 12:04:36 -07:00
|
|
|
/*
|
|
|
|
* Copyright (c) 2008-2009, Motorola, Inc.
|
|
|
|
*
|
|
|
|
* All rights reserved.
|
|
|
|
*
|
|
|
|
* Redistribution and use in source and binary forms, with or without
|
|
|
|
* modification, are permitted provided that the following conditions are met:
|
|
|
|
*
|
|
|
|
* - Redistributions of source code must retain the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer.
|
|
|
|
*
|
|
|
|
* - Redistributions in binary form must reproduce the above copyright notice,
|
|
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
|
|
* and/or other materials provided with the distribution.
|
|
|
|
*
|
|
|
|
* - Neither the name of the Motorola, Inc. nor the names of its contributors
|
|
|
|
* may be used to endorse or promote products derived from this software
|
|
|
|
* without specific prior written permission.
|
|
|
|
*
|
|
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
|
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
|
|
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
|
|
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
|
|
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
|
|
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
|
|
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
|
|
*/
|
|
|
|
|
|
|
|
package javax.obex;
|
|
|
|
|
|
|
|
import java.io.IOException;
|
|
|
|
import java.io.InputStream;
|
|
|
|
import java.io.OutputStream;
|
|
|
|
import java.io.DataInputStream;
|
|
|
|
import java.io.DataOutputStream;
|
|
|
|
import java.io.ByteArrayOutputStream;
|
|
|
|
|
|
|
|
/**
|
2009-07-13 15:57:11 -07:00
|
|
|
* This class implements the <code>Operation</code> interface. It will read and
|
|
|
|
* write data via puts and gets.
|
2009-06-30 16:28:54 -07:00
|
|
|
* @hide
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
2009-06-30 16:28:54 -07:00
|
|
|
public final class ClientOperation implements Operation, BaseStream {
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
private ClientSession mParent;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
private boolean mInputOpen;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
private PrivateInputStream mPrivateInput;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
private boolean mPrivateInputOpen;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
private PrivateOutputStream mPrivateOutput;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
private boolean mPrivateOutputOpen;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
private String mExceptionMessage;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
private int mMaxPacketSize;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
private boolean mOperationDone;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
private boolean mGetOperation;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
private HeaderSet mRequestHeader;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
private HeaderSet mReplyHeader;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
private boolean mEndOfBodySent;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-13 15:57:11 -07:00
|
|
|
/**
|
2009-06-30 12:04:36 -07:00
|
|
|
* Creates new OperationImpl to read and write data to a server
|
|
|
|
* @param maxSize the maximum packet size
|
|
|
|
* @param p the parent to this object
|
|
|
|
* @param type <code>true</code> if this is a get request;
|
2009-07-13 15:57:11 -07:00
|
|
|
* <code>false</code. if this is a put request
|
|
|
|
* @param header the header to set in the initial request
|
|
|
|
* @throws IOException if the an IO error occurred
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
2009-07-02 19:29:09 +08:00
|
|
|
public ClientOperation(int maxSize, ClientSession p, HeaderSet header, boolean type)
|
|
|
|
throws IOException {
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
mParent = p;
|
|
|
|
mEndOfBodySent = false;
|
|
|
|
mInputOpen = true;
|
|
|
|
mOperationDone = false;
|
|
|
|
mMaxPacketSize = maxSize;
|
|
|
|
mGetOperation = type;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
mPrivateInputOpen = false;
|
|
|
|
mPrivateOutputOpen = false;
|
|
|
|
mPrivateInput = null;
|
|
|
|
mPrivateOutput = null;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
mReplyHeader = new HeaderSet();
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
mRequestHeader = new HeaderSet();
|
2009-06-30 12:04:36 -07:00
|
|
|
|
|
|
|
int[] headerList = header.getHeaderList();
|
|
|
|
|
|
|
|
if (headerList != null) {
|
|
|
|
|
|
|
|
for (int i = 0; i < headerList.length; i++) {
|
2009-07-02 19:29:09 +08:00
|
|
|
mRequestHeader.setHeader(headerList[i], header.getHeader(headerList[i]));
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if ((header).mAuthChall != null) {
|
|
|
|
mRequestHeader.mAuthChall = new byte[(header).mAuthChall.length];
|
|
|
|
System.arraycopy((header).mAuthChall, 0, mRequestHeader.mAuthChall, 0,
|
|
|
|
(header).mAuthChall.length);
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if ((header).mAuthResp != null) {
|
|
|
|
mRequestHeader.mAuthResp = new byte[(header).mAuthResp.length];
|
|
|
|
System.arraycopy((header).mAuthResp, 0, mRequestHeader.mAuthResp, 0,
|
|
|
|
(header).mAuthResp.length);
|
2009-06-30 12:04:36 -07:00
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-07-13 15:57:11 -07:00
|
|
|
* Sends an ABORT message to the server. By calling this method, the
|
2009-06-30 12:04:36 -07:00
|
|
|
* corresponding input and output streams will be closed along with this
|
|
|
|
* object.
|
2009-07-13 15:57:11 -07:00
|
|
|
* @throws IOException if the transaction has already ended or if an OBEX
|
|
|
|
* server called this method
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
|
|
|
public synchronized void abort() throws IOException {
|
|
|
|
ensureOpen();
|
|
|
|
//no compatible with sun-ri
|
2009-07-02 19:29:09 +08:00
|
|
|
if ((mOperationDone) && (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
throw new IOException("Operation has already ended");
|
|
|
|
}
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
mExceptionMessage = "Operation aborted";
|
|
|
|
if ((!mOperationDone) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
|
|
|
|
mOperationDone = true;
|
2009-06-30 12:04:36 -07:00
|
|
|
/*
|
|
|
|
* Since we are not sending any headers or returning any headers then
|
|
|
|
* we just need to write and read the same bytes
|
|
|
|
*/
|
2009-07-02 19:29:09 +08:00
|
|
|
mParent.sendRequest(ObexHelper.OBEX_OPCODE_ABORT, null, mReplyHeader, null);
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_OK) {
|
2009-06-30 12:04:36 -07:00
|
|
|
throw new IOException("Invalid response code from server");
|
|
|
|
}
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
mExceptionMessage = null;
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
close();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-07-13 15:57:11 -07:00
|
|
|
* Retrieves the response code retrieved from the server. Response codes are
|
|
|
|
* defined in the <code>ResponseCodes</code> interface.
|
2009-06-30 12:04:36 -07:00
|
|
|
* @return the response code retrieved from the server
|
2009-06-30 16:28:54 -07:00
|
|
|
* @throws IOException if an error occurred in the transport layer during
|
2009-07-13 15:57:11 -07:00
|
|
|
* the transaction; if this method is called on a
|
|
|
|
* <code>HeaderSet</code> object created by calling
|
|
|
|
* <code>createHeaderSet</code> in a <code>ClientSession</code>
|
|
|
|
* object
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
|
|
|
public synchronized int getResponseCode() throws IOException {
|
|
|
|
//avoid dup validateConnection
|
2009-07-02 19:29:09 +08:00
|
|
|
if ((mReplyHeader.responseCode == -1)
|
|
|
|
|| (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
validateConnection();
|
|
|
|
}
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
return mReplyHeader.responseCode;
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This method will always return <code>null</code>
|
|
|
|
* @return <code>null</code>
|
|
|
|
*/
|
|
|
|
public String getEncoding() {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the type of content that the resource connected to is providing.
|
|
|
|
* E.g. if the connection is via HTTP, then the value of the content-type
|
|
|
|
* header field is returned.
|
|
|
|
* @return the content type of the resource that the URL references, or
|
2009-07-13 15:57:11 -07:00
|
|
|
* <code>null</code> if not known
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
|
|
|
public String getType() {
|
|
|
|
try {
|
2009-07-02 19:29:09 +08:00
|
|
|
return (String)mReplyHeader.getHeader(HeaderSet.TYPE);
|
2009-06-30 12:04:36 -07:00
|
|
|
} catch (IOException e) {
|
|
|
|
return null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the length of the content which is being provided. E.g. if the
|
2009-07-13 15:57:11 -07:00
|
|
|
* connection is via HTTP, then the value of the content-length header field
|
|
|
|
* is returned.
|
2009-06-30 12:04:36 -07:00
|
|
|
* @return the content length of the resource that this connection's URL
|
2009-07-13 15:57:11 -07:00
|
|
|
* references, or -1 if the content length is not known
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
|
|
|
public long getLength() {
|
|
|
|
try {
|
2009-07-02 19:29:09 +08:00
|
|
|
Long temp = (Long)mReplyHeader.getHeader(HeaderSet.LENGTH);
|
2009-06-30 12:04:36 -07:00
|
|
|
|
|
|
|
if (temp == null) {
|
|
|
|
return -1;
|
|
|
|
} else {
|
|
|
|
return temp.longValue();
|
|
|
|
}
|
|
|
|
} catch (IOException e) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Open and return an input stream for a connection.
|
|
|
|
* @return an input stream
|
2009-06-30 16:28:54 -07:00
|
|
|
* @throws IOException if an I/O error occurs
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
|
|
|
public InputStream openInputStream() throws IOException {
|
|
|
|
|
|
|
|
ensureOpen();
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mPrivateInputOpen)
|
2009-06-30 12:04:36 -07:00
|
|
|
throw new IOException("no more input streams available");
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mGetOperation) {
|
2009-06-30 12:04:36 -07:00
|
|
|
// send the GET request here
|
|
|
|
validateConnection();
|
|
|
|
} else {
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mPrivateInput == null) {
|
|
|
|
mPrivateInput = new PrivateInputStream(this);
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
mPrivateInputOpen = true;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
return mPrivateInput;
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
|
2009-07-13 15:57:11 -07:00
|
|
|
/**
|
2009-06-30 12:04:36 -07:00
|
|
|
* Open and return a data input stream for a connection.
|
|
|
|
* @return an input stream
|
2009-06-30 16:28:54 -07:00
|
|
|
* @throws IOException if an I/O error occurs
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
|
|
|
public DataInputStream openDataInputStream() throws IOException {
|
|
|
|
return new DataInputStream(openInputStream());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Open and return an output stream for a connection.
|
|
|
|
* @return an output stream
|
2009-06-30 16:28:54 -07:00
|
|
|
* @throws IOException if an I/O error occurs
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
|
|
|
public OutputStream openOutputStream() throws IOException {
|
2009-07-02 19:29:09 +08:00
|
|
|
|
2009-06-30 12:04:36 -07:00
|
|
|
ensureOpen();
|
|
|
|
ensureNotDone();
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mPrivateOutputOpen)
|
2009-06-30 12:04:36 -07:00
|
|
|
throw new IOException("no more output streams available");
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mPrivateOutput == null) {
|
2009-06-30 12:04:36 -07:00
|
|
|
// there are 3 bytes operation headers and 3 bytes body headers //
|
2009-11-11 00:51:22 +08:00
|
|
|
mPrivateOutput = new PrivateOutputStream(this, getMaxPacketSize());
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
mPrivateOutputOpen = true;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
return mPrivateOutput;
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
public int getMaxPacketSize() {
|
2009-11-11 00:51:22 +08:00
|
|
|
return mMaxPacketSize - 6 - getHeaderLength();
|
|
|
|
}
|
|
|
|
|
|
|
|
public int getHeaderLength() {
|
|
|
|
// OPP may need it
|
|
|
|
byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
|
|
|
|
return headerArray.length;
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Open and return a data output stream for a connection.
|
|
|
|
* @return an output stream
|
2009-06-30 16:28:54 -07:00
|
|
|
* @throws IOException if an I/O error occurs
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
|
|
|
public DataOutputStream openDataOutputStream() throws IOException {
|
|
|
|
return new DataOutputStream(openOutputStream());
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Closes the connection and ends the transaction
|
2009-06-30 16:28:54 -07:00
|
|
|
* @throws IOException if the operation has already ended or is closed
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
|
|
|
public void close() throws IOException {
|
2009-07-02 19:29:09 +08:00
|
|
|
mInputOpen = false;
|
|
|
|
mPrivateInputOpen = false;
|
|
|
|
mPrivateOutputOpen = false;
|
|
|
|
mParent.setRequestInactive();
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Returns the headers that have been received during the operation.
|
2009-07-13 15:57:11 -07:00
|
|
|
* Modifying the object returned has no effect on the headers that are sent
|
|
|
|
* or retrieved.
|
2009-06-30 12:04:36 -07:00
|
|
|
* @return the headers received during this <code>Operation</code>
|
2009-06-30 16:28:54 -07:00
|
|
|
* @throws IOException if this <code>Operation</code> has been closed
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
2009-07-02 19:29:09 +08:00
|
|
|
public HeaderSet getReceivedHeader() throws IOException {
|
2009-06-30 12:04:36 -07:00
|
|
|
ensureOpen();
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
return mReplyHeader;
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Specifies the headers that should be sent in the next OBEX message that
|
|
|
|
* is sent.
|
|
|
|
* @param headers the headers to send in the next message
|
2009-07-13 15:57:11 -07:00
|
|
|
* @throws IOException if this <code>Operation</code> has been closed or the
|
|
|
|
* transaction has ended and no further messages will be exchanged
|
2009-06-30 16:28:54 -07:00
|
|
|
* @throws IllegalArgumentException if <code>headers</code> was not created
|
2009-07-13 15:57:11 -07:00
|
|
|
* by a call to <code>ServerRequestHandler.createHeaderSet()</code>
|
2009-06-30 16:28:54 -07:00
|
|
|
* @throws NullPointerException if <code>headers</code> is <code>null</code>
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
|
|
|
public void sendHeaders(HeaderSet headers) throws IOException {
|
|
|
|
ensureOpen();
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mOperationDone) {
|
2009-06-30 12:04:36 -07:00
|
|
|
throw new IOException("Operation has already exchanged all data");
|
|
|
|
}
|
|
|
|
|
|
|
|
if (headers == null) {
|
2009-07-02 19:29:09 +08:00
|
|
|
throw new IOException("Headers may not be null");
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
int[] headerList = headers.getHeaderList();
|
|
|
|
if (headerList != null) {
|
|
|
|
for (int i = 0; i < headerList.length; i++) {
|
2009-07-02 19:29:09 +08:00
|
|
|
mRequestHeader.setHeader(headerList[i], headers.getHeader(headerList[i]));
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-07-13 15:57:11 -07:00
|
|
|
* Verifies that additional information may be sent. In other words, the
|
2009-06-30 12:04:36 -07:00
|
|
|
* operation is not done.
|
2009-06-30 16:28:54 -07:00
|
|
|
* @throws IOException if the operation is completed
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
|
|
|
public void ensureNotDone() throws IOException {
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mOperationDone) {
|
2009-06-30 12:04:36 -07:00
|
|
|
throw new IOException("Operation has completed");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Verifies that the connection is open and no exceptions should be thrown.
|
2009-06-30 16:28:54 -07:00
|
|
|
* @throws IOException if an exception needs to be thrown
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
|
|
|
public void ensureOpen() throws IOException {
|
2009-07-02 19:29:09 +08:00
|
|
|
mParent.ensureOpen();
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mExceptionMessage != null) {
|
|
|
|
throw new IOException(mExceptionMessage);
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
2009-07-02 19:29:09 +08:00
|
|
|
if (!mInputOpen) {
|
2009-06-30 12:04:36 -07:00
|
|
|
throw new IOException("Operation has already ended");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Verifies that the connection is open and the proper data has been read.
|
2009-06-30 16:28:54 -07:00
|
|
|
* @throws IOException if an IO error occurs
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
|
|
|
private void validateConnection() throws IOException {
|
|
|
|
ensureOpen();
|
|
|
|
|
|
|
|
// to sure only one privateInput object exist.
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mPrivateInput == null) {
|
2009-06-30 12:04:36 -07:00
|
|
|
startProcessing();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Sends a request to the client of the specified type
|
2009-07-13 15:57:11 -07:00
|
|
|
* @param opCode the request code to send to the client
|
2009-06-30 12:04:36 -07:00
|
|
|
* @return <code>true</code> if there is more data to send;
|
2009-07-13 15:57:11 -07:00
|
|
|
* <code>false</code> if there is no more data to send
|
2009-06-30 16:28:54 -07:00
|
|
|
* @throws IOException if an IO error occurs
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
2009-07-13 15:57:11 -07:00
|
|
|
private boolean sendRequest(int opCode) throws IOException {
|
2009-06-30 12:04:36 -07:00
|
|
|
boolean returnValue = false;
|
|
|
|
ByteArrayOutputStream out = new ByteArrayOutputStream();
|
|
|
|
int bodyLength = -1;
|
2009-07-02 19:29:09 +08:00
|
|
|
byte[] headerArray = ObexHelper.createHeader(mRequestHeader, true);
|
|
|
|
if (mPrivateOutput != null) {
|
|
|
|
bodyLength = mPrivateOutput.size();
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Determine if there is space to add a body request. At present
|
|
|
|
* this method checks to see if there is room for at least a 17
|
|
|
|
* byte body header. This number needs to be at least 6 so that
|
|
|
|
* there is room for the header ID and length and the reply ID and
|
|
|
|
* length, but it is a waste of resources if we can't send much of
|
|
|
|
* the body.
|
|
|
|
*/
|
2009-07-02 19:29:09 +08:00
|
|
|
if ((ObexHelper.BASE_PACKET_LENGTH + headerArray.length) > mMaxPacketSize) {
|
2009-06-30 12:04:36 -07:00
|
|
|
int end = 0;
|
|
|
|
int start = 0;
|
|
|
|
// split & send the headerArray in multiple packets.
|
|
|
|
|
|
|
|
while (end != headerArray.length) {
|
|
|
|
//split the headerArray
|
2009-07-02 19:29:09 +08:00
|
|
|
end = ObexHelper.findHeaderEnd(headerArray, start, mMaxPacketSize
|
|
|
|
- ObexHelper.BASE_PACKET_LENGTH);
|
2009-06-30 12:04:36 -07:00
|
|
|
// can not split
|
|
|
|
if (end == -1) {
|
2009-07-02 19:29:09 +08:00
|
|
|
mOperationDone = true;
|
2009-06-30 12:04:36 -07:00
|
|
|
abort();
|
2009-07-02 19:29:09 +08:00
|
|
|
mExceptionMessage = "Header larger then can be sent in a packet";
|
|
|
|
mInputOpen = false;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mPrivateInput != null) {
|
|
|
|
mPrivateInput.close();
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mPrivateOutput != null) {
|
|
|
|
mPrivateOutput.close();
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
throw new IOException("OBEX Packet exceeds max packet size");
|
|
|
|
}
|
|
|
|
|
|
|
|
byte[] sendHeader = new byte[end - start];
|
|
|
|
System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length);
|
2009-07-13 15:57:11 -07:00
|
|
|
if (!mParent.sendRequest(opCode, sendHeader, mReplyHeader, mPrivateInput)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
|
2009-06-30 12:04:36 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
start = end;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bodyLength > 0) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
out.write(headerArray);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (bodyLength > 0) {
|
|
|
|
/*
|
2009-07-02 19:29:09 +08:00
|
|
|
* Determine if we can send the whole body or just part of
|
2009-06-30 12:04:36 -07:00
|
|
|
* the body. Remember that there is the 3 bytes for the
|
|
|
|
* response message and 3 bytes for the header ID and length
|
|
|
|
*/
|
2009-07-02 19:29:09 +08:00
|
|
|
if (bodyLength > (mMaxPacketSize - headerArray.length - 6)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
returnValue = true;
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
bodyLength = mMaxPacketSize - headerArray.length - 6;
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
byte[] body = mPrivateOutput.readBytes(bodyLength);
|
2009-06-30 12:04:36 -07:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Since this is a put request if the final bit is set or
|
|
|
|
* the output stream is closed we need to send the 0x49
|
|
|
|
* (End of Body) otherwise, we need to send 0x48 (Body)
|
|
|
|
*/
|
2009-07-02 19:29:09 +08:00
|
|
|
if ((mPrivateOutput.isClosed()) && (!returnValue) && (!mEndOfBodySent)
|
2009-07-13 15:57:11 -07:00
|
|
|
&& ((opCode & 0x80) != 0)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
out.write(0x49);
|
2009-07-02 19:29:09 +08:00
|
|
|
mEndOfBodySent = true;
|
2009-06-30 12:04:36 -07:00
|
|
|
} else {
|
|
|
|
out.write(0x48);
|
|
|
|
}
|
|
|
|
|
|
|
|
bodyLength += 3;
|
|
|
|
out.write((byte)(bodyLength >> 8));
|
|
|
|
out.write((byte)bodyLength);
|
|
|
|
|
|
|
|
if (body != null) {
|
|
|
|
out.write(body);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mPrivateOutputOpen && bodyLength <= 0 && !mEndOfBodySent) {
|
2009-06-30 12:04:36 -07:00
|
|
|
// only 0x82 or 0x83 can send 0x49
|
2009-07-13 15:57:11 -07:00
|
|
|
if ((opCode & 0x80) == 0) {
|
2009-06-30 12:04:36 -07:00
|
|
|
out.write(0x48);
|
|
|
|
} else {
|
|
|
|
out.write(0x49);
|
2009-07-02 19:29:09 +08:00
|
|
|
mEndOfBodySent = true;
|
2009-06-30 12:04:36 -07:00
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
bodyLength = 3;
|
|
|
|
out.write((byte)(bodyLength >> 8));
|
|
|
|
out.write((byte)bodyLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (out.size() == 0) {
|
2009-07-13 15:57:11 -07:00
|
|
|
if (!mParent.sendRequest(opCode, null, mReplyHeader, mPrivateInput)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return returnValue;
|
|
|
|
}
|
|
|
|
if ((out.size() > 0)
|
2009-07-13 15:57:11 -07:00
|
|
|
&& (!mParent.sendRequest(opCode, out.toByteArray(), mReplyHeader, mPrivateInput))) {
|
2009-06-30 12:04:36 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// send all of the output data in 0x48,
|
|
|
|
// send 0x49 with empty body
|
2009-07-02 19:29:09 +08:00
|
|
|
if ((mPrivateOutput != null) && (mPrivateOutput.size() > 0))
|
2009-06-30 12:04:36 -07:00
|
|
|
returnValue = true;
|
|
|
|
|
|
|
|
return returnValue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-07-13 15:57:11 -07:00
|
|
|
* This method starts the processing thread results. It will send the
|
|
|
|
* initial request. If the response takes more then one packet, a thread
|
2009-06-30 12:04:36 -07:00
|
|
|
* will be started to handle additional requests
|
2009-06-30 16:28:54 -07:00
|
|
|
* @throws IOException if an IO error occurs
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
|
|
|
private synchronized void startProcessing() throws IOException {
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mPrivateInput == null) {
|
|
|
|
mPrivateInput = new PrivateInputStream(this);
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
boolean more = true;
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mGetOperation) {
|
|
|
|
if (!mOperationDone) {
|
|
|
|
mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
|
|
|
|
while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
more = sendRequest(0x03);
|
|
|
|
}
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
|
|
|
|
mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
|
|
|
|
mOperationDone = true;
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (!mOperationDone) {
|
|
|
|
mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
|
|
|
|
while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
more = sendRequest(0x02);
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
|
|
|
|
mParent.sendRequest(0x82, null, mReplyHeader, mPrivateInput);
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
|
|
|
|
mOperationDone = true;
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Continues the operation since there is no data to read.
|
2009-07-13 15:57:11 -07:00
|
|
|
* @param sendEmpty <code>true</code> if the operation should send an empty
|
|
|
|
* packet or not send anything if there is no data to send
|
|
|
|
* @param inStream <code>true</code> if the stream is input stream or is
|
|
|
|
* output stream
|
2009-06-30 16:28:54 -07:00
|
|
|
* @throws IOException if an IO error occurs
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
|
|
|
public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream)
|
|
|
|
throws IOException {
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mGetOperation) {
|
|
|
|
if ((inStream) && (!mOperationDone)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
// to deal with inputstream in get operation
|
2009-07-02 19:29:09 +08:00
|
|
|
mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
|
2009-06-30 12:04:36 -07:00
|
|
|
/*
|
|
|
|
* Determine if that was not the last packet in the operation
|
|
|
|
*/
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
|
|
|
|
mOperationDone = true;
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
} else if ((!inStream) && (!mOperationDone)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
// to deal with outputstream in get operation
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mPrivateInput == null) {
|
|
|
|
mPrivateInput = new PrivateInputStream(this);
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
sendRequest(0x03);
|
|
|
|
return true;
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
} else if (mOperationDone) {
|
2009-06-30 12:04:36 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
} else {
|
2009-07-02 19:29:09 +08:00
|
|
|
if ((!inStream) && (!mOperationDone)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
// to deal with outputstream in put operation
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mReplyHeader.responseCode == -1) {
|
|
|
|
mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
sendRequest(0x02);
|
|
|
|
return true;
|
2009-07-02 19:29:09 +08:00
|
|
|
} else if ((inStream) && (!mOperationDone)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
// How to deal with inputstream in put operation ?
|
|
|
|
return false;
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
} else if (mOperationDone) {
|
2009-06-30 12:04:36 -07:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called when the output or input stream is closed.
|
|
|
|
* @param inStream <code>true</code> if the input stream is closed;
|
2009-07-13 15:57:11 -07:00
|
|
|
* <code>false</code> if the output stream is closed
|
2009-06-30 16:28:54 -07:00
|
|
|
* @throws IOException if an IO error occurs
|
2009-06-30 12:04:36 -07:00
|
|
|
*/
|
|
|
|
public void streamClosed(boolean inStream) throws IOException {
|
2009-07-02 19:29:09 +08:00
|
|
|
if (!mGetOperation) {
|
|
|
|
if ((!inStream) && (!mOperationDone)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
// to deal with outputstream in put operation
|
|
|
|
|
|
|
|
boolean more = true;
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0)) {
|
|
|
|
byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
|
2009-06-30 12:04:36 -07:00
|
|
|
if (headerArray.length <= 0)
|
|
|
|
more = false;
|
|
|
|
}
|
|
|
|
// If have not sent any data so send all now
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mReplyHeader.responseCode == -1) {
|
|
|
|
mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
more = sendRequest(0x02);
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* According to the IrOBEX specification, after the final put, you
|
|
|
|
* only have a single reply to send. so we don't need the while
|
|
|
|
* loop.
|
|
|
|
*/
|
2009-07-02 19:29:09 +08:00
|
|
|
while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
|
2009-06-30 12:04:36 -07:00
|
|
|
|
|
|
|
sendRequest(0x82);
|
|
|
|
}
|
2009-07-02 19:29:09 +08:00
|
|
|
mOperationDone = true;
|
|
|
|
} else if ((inStream) && (mOperationDone)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
// how to deal with input stream in put stream ?
|
2009-07-02 19:29:09 +08:00
|
|
|
mOperationDone = true;
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
} else {
|
2009-07-02 19:29:09 +08:00
|
|
|
if ((inStream) && (!mOperationDone)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
|
|
|
|
// to deal with inputstream in get operation
|
|
|
|
// Have not sent any data so send it all now
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mReplyHeader.responseCode == -1) {
|
|
|
|
mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
|
2009-06-30 12:04:36 -07:00
|
|
|
if (!sendRequest(0x83)) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2009-07-02 19:29:09 +08:00
|
|
|
while (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE) {
|
|
|
|
mParent.sendRequest(0x83, null, mReplyHeader, mPrivateInput);
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
2009-07-02 19:29:09 +08:00
|
|
|
mOperationDone = true;
|
|
|
|
} else if ((!inStream) && (!mOperationDone)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
// to deal with outputstream in get operation
|
|
|
|
// part of the data may have been sent in continueOperation.
|
|
|
|
|
|
|
|
boolean more = true;
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0)) {
|
|
|
|
byte[] headerArray = ObexHelper.createHeader(mRequestHeader, false);
|
2009-06-30 12:04:36 -07:00
|
|
|
if (headerArray.length <= 0)
|
|
|
|
more = false;
|
|
|
|
}
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mPrivateInput == null) {
|
|
|
|
mPrivateInput = new PrivateInputStream(this);
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
2009-07-02 19:29:09 +08:00
|
|
|
if ((mPrivateOutput != null) && (mPrivateOutput.size() <= 0))
|
2009-06-30 12:04:36 -07:00
|
|
|
more = false;
|
|
|
|
|
2009-07-02 19:29:09 +08:00
|
|
|
mReplyHeader.responseCode = ResponseCodes.OBEX_HTTP_CONTINUE;
|
|
|
|
while ((more) && (mReplyHeader.responseCode == ResponseCodes.OBEX_HTTP_CONTINUE)) {
|
2009-06-30 12:04:36 -07:00
|
|
|
more = sendRequest(0x03);
|
|
|
|
}
|
|
|
|
sendRequest(0x83);
|
|
|
|
// parent.sendRequest(0x83, null, replyHeaders, privateInput);
|
2009-07-02 19:29:09 +08:00
|
|
|
if (mReplyHeader.responseCode != ResponseCodes.OBEX_HTTP_CONTINUE) {
|
|
|
|
mOperationDone = true;
|
2009-06-30 12:04:36 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|