ClientOperation.java revision 9439a7fe517b858bc5e5c654b459315e4722feb2
1/* 2 * Copyright (c) 2008-2009, Motorola, Inc. 3 * 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions are met: 8 * 9 * - Redistributions of source code must retain the above copyright notice, 10 * this list of conditions and the following disclaimer. 11 * 12 * - Redistributions in binary form must reproduce the above copyright notice, 13 * this list of conditions and the following disclaimer in the documentation 14 * and/or other materials provided with the distribution. 15 * 16 * - Neither the name of the Motorola, Inc. nor the names of its contributors 17 * may be used to endorse or promote products derived from this software 18 * without specific prior written permission. 19 * 20 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 21 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 24 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 25 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 28 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 30 * POSSIBILITY OF SUCH DAMAGE. 31 */ 32 33package javax.obex; 34 35import java.io.IOException; 36import java.io.InputStream; 37import java.io.OutputStream; 38import java.io.DataInputStream; 39import java.io.DataOutputStream; 40import java.io.ByteArrayOutputStream; 41 42/** 43 * This class implements the <code>Operation</code> interface. It will read 44 * and write data via puts and gets. 45 * 46 * @version 0.3 November 28, 2008 47 */ 48public class ClientOperation implements Operation, BaseStream { 49 50 /** 51 * Defines the basic packet length used by OBEX. Event OBEX packet has the 52 * same basic format:<BR> 53 * Byte 0: Request or Response Code 54 * Byte 1&2: Length of the packet. 55 */ 56 private static final int BASE_PACKET_LENGTH = 3; 57 58 private ClientSession parent; 59 60 private InputStream socketInput; 61 62 private PrivateInputStream privateInput; 63 64 private PrivateOutputStream privateOutput; 65 66 private boolean isClosed; 67 68 private String exceptionMessage; 69 70 private int maxPacketSize; 71 72 private boolean isDone; 73 74 private boolean isGet; 75 76 private HeaderSet requestHeaders; 77 78 private HeaderSet replyHeaders; 79 80 private boolean isEndOfBodySent; 81 82 private boolean inputStreamOpened; 83 84 private boolean outputStreamOpened; 85 86 private boolean isValidateConnected; 87 88 /** 89 * Creates new OperationImpl to read and write data to a server 90 * 91 * @param in the input stream to read from 92 * 93 * @param maxSize the maximum packet size 94 * 95 * @param p the parent to this object 96 * 97 * @param headers the headers to set in the initial request 98 * 99 * @param type <code>true</code> if this is a get request; 100 * <code>false</code. if this is a put request 101 * 102 * @exception IOExcpetion if the an IO error occured 103 */ 104 public ClientOperation(InputStream in, int maxSize, ClientSession p, HeaderSet header, 105 boolean type) throws IOException { 106 107 parent = p; 108 isEndOfBodySent = false; 109 socketInput = in; 110 isClosed = false; 111 isDone = false; 112 maxPacketSize = maxSize; 113 isGet = type; 114 115 inputStreamOpened = false; 116 outputStreamOpened = false; 117 isValidateConnected = false; 118 119 privateInput = null; 120 privateOutput = null; 121 122 replyHeaders = new HeaderSet(); 123 124 requestHeaders = new HeaderSet(); 125 126 int[] headerList = header.getHeaderList(); 127 128 if (headerList != null) { 129 130 for (int i = 0; i < headerList.length; i++) { 131 requestHeaders.setHeader(headerList[i], header.getHeader(headerList[i])); 132 } 133 } 134 135 if ((header).authChall != null) { 136 requestHeaders.authChall = new byte[(header).authChall.length]; 137 System.arraycopy((header).authChall, 0, requestHeaders.authChall, 0, 138 (header).authChall.length); 139 } 140 141 if ((header).authResp != null) { 142 requestHeaders.authResp = new byte[(header).authResp.length]; 143 System.arraycopy((header).authResp, 0, requestHeaders.authResp, 0, 144 (header).authResp.length); 145 146 } 147 // requestHeaders = (HeaderSet)header; 148 } 149 150 /** 151 * Sends an ABORT message to the server. By calling this method, the 152 * corresponding input and output streams will be closed along with this 153 * object. 154 * 155 * @exception IOException if the transaction has already ended or if an 156 * OBEX server called this method 157 */ 158 public synchronized void abort() throws IOException { 159 ensureOpen(); 160 // need check again . 161 // if(isDone) { 162 // throw new IOException("Operation has already ended"); 163 // } 164 165 //no compatible with sun-ri 166 if ((isDone) && (replyHeaders.responseCode != OBEXConstants.OBEX_HTTP_CONTINUE)) { 167 throw new IOException("Operation has already ended"); 168 } 169 170 exceptionMessage = "Operation aborted"; 171 if ((!isDone) && (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE)) { 172 isDone = true; 173 /* 174 * Since we are not sending any headers or returning any headers then 175 * we just need to write and read the same bytes 176 */ 177 parent.sendRequest(0xFF, null, replyHeaders, null); 178 179 if (replyHeaders.responseCode != ResponseCodes.OBEX_HTTP_OK) { 180 throw new IOException("Invalid response code from server"); 181 } 182 183 exceptionMessage = null; 184 } 185 186 close(); 187 } 188 189 /** 190 * Retrieves the response code retrieved from the server. Response codes 191 * are defined in the <code>ResponseCodes</code> interface. 192 * 193 * @return the response code retrieved from the server 194 * 195 * @exception IOException if an error occurred in the transport layer during 196 * the transaction; if this method is called on a <code>HeaderSet</code> 197 * object created by calling <code>createHeaderSet</code> in a 198 * <code>ClientSession</code> object 199 */ 200 public synchronized int getResponseCode() throws IOException { 201 //avoid dup validateConnection 202 if ((replyHeaders.responseCode == -1) 203 || (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE)) { 204 validateConnection(); 205 } 206 207 return replyHeaders.responseCode; 208 } 209 210 /** 211 * This method will always return <code>null</code> 212 * 213 * @return <code>null</code> 214 */ 215 public String getEncoding() { 216 return null; 217 } 218 219 /** 220 * Returns the type of content that the resource connected to is providing. 221 * E.g. if the connection is via HTTP, then the value of the content-type 222 * header field is returned. 223 * 224 * @return the content type of the resource that the URL references, or 225 * <code>null</code> if not known 226 */ 227 public String getType() { 228 try { 229 return (String)replyHeaders.getHeader(HeaderSet.TYPE); 230 } catch (IOException e) { 231 return null; 232 } 233 } 234 235 /** 236 * Returns the length of the content which is being provided. E.g. if the 237 * connection is via HTTP, then the value of the content-length header 238 * field is returned. 239 * 240 * @return the content length of the resource that this connection's URL 241 * references, or -1 if the content length is not known 242 */ 243 public long getLength() { 244 try { 245 Long temp = (Long)replyHeaders.getHeader(HeaderSet.LENGTH); 246 247 if (temp == null) { 248 return -1; 249 } else { 250 return temp.longValue(); 251 } 252 } catch (IOException e) { 253 return -1; 254 } 255 } 256 257 /** 258 * Open and return an input stream for a connection. 259 * 260 * @return an input stream 261 * 262 * @exception IOException if an I/O error occurs 263 */ 264 public InputStream openInputStream() throws IOException { 265 // TODO: this mode is not set yet. 266 // if ((parent.mode & Connector.READ) == 0) 267 // throw new IOException("write-only connection"); 268 269 ensureOpen(); 270 271 if (inputStreamOpened) 272 throw new IOException("no more input streams available"); 273 if (isGet) { 274 // send the GET request here 275 validateConnection(); 276 isValidateConnected = true; 277 } else { 278 if (privateInput == null) { 279 privateInput = new PrivateInputStream(this); 280 } 281 } 282 283 inputStreamOpened = true; 284 285 return privateInput; 286 } 287 288 /**8 289 * Open and return a data input stream for a connection. 290 * 291 * @return an input stream 292 * 293 * @exception IOException if an I/O error occurs 294 */ 295 public DataInputStream openDataInputStream() throws IOException { 296 return new DataInputStream(openInputStream()); 297 } 298 299 /** 300 * Open and return an output stream for a connection. 301 * 302 * @return an output stream 303 * 304 * @exception IOException if an I/O error occurs 305 */ 306 public OutputStream openOutputStream() throws IOException { 307 // TODO: this mode is not set yet. 308 // if ((parent.mode & Connector.WRITE) == 0) 309 // throw new IOException("read-only connection"); 310 ensureOpen(); 311 ensureNotDone(); 312 313 if (outputStreamOpened) 314 throw new IOException("no more output streams available"); 315 316 if (privateOutput == null) { 317 // there are 3 bytes operation headers and 3 bytes body headers // 318 privateOutput = new PrivateOutputStream(this, maxPacketSize - 6); 319 } 320 321 outputStreamOpened = true; 322 323 return privateOutput; 324 } 325 326 public int getMaxPacketSize() { 327 return maxPacketSize - 6; 328 } 329 330 /** 331 * Open and return a data output stream for a connection. 332 * 333 * @return an output stream 334 * 335 * @exception IOException if an I/O error occurs 336 */ 337 public DataOutputStream openDataOutputStream() throws IOException { 338 return new DataOutputStream(openOutputStream()); 339 } 340 341 /** 342 * Closes the connection and ends the transaction 343 * 344 * @exception IOException if the operation has already ended or is closed 345 */ 346 public void close() throws IOException { 347 isClosed = true; 348 inputStreamOpened = false; 349 outputStreamOpened = false; 350 parent.setInactive(); 351 } 352 353 /** 354 * Returns the headers that have been received during the operation. 355 * Modifying the object returned has no effect on the headers that are 356 * sent or retrieved. 357 * 358 * @return the headers received during this <code>Operation</code> 359 * 360 * @exception IOException if this <code>Operation</code> has been closed 361 */ 362 public HeaderSet getReceivedHeaders() throws IOException { 363 ensureOpen(); 364 365 return replyHeaders; 366 } 367 368 /** 369 * Specifies the headers that should be sent in the next OBEX message that 370 * is sent. 371 * 372 * @param headers the headers to send in the next message 373 * 374 * @exception IOException if this <code>Operation</code> has been closed 375 * or the transaction has ended and no further messages will be exchanged 376 * 377 * @exception IllegalArgumentException if <code>headers</code> was not created 378 * by a call to <code>ServerRequestHandler.createHeaderSet()</code> 379 * 380 * @exception NullPointerException if <code>headers</code> is <code>null</code> 381 */ 382 public void sendHeaders(HeaderSet headers) throws IOException { 383 ensureOpen(); 384 if (isDone) { 385 throw new IOException("Operation has already exchanged all data"); 386 } 387 388 if (headers == null) { 389 throw new NullPointerException("Headers may not be null"); 390 } 391 392 int[] headerList = headers.getHeaderList(); 393 if (headerList != null) { 394 for (int i = 0; i < headerList.length; i++) { 395 requestHeaders.setHeader(headerList[i], headers.getHeader(headerList[i])); 396 } 397 } 398 } 399 400 /** 401 * Reads a response from the server. It will populate the appropriate body 402 * and headers. 403 * 404 * @return <code>true</code> if the transaction should end; 405 * <code>false</code> if the transaction should not end 406 * 407 * @exception IOException if an IO error occurred 408 */ 409 private boolean readResponse() throws IOException { 410 replyHeaders.responseCode = socketInput.read(); 411 int packetLength = socketInput.read(); 412 packetLength = (packetLength << 8) + socketInput.read(); 413 414 if (packetLength > OBEXConstants.MAX_PACKET_SIZE_INT) { 415 if (exceptionMessage != null) { 416 abort(); 417 } 418 throw new IOException("Received a packet that was too big"); 419 } 420 421 if (packetLength > BASE_PACKET_LENGTH) { 422 int dataLength = packetLength - BASE_PACKET_LENGTH; 423 byte[] data = new byte[dataLength]; 424 int readLength = socketInput.read(data); 425 if (readLength != dataLength) { 426 throw new IOException("Received a packet without data as decalred length"); 427 } 428 byte[] body = OBEXHelper.updateHeaderSet(replyHeaders, data); 429 430 if (body != null) { 431 privateInput.writeBytes(body, 1); 432 433 /* 434 * Determine if a body (0x48) header or an end of body (0x49) 435 * was received. If we received an end of body and 436 * a response code of OBEX_HTTP_OK, then the operation should 437 * end. 438 */ 439 if ((body[0] == 0x49) && (replyHeaders.responseCode == ResponseCodes.OBEX_HTTP_OK)) { 440 return false; 441 } 442 } 443 } 444 445 if (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE) { 446 return true; 447 } else { 448 return false; 449 } 450 } 451 452 /** 453 * Verifies that additional information may be sent. In other words, the 454 * operation is not done. 455 * 456 * @exception IOException if the operation is completed 457 */ 458 public void ensureNotDone() throws IOException { 459 if (isDone) { 460 throw new IOException("Operation has completed"); 461 } 462 } 463 464 /** 465 * Verifies that the connection is open and no exceptions should be thrown. 466 * 467 * @exception IOException if an exception needs to be thrown 468 */ 469 public void ensureOpen() throws IOException { 470 parent.ensureOpen(); 471 472 if (exceptionMessage != null) { 473 throw new IOException(exceptionMessage); 474 } 475 if (isClosed) { 476 throw new IOException("Operation has already ended"); 477 } 478 } 479 480 /** 481 * Verifies that the connection is open and the proper data has been read. 482 * 483 * @exception IOException if an IO error occurs 484 */ 485 private void validateConnection() throws IOException { 486 ensureOpen(); 487 488 // to sure only one privateInput object exist. 489 if (privateInput == null) { 490 startProcessing(); 491 } 492 } 493 494 /** 495 * Sends a request to the client of the specified type 496 * 497 * @param response the response code to send back to the client 498 * 499 * @return <code>true</code> if there is more data to send; 500 * <code>false</code> if there is no more data to send 501 * 502 * @exception IOException if an IO error occurs 503 */ 504 protected boolean sendRequest(int type) throws IOException { 505 boolean returnValue = false; 506 ByteArrayOutputStream out = new ByteArrayOutputStream(); 507 int bodyLength = -1; 508 byte[] headerArray = OBEXHelper.createHeader(requestHeaders, true); 509 if (privateOutput != null) { 510 bodyLength = privateOutput.size(); 511 } 512 513 /* 514 * Determine if there is space to add a body request. At present 515 * this method checks to see if there is room for at least a 17 516 * byte body header. This number needs to be at least 6 so that 517 * there is room for the header ID and length and the reply ID and 518 * length, but it is a waste of resources if we can't send much of 519 * the body. 520 */ 521 if ((BASE_PACKET_LENGTH + headerArray.length) > maxPacketSize) { 522 int end = 0; 523 int start = 0; 524 // split & send the headerArray in multiple packets. 525 526 while (end != headerArray.length) { 527 //split the headerArray 528 end = OBEXHelper.findHeaderEnd(headerArray, start, maxPacketSize 529 - BASE_PACKET_LENGTH); 530 // can not split 531 if (end == -1) { 532 isDone = true; 533 abort(); 534 // isDone = true; 535 exceptionMessage = "Header larger then can be sent in a packet"; 536 isClosed = true; 537 538 if (privateInput != null) { 539 privateInput.close(); 540 } 541 542 if (privateOutput != null) { 543 privateOutput.close(); 544 } 545 throw new IOException("OBEX Packet exceeds max packet size"); 546 } 547 548 byte[] sendHeader = new byte[end - start]; 549 System.arraycopy(headerArray, start, sendHeader, 0, sendHeader.length); 550 if (!parent.sendRequest(type, sendHeader, replyHeaders, privateInput)) { 551 return false; 552 } 553 554 if (replyHeaders.responseCode != OBEXConstants.OBEX_HTTP_CONTINUE) { 555 return false; 556 } 557 558 start = end; 559 } 560 561 if (bodyLength > 0) { 562 return true; 563 } else { 564 return false; 565 } 566 } else { 567 out.write(headerArray); 568 } 569 570 if (bodyLength > 0) { 571 /* 572 * Determine if I can send the whole body or just part of 573 * the body. Remember that there is the 3 bytes for the 574 * response message and 3 bytes for the header ID and length 575 */ 576 if (bodyLength > (maxPacketSize - headerArray.length - 6)) { 577 returnValue = true; 578 579 bodyLength = maxPacketSize - headerArray.length - 6; 580 } 581 582 byte[] body = privateOutput.readBytes(bodyLength); 583 584 /* 585 * Since this is a put request if the final bit is set or 586 * the output stream is closed we need to send the 0x49 587 * (End of Body) otherwise, we need to send 0x48 (Body) 588 */ 589 if ((privateOutput.isClosed()) && (!returnValue) && (!isEndOfBodySent) 590 && ((type & 0x80) != 0)) { 591 out.write(0x49); 592 isEndOfBodySent = true; 593 } else { 594 out.write(0x48); 595 } 596 597 bodyLength += 3; 598 out.write((byte)(bodyLength >> 8)); 599 out.write((byte)bodyLength); 600 601 if (body != null) { 602 out.write(body); 603 } 604 } 605 606 if (outputStreamOpened && bodyLength <= 0 && !isEndOfBodySent) { 607 // only 0x82 or 0x83 can send 0x49 608 if ((type & 0x80) == 0) { 609 out.write(0x48); 610 } else { 611 out.write(0x49); 612 isEndOfBodySent = true; 613 614 } 615 616 bodyLength = 3; 617 out.write((byte)(bodyLength >> 8)); 618 out.write((byte)bodyLength); 619 } 620 621 if (out.size() == 0) { 622 if (!parent.sendRequest(type, null, replyHeaders, privateInput)) { 623 return false; 624 } 625 return returnValue; 626 } 627 if ((out.size() > 0) 628 && (!parent.sendRequest(type, out.toByteArray(), replyHeaders, privateInput))) { 629 return false; 630 } 631 632 // send all of the output data in 0x48, 633 // send 0x49 with empty body 634 if ((privateOutput != null) && (privateOutput.size() > 0)) 635 returnValue = true; 636 637 return returnValue; 638 } 639 640 /** 641 * This method starts the processing thread results. It will send the 642 * initial request. If the response takes more then one packet, a thread 643 * will be started to handle additional requests 644 * 645 * @exception IOException if an IO error occurs 646 */ 647 private synchronized void startProcessing() throws IOException { 648 649 if (privateInput == null) { 650 privateInput = new PrivateInputStream(this); 651 } 652 boolean more = true; 653 654 if (isGet) { 655 if (!isDone) { 656 replyHeaders.responseCode = OBEXConstants.OBEX_HTTP_CONTINUE; 657 while ((more) && (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE)) { 658 more = sendRequest(0x03); 659 } 660 661 if (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE) { 662 parent.sendRequest(0x83, null, replyHeaders, privateInput); 663 } 664 if (replyHeaders.responseCode != OBEXConstants.OBEX_HTTP_CONTINUE) { 665 isDone = true; 666 } 667 } 668 } else { 669 670 if (!isDone) { 671 replyHeaders.responseCode = OBEXConstants.OBEX_HTTP_CONTINUE; 672 while ((more) && (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE)) { 673 more = sendRequest(0x02); 674 675 } 676 } 677 678 if (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE) { 679 parent.sendRequest(0x82, null, replyHeaders, privateInput); 680 } 681 682 if (replyHeaders.responseCode != OBEXConstants.OBEX_HTTP_CONTINUE) { 683 isDone = true; 684 } 685 } 686 } 687 688 /** 689 * Continues the operation since there is no data to read. 690 * 691 * @param sendEmpty <code>true</code> if the operation should send an 692 * empty packet or not send anything if there is no data to send 693 * @param inStream <code>true</code> if the stream is input stream or 694 * is output stream 695 * @exception IOException if an IO error occurs 696 */ 697 public synchronized boolean continueOperation(boolean sendEmpty, boolean inStream) 698 throws IOException { 699 700 if (isGet) { 701 if ((inStream) && (!isDone)) { 702 // to deal with inputstream in get operation 703 parent.sendRequest(0x83, null, replyHeaders, privateInput); 704 /* 705 * Determine if that was not the last packet in the operation 706 */ 707 if (replyHeaders.responseCode != OBEXConstants.OBEX_HTTP_CONTINUE) { 708 isDone = true; 709 } 710 711 return true; 712 713 } else if ((!inStream) && (!isDone)) { 714 // to deal with outputstream in get operation 715 716 if (privateInput == null) { 717 privateInput = new PrivateInputStream(this); 718 } 719 sendRequest(0x03); 720 return true; 721 722 } else if (isDone) { 723 return false; 724 } 725 726 } else { 727 if ((!inStream) && (!isDone)) { 728 // to deal with outputstream in put operation 729 if (replyHeaders.responseCode == -1) { 730 replyHeaders.responseCode = OBEXConstants.OBEX_HTTP_CONTINUE; 731 } 732 sendRequest(0x02); 733 return true; 734 } else if ((inStream) && (!isDone)) { 735 // How to deal with inputstream in put operation ? 736 return false; 737 738 } else if (isDone) { 739 return false; 740 } 741 742 } 743 return false; 744 } 745 746 /** 747 * Called when the output or input stream is closed. 748 * 749 * @param inStream <code>true</code> if the input stream is closed; 750 * <code>false</code> if the output stream is closed 751 * 752 * @exception IOException if an IO error occurs 753 */ 754 public void streamClosed(boolean inStream) throws IOException { 755 if (!isGet) { 756 if ((!inStream) && (!isDone)) { 757 // to deal with outputstream in put operation 758 759 boolean more = true; 760 761 if ((privateOutput != null) && (privateOutput.size() <= 0)) { 762 byte[] headerArray = OBEXHelper.createHeader(requestHeaders, false); 763 if (headerArray.length <= 0) 764 more = false; 765 } 766 // If have not sent any data so send all now 767 if (replyHeaders.responseCode == -1) { 768 replyHeaders.responseCode = OBEXConstants.OBEX_HTTP_CONTINUE; 769 } 770 771 while ((more) && (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE)) { 772 more = sendRequest(0x02); 773 } 774 775 /* 776 * According to the IrOBEX specification, after the final put, you 777 * only have a single reply to send. so we don't need the while 778 * loop. 779 */ 780 while (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE) { 781 782 sendRequest(0x82); 783 } 784 isDone = true; 785 } else if ((inStream) && (isDone)) { 786 // how to deal with input stream in put stream ? 787 isDone = true; 788 } 789 } else { 790 isValidateConnected = false; 791 if ((inStream) && (!isDone)) { 792 793 // to deal with inputstream in get operation 794 // Have not sent any data so send it all now 795 796 if (replyHeaders.responseCode == -1) { 797 replyHeaders.responseCode = OBEXConstants.OBEX_HTTP_CONTINUE; 798 } 799 800 while (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE) { 801 if (!sendRequest(0x83)) { 802 break; 803 } 804 } 805 while (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE) { 806 parent.sendRequest(0x83, null, replyHeaders, privateInput); 807 } 808 isDone = true; 809 } else if ((!inStream) && (!isDone)) { 810 // to deal with outputstream in get operation 811 // part of the data may have been sent in continueOperation. 812 813 boolean more = true; 814 815 if ((privateOutput != null) && (privateOutput.size() <= 0)) { 816 byte[] headerArray = OBEXHelper.createHeader(requestHeaders, false); 817 if (headerArray.length <= 0) 818 more = false; 819 } 820 821 if (privateInput == null) { 822 privateInput = new PrivateInputStream(this); 823 } 824 if ((privateOutput != null) && (privateOutput.size() <= 0)) 825 more = false; 826 827 replyHeaders.responseCode = OBEXConstants.OBEX_HTTP_CONTINUE; 828 while ((more) && (replyHeaders.responseCode == OBEXConstants.OBEX_HTTP_CONTINUE)) { 829 more = sendRequest(0x03); 830 } 831 sendRequest(0x83); 832 // parent.sendRequest(0x83, null, replyHeaders, privateInput); 833 if (replyHeaders.responseCode != OBEXConstants.OBEX_HTTP_CONTINUE) { 834 isDone = true; 835 } 836 837 } 838 } 839 } 840} 841