001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: package org.apache.harmony.luni.internal.process;
019:
020: import java.io.FileDescriptor;
021: import java.io.IOException;
022:
023: class ProcessInputStream extends java.io.InputStream {
024:
025: private long handle;
026:
027: private FileDescriptor fd;
028:
029: // Fill in the JNI id caches
030: private static native void oneTimeInitialization();
031:
032: static {
033: oneTimeInitialization();
034: }
035:
036: /**
037: * Native to determine the bytes available.
038: */
039: private native int availableImpl() throws IOException;
040:
041: /**
042: * Native to read into the buffer from the stream.
043: */
044: private native int readImpl(byte[] buf, int offset, int nbytes,
045: long hndl) throws IOException;
046:
047: /**
048: * Native to set the FileDescriptor handle.
049: */
050: private native void setFDImpl(FileDescriptor fd, long handle);
051:
052: /**
053: * Native to close the stream.
054: */
055: private native void closeImpl() throws IOException;
056:
057: /**
058: * Open an InputStream based on the handle.
059: */
060: protected ProcessInputStream(long handle) {
061: this .fd = new java.io.FileDescriptor();
062: setFDImpl(fd, handle);
063: this .handle = handle;
064: }
065:
066: @Override
067: public int available() throws IOException {
068: synchronized (this ) {
069: if (handle == -1) {
070: return -1;
071: }
072: return availableImpl();
073: }
074: }
075:
076: /**
077: * There is no way, at the library/vm level, to know when the stream will be
078: * available for closing. If the user doesn't close it in his code, the
079: * finalize() will run (eventually ?) and close the dangling OS
080: * fileDescriptor.
081: */
082: @Override
083: protected void finalize() throws Throwable {
084: close();
085: }
086:
087: @Override
088: public void close() throws IOException {
089: synchronized (this ) {
090: if (handle == -1) {
091: return;
092: }
093: closeImpl();
094: handle = -1;
095: }
096: }
097:
098: @Override
099: public int read() throws IOException {
100: byte buf[] = new byte[1];
101: synchronized (this ) {
102: if (readImpl(buf, 0, 1, handle) == -1) {
103: return -1;
104: }
105: }
106:
107: return buf[0];
108: }
109:
110: @Override
111: public int read(byte[] buffer) throws IOException {
112: synchronized (this ) {
113: return readImpl(buffer, 0, buffer.length, handle);
114: }
115: }
116:
117: @Override
118: public int read(byte[] buffer, int offset, int nbytes)
119: throws IOException {
120: synchronized (this ) {
121: if (handle == -1) {
122: return -1;
123: }
124: if ((nbytes < 0 || nbytes > buffer.length)
125: || (offset < 0 || offset > buffer.length)
126: || ((nbytes + offset) > buffer.length)) {
127: throw new ArrayIndexOutOfBoundsException();
128: }
129: return readImpl(buffer, offset, nbytes, handle);
130: }
131: }
132: }
|