0001: /*
0002: * @(#)ConnectionBaseAdapter.java 1.7 06/10/10
0003: *
0004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
0005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
0006: *
0007: * This program is free software; you can redistribute it and/or
0008: * modify it under the terms of the GNU General Public License version
0009: * 2 only, as published by the Free Software Foundation.
0010: *
0011: * This program is distributed in the hope that it will be useful, but
0012: * WITHOUT ANY WARRANTY; without even the implied warranty of
0013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
0014: * General Public License version 2 for more details (a copy is
0015: * included at /legal/license.txt).
0016: *
0017: * You should have received a copy of the GNU General Public License
0018: * version 2 along with this work; if not, write to the Free Software
0019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
0020: * 02110-1301 USA
0021: *
0022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
0023: * Clara, CA 95054 or visit www.sun.com if you need additional
0024: * information or have any questions.
0025: */
0026:
0027: package com.sun.cdc.io;
0028:
0029: import com.sun.cdc.io.ConnectionBaseInterface;
0030: import com.sun.cdc.io.GeneralBase;
0031:
0032: //import com.sun.midp.midlet.*;
0033:
0034: //import com.sun.midp.security.*;
0035:
0036: import java.io.*;
0037:
0038: import javax.microedition.io.*;
0039:
0040: /**
0041: * Protocol classes extend this class to gain some of the common functionality
0042: * needed to implement a CDC Generic Connection.
0043: * <p>
0044: * The common functionality includes:</p>
0045: * <ul>
0046: * <li>Supplies the input and output stream classes for a StreamConnection</li>
0047: * <li>Limits the number of streams opened according to mode, but the limit
0048: * can be overridden. Read-write allows 1 input and 1 output, write-only
0049: * allows 1 output, read-only allows 1 input</li>
0050: * <li>Only "disconnects" when the connection and all streams are closed</li>
0051: * <li>Throws I/O exceptions when used after being closed</li>
0052: * <li>Provides a more efficient implementation of
0053: * {@link InputStream#read(byte[], int, int)}, which is called by
0054: * {@link InputStream#read()}
0055: * <li>Provides a more efficient implementation of
0056: * {@link OutputStream#write(byte[], int, int)}, which is called by
0057: * {@link OutputStream#write(int)}
0058: * </ul>
0059: * <p align="center">
0060: * <b>Class Relationship Diagram</b></p>
0061: * <p align="center">
0062: * <img src="doc-files/ConnectionBaseAdapter.gif" border=0></p>
0063: *
0064: * @version 3.0 9/1/2000
0065: */
0066: public abstract class ConnectionBaseAdapter implements
0067: ConnectionBaseInterface, StreamConnection {
0068:
0069: /** Flag indicating if the connection is open. */
0070: protected boolean connectionOpen = false;
0071: /** Number of input streams that were opened. */
0072: protected static int iStreams = 0;
0073: /**
0074: * Maximum number of open input streams. Set this
0075: * to zero to prevent openInputStream from giving out a stream in
0076: * write-only mode.
0077: */
0078: protected int maxIStreams = 1;
0079: /** Number of output streams were opened. */
0080: protected static int oStreams = 0;
0081: /**
0082: * Maximum number of output streams. Set this
0083: * to zero to prevent openOutputStream from giving out a stream in
0084: * read-only mode.
0085: */
0086: protected int maxOStreams = 1;
0087:
0088: /**
0089: * Check for required permission and open a connection to a target.
0090: *
0091: * @param name URL for the connection, without the
0092: * without the protocol part
0093: * @param mode I/O access mode, see {@link Connector}
0094: * @param timeouts flag to indicate that the caller
0095: * wants timeout exceptions
0096: * @return this Connection object
0097: *
0098: * @exception IllegalArgumentException If a parameter is invalid.
0099: * @exception ConnectionNotFoundException If the connection cannot
0100: * be found.
0101: * @exception IOException If some other kind of I/O error occurs.
0102: */
0103: public Connection openPrim(String name, int mode, boolean timeouts)
0104: throws IOException {
0105: /// checkForPermission(null, name); // Give the subclass a chance to check
0106: /// checkForPermission(name); // Give the subclass a chance to check
0107:
0108: switch (mode) {
0109: case Connector.READ:
0110: case Connector.WRITE:
0111: case Connector.READ_WRITE:
0112: break;
0113:
0114: default:
0115: throw new IllegalArgumentException("Illegal mode");
0116: }
0117:
0118: connect(name, mode, timeouts);
0119: connectionOpen = true;
0120: return this ;
0121: }
0122:
0123: /**
0124: * Overridden by Protocols to check for permissions.
0125: * This implementation always throws a security exception.
0126: * The subclass is responsible for checking permissions and
0127: * maintaining the state (in private local fields) as to whether
0128: * it was granted.
0129: *
0130: * @param token security token of the calling class or null
0131: * @param name the URL of the connection without the protocol
0132: *
0133: * @exception SecurityException if permissions are not granted
0134: * @exception InterruptedIOException if I/O associated with permissions is interrupted
0135: */
0136: /// protected void checkForPermission(SecurityToken token, String name)
0137: protected void checkForPermission() throws SecurityException,
0138: InterruptedIOException {
0139: throw new SecurityException("Permission not granted");
0140: }
0141:
0142: /**
0143: * Utility method to check for the required permission, and handle
0144: * prompts, etc. A SecurityToken may be supplied, in which case
0145: * the permission must be allowed by the token. If the token is
0146: * <code>null</code> then the permission is checked in the current
0147: * app. If there is no app then the permission
0148: * is allowed. A SecurityException is thrown when the permission
0149: * is not granted.
0150: *
0151: * @param token security token of the calling class or null
0152: * @param requiredPermission the permission that is needed
0153: * @param name resource to insert into the permission question
0154: * @param protocol the protocol string used in the resource name
0155: *
0156: * @exception SecurityException if the permission is not granted
0157: * @exception InterruptedIOException if another thread interrupts the
0158: * calling thread while this method is waiting to preempt the
0159: * display.
0160: */
0161: /// protected final void checkForPermission(SecurityToken token,
0162: /// int requiredPermission,
0163: /// String name, String protocol)
0164: /// protected final void checkForPermission()
0165: /// throws InterruptedIOException
0166: ///{
0167: /// If a security token was supplied, use it for the check
0168: /// if (token != null) {
0169: /// token.checkIfPermissionAllowed(requiredPermission);
0170: /// return;
0171: ///}
0172: /// Scheduler scheduler;
0173: /// MIDletSuite midletSuite;
0174: /// scheduler = Scheduler.getScheduler();
0175: /// midletSuite = scheduler.getMIDletSuite();
0176: /// there is no suite running when installing from the command line
0177: /// if (midletSuite != null) {
0178: /// if (protocol != null) {
0179: /// name = protocol + ":" + name;
0180: /// }
0181: /// try {
0182: /// midletSuite.checkForPermission(requiredPermission, name);
0183: /// } catch (InterruptedException ie) {
0184: /// throw new InterruptedIOException(
0185: /// "Interrupted while trying to ask the user permission");
0186: /// }
0187: ///}
0188: ///}
0189: /**
0190: * Check for the required permission and open a connection to a target.
0191: * This method can be used with permissions greater than
0192: * the current app.
0193: *
0194: * @param token security token of the calling class
0195: * @param name URL for the connection, without the
0196: * without the protocol part
0197: * @param mode I/O access mode, see {@link Connector}
0198: * @param timeouts flag to indicate that the caller
0199: * wants timeout exceptions
0200: * @return this Connection object
0201: *
0202: * @exception IllegalArgumentException If a parameter is invalid.
0203: * @exception ConnectionNotFoundException If the connection cannot
0204: * be found.
0205: * @exception IOException If some other kind of I/O error occurs.
0206: */
0207: /// public Connection openPrim(SecurityToken token, String name, int mode,
0208: /// boolean timeouts) throws IOException {
0209: /// checkForPermission(token, name);
0210: /// public Connection openPrim(String name, int mode,
0211: /// boolean timeouts) throws IOException {
0212: /// checkForPermission();
0213: /// return openPrim(name, mode, timeouts);
0214: /// }
0215: /**
0216: * Check for required permission and open a connection to a target.
0217: * This method can be used with permissions greater than
0218: * the current app. Assume read/write and no timeouts.
0219: *
0220: * @param token security token of the calling class
0221: * @param name URL for the connection, without the
0222: * without the protocol part
0223: * @return this Connection object
0224: *
0225: * @exception IllegalArgumentException If a parameter is invalid.
0226: * @exception ConnectionNotFoundException If the connection cannot
0227: * be found.
0228: * @exception IOException If some other kind of I/O error occurs.
0229: */
0230: /// public Connection openPrim(SecurityToken token, String name)
0231: /// throws IOException {
0232: /// return openPrim(token, name, Connector.READ_WRITE, false);
0233: public Connection openPrim(String name) throws IOException {
0234: return openPrim(name, Connector.READ_WRITE, false);
0235: }
0236:
0237: /**
0238: * Returns an input stream.
0239: *
0240: * @return an input stream for writing bytes to this port.
0241: * @exception IOException if an I/O error occurs when creating the
0242: * output stream.
0243: */
0244: public InputStream openInputStream() throws IOException {
0245: InputStream i;
0246:
0247: ensureOpen();
0248:
0249: /* Fix for CR 6246819: Comment out MIDP code that limits streams so
0250: that multiple streams are supported for CDC */
0251: /*if (maxIStreams == 0) {
0252: throw new IOException("no more input streams available");
0253: }*/
0254:
0255: i = new BaseInputStream(this );
0256: //maxIStreams--;
0257: iStreams++;
0258: return i;
0259: }
0260:
0261: /**
0262: * Open and return a data input stream for a connection.
0263: *
0264: * @return An input stream
0265: * @exception IOException If an I/O error occurs
0266: */
0267: public DataInputStream openDataInputStream() throws IOException {
0268: return new DataInputStream(openInputStream());
0269: }
0270:
0271: /**
0272: * Returns an output stream.
0273: *
0274: * @return an output stream for writing bytes to this port.
0275: * @exception IOException if an I/O error occurs when creating the
0276: * output stream.
0277: */
0278: public OutputStream openOutputStream() throws IOException {
0279: OutputStream o;
0280:
0281: ensureOpen();
0282: /* Fix for CR 6246819: Comment out MIDP code that limits streams so
0283: that multiple streams are supported for CDC */
0284: /*if (maxOStreams == 0) {
0285: throw new IOException("no more output streams available");
0286: }*/
0287:
0288: o = new BaseOutputStream(this );
0289: //maxOStreams--;
0290: oStreams++;
0291: return o;
0292: }
0293:
0294: /**
0295: * Open and return a data output stream for a connection.
0296: *
0297: * @return An input stream
0298: * @exception IOException If an I/O error occurs
0299: */
0300: public DataOutputStream openDataOutputStream() throws IOException {
0301: return new DataOutputStream(openOutputStream());
0302: }
0303:
0304: /**
0305: * Close the connection.
0306: *
0307: * @exception IOException if an I/O error occurs when closing the
0308: * connection.
0309: */
0310: public void close() throws IOException {
0311: if (connectionOpen) {
0312: connectionOpen = false;
0313: closeCommon();
0314: }
0315: }
0316:
0317: /**
0318: * Called once by each child input stream.
0319: * If the input stream is marked open, it will be marked closed and
0320: * the if the connection and output stream are closed the disconnect
0321: * method will be called.
0322: *
0323: * @exception IOException if the subclass throws one
0324: */
0325: protected void closeInputStream() throws IOException {
0326: iStreams--;
0327: closeCommon();
0328: }
0329:
0330: /**
0331: * Called once by each child output stream.
0332: * If the output stream is marked open, it will be marked closed and
0333: * the if the connection and input stream are closed the disconnect
0334: * method will be called.
0335: *
0336: * @exception IOException if the subclass throws one
0337: */
0338: protected void closeOutputStream() throws IOException {
0339: oStreams--;
0340: closeCommon();
0341: }
0342:
0343: /**
0344: * Disconnect if the connection and all the streams and the closed.
0345: *
0346: * @exception IOException if an I/O error occurs when closing the
0347: * connection.
0348: */
0349: void closeCommon() throws IOException {
0350: if (!connectionOpen && iStreams == 0 && oStreams == 0) {
0351: disconnect();
0352: }
0353: }
0354:
0355: /**
0356: * Check if the connection is open.
0357: *
0358: * @exception IOException is thrown, if the stream is not open.
0359: */
0360: protected void ensureOpen() throws IOException {
0361: if (!connectionOpen) {
0362: throw new IOException("Connection closed");
0363: }
0364: }
0365:
0366: /**
0367: * Check if the streams are open.
0368: *
0369: * @exception IOException is thrown, if the stream is still open.
0370: */
0371: protected void ensureNoStreamsOpen() throws IOException {
0372: if ((iStreams > 0) || (oStreams > 0)) {
0373: throw new IOException("Stream is still open");
0374: }
0375: }
0376:
0377: /**
0378: * Connect to a target.
0379: *
0380: * @param name URL for the connection, without the protocol
0381: * part
0382: * @param mode I/O access mode, see {@link Connector}
0383: * @param timeouts flag to indicate that the called wants
0384: * timeout exceptions
0385: *
0386: * @exception IllegalArgumentException If a parameter is invalid.
0387: * @exception ConnectionNotFoundException If the connection cannot be
0388: * found.
0389: * @exception IOException If some other kind of I/O error occurs.
0390: */
0391: protected abstract void connect(String name, int mode,
0392: boolean timeouts) throws IOException;
0393:
0394: /**
0395: * Free up the connection resources.
0396: *
0397: * @exception IOException if an I/O error occurs.
0398: */
0399: protected abstract void disconnect() throws IOException;
0400:
0401: /**
0402: * Reads up to <code>len</code> bytes of data from the input stream into
0403: * an array of bytes, blocks until at least one byte is available.
0404: *
0405: * @param b the buffer into which the data is read.
0406: * @param off the start offset in array <code>b</code>
0407: * at which the data is written.
0408: * @param len the maximum number of bytes to read.
0409: * @return the total number of bytes read into the buffer, or
0410: * <code>-1</code> if there is no more data because the end of
0411: * the stream has been reached.
0412: * @exception IOException if an I/O error occurs.
0413: */
0414: protected abstract int readBytes(byte b[], int off, int len)
0415: throws IOException;
0416:
0417: /**
0418: * Returns the number of bytes that can be read (or skipped over) from
0419: * this input stream without blocking by the next caller of a method for
0420: * this input stream. The next caller might be the same thread or
0421: * another thread. This classes implementation always returns
0422: * <code>0</code>. It is up to subclasses to override this method.
0423: *
0424: * @return the number of bytes that can be read from this input stream
0425: * without blocking.
0426: * @exception IOException if an I/O error occurs.
0427: */
0428: public int available() throws IOException {
0429: return 0;
0430: }
0431:
0432: /**
0433: * Writes <code>len</code> bytes from the specified byte array
0434: * starting at offset <code>off</code> to this output stream.
0435: * <p>
0436: * Polling the native code is done here to allow for simple
0437: * asynchronous native code to be written. Not all implementations
0438: * work this way (they block in the native code) but the same
0439: * Java code works for both.
0440: *
0441: * @param b the data.
0442: * @param off the start offset in the data.
0443: * @param len the number of bytes to write.
0444: * @return number of bytes written
0445: * @exception IOException if an I/O error occurs. In particular,
0446: * an <code>IOException</code> is thrown if the output
0447: * stream is closed.
0448: */
0449: protected abstract int writeBytes(byte b[], int off, int len)
0450: throws IOException;
0451:
0452: /**
0453: * Forces any buffered output bytes to be written out.
0454: * The general contract of <code>flush</code> is
0455: * that calling it is an indication that, if any bytes previously
0456: * written that have been buffered by the connection,
0457: * should immediately be written to their intended destination.
0458: * <p>
0459: * The <code>flush</code> method of <code>ConnectionBaseAdapter</code>
0460: * does nothing.
0461: *
0462: * @exception IOException if an I/O error occurs.
0463: */
0464: protected void flush() throws IOException {
0465: }
0466:
0467: /**
0468: * Tests if input stream for a connection supports the <code>mark</code> and
0469: * <code>reset</code> methods.
0470: *
0471: * <p> The <code>markSupported</code> method of
0472: * <code>ConnectionBaseAdapter</code> returns <code>false</code>.
0473: *
0474: * <p> Subclasses should override this method if they support own mark/reset
0475: * functionality.
0476: *
0477: * @return <code>true</code> if input stream for this connection supports
0478: * the <code>mark</code> and <code>reset</code> methods;
0479: * <code>false</code> otherwise.
0480: * @see java.io.InputStream#mark(int)
0481: * @see java.io.InputStream#reset()
0482: */
0483: public boolean markSupported() {
0484: return false;
0485: }
0486:
0487: /**
0488: * Marks the current position in input stream for a connection.
0489: * A subsequent call to the <code>reset</code> method repositions this
0490: * stream at the last marked position so that subsequent reads re-read
0491: * the same bytes.
0492: *
0493: * <p> The <code>mark</code> method of <code>ConnectionBaseAdapter</code>
0494: * does nothing.
0495: *
0496: * <p> Subclasses should override this method if they support own mark/reset
0497: * functionality.
0498: *
0499: * @param readlimit the maximum limit of bytes that can be read before
0500: * the mark position becomes invalid.
0501: * @see java.io.InputStream#reset()
0502: */
0503: public synchronized void mark(int readlimit) {
0504: }
0505:
0506: /**
0507: * Repositions input stream for a connection to the position at the time the
0508: * <code>mark</code> method was last called on this input stream.
0509: *
0510: * <p> The method <code>reset</code> for <code>ConnectionBaseAdapter</code>
0511: * class does nothing and always throws an <code>IOException</code>.
0512: *
0513: * <p> Subclasses should override this method if they support own mark/reset
0514: * functionality.
0515: *
0516: * @exception IOException if this stream has not been marked or if the
0517: * mark has been invalidated.
0518: * @see java.io.InputStream#reset()
0519: * @see java.io.InputStream#mark(int)
0520: * @see java.io.IOException
0521: */
0522: public synchronized void reset() throws IOException {
0523: throw new IOException("mark/reset not supported");
0524: }
0525: }
0526:
0527: /**
0528: * Input stream for the connection
0529: */
0530: class BaseInputStream extends InputStream {
0531:
0532: /** Pointer to the connection */
0533: private ConnectionBaseAdapter parent;
0534:
0535: /** Buffer for single char reads */
0536: byte[] buf = new byte[1];
0537:
0538: /**
0539: * Buffer for mark/reset funtionality support.
0540: * <code>null</code> value indicates <code>mark</code> was not called or
0541: * <code>readlimit</code> value of the last <code>mark</code> was exceeded.
0542: */
0543: byte[] markBuf = null;
0544:
0545: /** The size of data stored in <code>markBuf</code>. */
0546: int markSize = 0;
0547:
0548: /** Current position in <code>markBuf</code> to read data from. */
0549: int markPos = 0;
0550:
0551: /**
0552: * Indicates whether <code>reset</code> method was called.
0553: * If so, data is read from <code>markBuf</code> buffer,
0554: * otherwise via <code>parent.readBytes</code> method.
0555: */
0556: boolean isReadFromBuffer = false;
0557:
0558: /**
0559: * Constructs a BaseInputStream for a ConnectionBaseAdapter.
0560: *
0561: * @param parent pointer to the connection object
0562: *
0563: * @exception IOException if an I/O error occurs.
0564: */
0565: BaseInputStream(ConnectionBaseAdapter parent) throws IOException {
0566: this .parent = parent;
0567: }
0568:
0569: /**
0570: * Check the stream is open
0571: *
0572: * @exception InterruptedIOException if it is not.
0573: */
0574: private void ensureOpen() throws InterruptedIOException {
0575: if (parent == null) {
0576: throw new InterruptedIOException("Stream closed");
0577: }
0578: }
0579:
0580: /**
0581: * Returns the number of bytes that can be read (or skipped over) from
0582: * this input stream without blocking by the next caller of a method for
0583: * this input stream. The next caller might be the same thread or
0584: * another thread.
0585: *
0586: * <p>The <code>available</code> method always returns <code>0</code> if
0587: * {@link ConnectionBaseAdapter#available()} is
0588: * not overridden by the subclass.
0589: *
0590: * @return the number of bytes that can be read from this input stream
0591: * without blocking.
0592: * @exception IOException if an I/O error occurs.
0593: */
0594: public int available() throws IOException {
0595:
0596: ensureOpen();
0597:
0598: return parent.available();
0599: }
0600:
0601: /**
0602: * Reads the next byte of data from the input stream. The value byte is
0603: * returned as an <code>int</code> in the range <code>0</code> to
0604: * <code>255</code>. If no byte is available because the end of the stream
0605: * has been reached, the value <code>-1</code> is returned. This method
0606: * blocks until input data is available, the end of the stream is detected,
0607: * or an exception is thrown.
0608: *
0609: * @return the next byte of data, or <code>-1</code> if the end of the
0610: * stream is reached.
0611: * @exception IOException if an I/O error occurs.
0612: */
0613: public int read() throws IOException {
0614: if (read(buf, 0, 1) > 0) {
0615: return (buf[0] & 0xFF);
0616: }
0617:
0618: return -1;
0619: }
0620:
0621: /**
0622: * Reads up to <code>len</code> bytes of data from the input stream into
0623: * an array of bytes. An attempt is made to read as many as
0624: * <code>len</code> bytes, but a smaller number may be read, possibly
0625: * zero. The number of bytes actually read is returned as an integer.
0626: *
0627: * <p> This method blocks until input data is available, end of file is
0628: * detected, or an exception is thrown.
0629: *
0630: * <p> If <code>b</code> is <code>null</code>, a
0631: * <code>NullPointerException</code> is thrown.
0632: *
0633: * <p> If <code>off</code> is negative, or <code>len</code> is negative, or
0634: * <code>off+len</code> is greater than the length of the array
0635: * <code>b</code>, then an <code>IndexOutOfBoundsException</code> is
0636: * thrown.
0637: *
0638: * <p> If <code>len</code> is zero, then no bytes are read and
0639: * <code>0</code> is returned; otherwise, there is an attempt to read at
0640: * least one byte. If no byte is available because the stream is at end of
0641: * file, the value <code>-1</code> is returned; otherwise, at least one
0642: * byte is read and stored into <code>b</code>.
0643: *
0644: * <p> The first byte read is stored into element <code>b[off]</code>, the
0645: * next one into <code>b[off+1]</code>, and so on. The number of bytes read
0646: * is, at most, equal to <code>len</code>. Let <i>k</i> be the number of
0647: * bytes actually read; these bytes will be stored in elements
0648: * <code>b[off]</code> through <code>b[off+</code><i>k</i><code>-1]</code>,
0649: * leaving elements <code>b[off+</code><i>k</i><code>]</code> through
0650: * <code>b[off+len-1]</code> unaffected.
0651: *
0652: * <p> In every case, elements <code>b[0]</code> through
0653: * <code>b[off]</code> and elements <code>b[off+len]</code> through
0654: * <code>b[b.length-1]</code> are unaffected.
0655: *
0656: * <p> If the first byte cannot be read for any reason other than end of
0657: * file, then an <code>IOException</code> is thrown. In particular, an
0658: * <code>IOException</code> is thrown if the input stream has been closed.
0659: *
0660: * @param b the buffer into which the data is read.
0661: * @param off the start offset in array <code>b</code>
0662: * at which the data is written.
0663: * @param len the maximum number of bytes to read.
0664: * @return the total number of bytes read into the buffer, or
0665: * <code>-1</code> if there is no more data because the end of
0666: * the stream has been reached.
0667: * @exception IOException if an I/O error occurs.
0668: * @see java.io.InputStream#read()
0669: */
0670: public int read(byte b[], int off, int len) throws IOException {
0671: int test;
0672:
0673: ensureOpen();
0674:
0675: if (len == 0) {
0676: return 0;
0677: }
0678:
0679: /*
0680: * test the parameters so the subclass will not have to.
0681: * this will avoid crashes in the native code
0682: */
0683: test = b[off] + b[len - 1] + b[off + len - 1];
0684:
0685: // use parent's mark/reset functionality
0686: // if the parent supports the own one
0687: if (parent.markSupported()) {
0688: return parent.readBytes(b, off, len);
0689: }
0690:
0691: // read data from mark buffer if reset method was called
0692: if (isReadFromBuffer) {
0693: int dataSize = markSize - markPos;
0694: if (dataSize > 0) {
0695: int copySize = (dataSize > len) ? len : dataSize;
0696: System.arraycopy(markBuf, markPos, b, off, copySize);
0697: markPos += copySize;
0698:
0699: // read data directly from the stream
0700: // if size of data in the buffer is not enough
0701: int readSize = 0;
0702: if (copySize < len) {
0703: readSize = parent.readBytes(b, off + copySize, len
0704: - copySize);
0705:
0706: // check if eos is reached
0707: if (readSize == -1) {
0708: readSize = 0;
0709: } else {
0710: // check the mark buffer overflow
0711: if (markSize + readSize > markBuf.length) {
0712: markBuf = null;
0713: // cache the data in the mark buffer
0714: } else {
0715: System.arraycopy(b, off + copySize,
0716: markBuf, markSize, readSize);
0717: markSize += readSize;
0718: }
0719: }
0720:
0721: isReadFromBuffer = false;
0722: }
0723:
0724: return copySize + readSize;
0725: } else {
0726: isReadFromBuffer = false;
0727: }
0728: }
0729:
0730: int readSize = parent.readBytes(b, off, len);
0731:
0732: // fill mark buffer if exists
0733: if (markBuf != null) {
0734: if (readSize > 0) {
0735: // check the mark buffer overflow
0736: if (markSize + readSize > markBuf.length) {
0737: markBuf = null;
0738: // cache the data in the mark buffer
0739: } else {
0740: System.arraycopy(b, off, markBuf, markSize,
0741: readSize);
0742: markSize += readSize;
0743: }
0744: }
0745: }
0746:
0747: return readSize;
0748: }
0749:
0750: /**
0751: * Closes this input stream and releases any system resources associated
0752: * with the stream.
0753: *
0754: * @exception IOException if an I/O error occurs.
0755: */
0756: public void close() throws IOException {
0757: if (parent != null) {
0758: parent.closeInputStream();
0759: parent = null;
0760: }
0761: // free buffer used by mark/reset operations if it was allocated
0762: markBuf = null;
0763: }
0764:
0765: /**
0766: * Tests if this input stream supports the <code>mark</code> and
0767: * <code>reset</code> methods.
0768: *
0769: * <p>The <code>markSupported</code> method of
0770: * <code>BaseInputStream</code> returns <code>true</code>.
0771: *
0772: * @return always <code>true</code>
0773: *
0774: * @see BaseInputStream#mark(int)
0775: * @see BaseInputStream#reset()
0776: * @see java.io.InputStream#markSupported()
0777: * @see java.io.InputStream#mark(int)
0778: * @see java.io.InputStream#reset()
0779: */
0780: public boolean markSupported() {
0781: return true;
0782: }
0783:
0784: /**
0785: * Marks the current position in this input stream. A subsequent call to
0786: * the <code>reset</code> method repositions this stream at the last marked
0787: * position so that subsequent reads re-read the same bytes.
0788: *
0789: * <p> The <code>readlimit</code> arguments tells this input stream to
0790: * allow that many bytes to be read before the mark position gets
0791: * invalidated.
0792: *
0793: * <p> The stream remembers all the bytes read after the call to
0794: * <code>mark</code> and stands ready to supply those same bytes again
0795: * if and whenever the method <code>reset</code> is called.
0796: * However, the stream is not required to remember any data at all if more
0797: * than <code>readlimit</code> bytes are read from the stream before
0798: * <code>reset</code> is called.
0799: *
0800: * @param readlimit the maximum limit of bytes that can be read before
0801: * the mark position becomes invalid.
0802: * @see BaseInputStream#reset()
0803: * @see java.io.InputStream#reset()
0804: * @see java.io.InputStream#mark(int)
0805: */
0806: public synchronized void mark(int readlimit) {
0807: // check whether the stream is closed
0808: if (parent == null) {
0809: return;
0810: }
0811:
0812: // use parent's mark/reset functionality
0813: // if the parent supports the own one
0814: if (parent.markSupported()) {
0815: parent.mark(readlimit);
0816: } else {
0817: byte[] oldBuf = markBuf;
0818:
0819: // copy relevant data from old buffer if any
0820: if (isReadFromBuffer) {
0821: int oldDataSize = markSize - markPos;
0822: if (readlimit < oldDataSize) {
0823: readlimit = oldDataSize;
0824: }
0825: markBuf = new byte[readlimit];
0826: System.arraycopy(oldBuf, markPos, markBuf, 0,
0827: oldDataSize);
0828: markSize = oldDataSize;
0829: } else {
0830: markBuf = new byte[readlimit];
0831: markSize = 0;
0832: }
0833: markPos = 0;
0834: }
0835: }
0836:
0837: /**
0838: * Repositions this stream to the position at the time the
0839: * <code>mark</code> method was last called on this input stream.
0840: *
0841: * <p> If the method <code>mark</code> has not been called since
0842: * the stream was created, or the number of bytes read from the stream
0843: * since <code>mark</code> was last called is larger than the argument
0844: * to <code>mark</code> at that last call, then an
0845: * <code>IOException</code> is thrown.
0846: *
0847: * <p> If such an <code>IOException</code> is not thrown, then the
0848: * stream is reset to a state such that all the bytes read since the
0849: * most recent call to <code>mark</code> will be resupplied
0850: * to subsequent callers of the <code>read</code> method, followed by
0851: * any bytes that otherwise would have been the next input data as of
0852: * the time of the call to <code>reset</code>.
0853: *
0854: * @exception IOException if this stream has not been marked or if the
0855: * mark has been invalidated;
0856: * or if the stream is closed
0857: * @see BaseInputStream#mark(int)
0858: * @see java.io.InputStream#mark(int)
0859: * @see java.io.InputStream#reset(int)
0860: * @see java.io.IOException
0861: */
0862: public synchronized void reset() throws IOException {
0863: ensureOpen();
0864:
0865: // use parent's mark/reset functionality
0866: // if the parent supports the own one
0867: if (parent.markSupported()) {
0868: parent.reset();
0869: } else {
0870: if (markBuf == null) {
0871: throw new IOException("Invalid mark position");
0872: }
0873: markPos = 0;
0874: isReadFromBuffer = true;
0875: }
0876: }
0877: }
0878:
0879: /**
0880: * Output stream for the connection
0881: */
0882: class BaseOutputStream extends OutputStream {
0883:
0884: /** Pointer to the connection */
0885: ConnectionBaseAdapter parent;
0886:
0887: /** Buffer for single char writes */
0888: byte[] buf = new byte[1];
0889:
0890: /**
0891: * Constructs a BaseOutputStream for an ConnectionBaseAdapter.
0892: *
0893: * @param p parent connection
0894: */
0895: BaseOutputStream(ConnectionBaseAdapter p) {
0896: parent = p;
0897: }
0898:
0899: /**
0900: * Check the stream is open
0901: *
0902: * @exception InterruptedIOException if it is not.
0903: */
0904: private void ensureOpen() throws InterruptedIOException {
0905: if (parent == null) {
0906: throw new InterruptedIOException("Stream closed");
0907: }
0908: }
0909:
0910: /**
0911: * Writes the specified byte to this output stream. The general
0912: * contract for <code>write</code> is that one byte is written
0913: * to the output stream. The byte to be written is the eight
0914: * low-order bits of the argument <code>b</code>. The 24
0915: * high-order bits of <code>b</code> are ignored.
0916: *
0917: * @param b the <code>byte</code>.
0918: * @exception IOException if an I/O error occurs. In particular,
0919: * an <code>IOException</code> may be thrown if the
0920: * output stream has been closed.
0921: */
0922: public void write(int b) throws IOException {
0923: buf[0] = (byte) b;
0924: write(buf, 0, 1);
0925: }
0926:
0927: /**
0928: * Writes <code>len</code> bytes from the specified byte array
0929: * starting at offset <code>off</code> to this output stream.
0930: * The general contract for <code>write(b, off, len)</code> is that
0931: * some of the bytes in the array <code>b</code> are written to the
0932: * output stream in order; element <code>b[off]</code> is the first
0933: * byte written and <code>b[off+len-1]</code> is the last byte written
0934: * by this operation.
0935: * <p>
0936: * If <code>b</code> is <code>null</code>, a
0937: * <code>NullPointerException</code> is thrown.
0938: * <p>
0939: * If <code>off</code> is negative, or <code>len</code> is negative, or
0940: * <code>off+len</code> is greater than the length of the array
0941: * <code>b</code>, then an <tt>IndexOutOfBoundsException</tt> is thrown.
0942: *
0943: * @param b the data.
0944: * @param off the start offset in the data.
0945: * @param len the number of bytes to write.
0946: * @exception IOException if an I/O error occurs. In particular,
0947: * an <code>IOException</code> is thrown if the output
0948: * stream is closed.
0949: */
0950: public void write(byte b[], int off, int len) throws IOException {
0951: int test;
0952: int bytesWritten;
0953:
0954: ensureOpen();
0955:
0956: if (len == 0) {
0957: return;
0958: }
0959:
0960: /*
0961: * test the parameters here so subclases do not have to,
0962: * this will avoid a crash in the native code
0963: */
0964: test = b[off] + b[len - 1] + b[off + len - 1];
0965:
0966: /*
0967: * Polling the native code is done here to allow for simple
0968: * asynchronous native code to be written. Not all implementations
0969: * work this way (they block in the native code) but the same
0970: * Java code works for both.
0971: */
0972: for (bytesWritten = 0;;) {
0973: try {
0974: bytesWritten += parent.writeBytes(b,
0975: off + bytesWritten, len - bytesWritten);
0976: } finally {
0977: if (parent == null) {
0978: throw new InterruptedIOException("Stream closed");
0979: }
0980: }
0981:
0982: if (bytesWritten == len) {
0983: break;
0984: }
0985:
0986: /// GeneralBase.iowait();
0987: }
0988: }
0989:
0990: /**
0991: * Flushes this output stream and forces any buffered output bytes
0992: * to be written out. The general contract of <code>flush</code> is
0993: * that calling it is an indication that, if any bytes previously
0994: * written have been buffered by the implementation of the output
0995: * stream, such bytes should immediately be written to their
0996: * intended destination.
0997: *
0998: * @exception IOException if an I/O error occurs.
0999: */
1000: public void flush() throws IOException {
1001: ensureOpen();
1002: parent.flush();
1003: }
1004:
1005: /**
1006: * Closes this output stream and releases any system resources
1007: * associated with this stream. The general contract of <code>close</code>
1008: * is that it closes the output stream. A closed stream cannot perform
1009: * output operations and cannot be reopened.
1010: *
1011: * @exception IOException if an I/O error occurs.
1012: */
1013: public void close() throws IOException {
1014: if (parent != null) {
1015: parent.closeOutputStream();
1016: parent = null;
1017: }
1018: }
1019: }
|