Home | History | Annotate | Download | only in internal
      1 /* Licensed to the Apache Software Foundation (ASF) under one or more
      2  * contributor license agreements.  See the NOTICE file distributed with
      3  * this work for additional information regarding copyright ownership.
      4  * The ASF licenses this file to You under the Apache License, Version 2.0
      5  * (the "License"); you may not use this file except in compliance with
      6  * the License.  You may obtain a copy of the License at
      7  *
      8  *     http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package org.apache.harmony.nio.internal;
     18 
     19 import java.io.Closeable;
     20 import java.io.FileDescriptor;
     21 import java.io.IOException;
     22 import java.nio.ByteBuffer;
     23 import java.nio.channels.Pipe;
     24 import java.nio.channels.spi.SelectorProvider;
     25 import libcore.io.IoUtils;
     26 import org.apache.harmony.luni.platform.FileDescriptorHandler;
     27 
     28 /*
     29  * Implements {@link java.nio.channels.Pipe}.
     30  */
     31 final class PipeImpl extends Pipe {
     32     private final PipeSinkChannel sink;
     33     private final PipeSourceChannel source;
     34 
     35     public PipeImpl() throws IOException {
     36         int[] fds = new int[2];
     37         IoUtils.pipe(fds);
     38         // Which fd is used for which channel is important. Unix pipes are only guaranteed to be
     39         // unidirectional, and indeed are only unidirectional on Linux. See IoUtils.pipe.
     40         this.sink = new PipeSinkChannel(fds[1]);
     41         this.source = new PipeSourceChannel(fds[0]);
     42     }
     43 
     44     @Override public SinkChannel sink() {
     45         return sink;
     46     }
     47 
     48     @Override public SourceChannel source() {
     49         return source;
     50     }
     51 
     52     /**
     53      * FileChannelImpl doesn't close its fd itself; it calls close on the object it's given.
     54      */
     55     private static class FdCloser implements Closeable {
     56         private final FileDescriptor fd;
     57         private FdCloser(FileDescriptor fd) {
     58             this.fd = fd;
     59         }
     60         public void close() throws IOException {
     61             IoUtils.close(fd);
     62         }
     63     }
     64 
     65     private class PipeSourceChannel extends Pipe.SourceChannel implements FileDescriptorHandler {
     66         private final FileDescriptor fd;
     67         private final FileChannelImpl channel;
     68 
     69         private PipeSourceChannel(int fd) throws IOException {
     70             super(SelectorProvider.provider());
     71             this.fd = IoUtils.newFileDescriptor(fd);
     72             this.channel = new ReadOnlyFileChannel(new FdCloser(this.fd), fd);
     73         }
     74 
     75         @Override protected void implCloseSelectableChannel() throws IOException {
     76             channel.close();
     77         }
     78 
     79         @Override protected void implConfigureBlocking(boolean blocking) throws IOException {
     80             IoUtils.setBlocking(getFD(), blocking);
     81         }
     82 
     83         public int read(ByteBuffer buffer) throws IOException {
     84             return channel.read(buffer);
     85         }
     86 
     87         public long read(ByteBuffer[] buffers) throws IOException {
     88             return channel.read(buffers);
     89         }
     90 
     91         public long read(ByteBuffer[] buffers, int offset, int length) throws IOException {
     92             return channel.read(buffers, offset, length);
     93         }
     94 
     95         public FileDescriptor getFD() {
     96             return fd;
     97         }
     98     }
     99 
    100     private class PipeSinkChannel extends Pipe.SinkChannel implements FileDescriptorHandler {
    101         private final FileDescriptor fd;
    102         private final FileChannelImpl channel;
    103 
    104         private PipeSinkChannel(int fd) throws IOException {
    105             super(SelectorProvider.provider());
    106             this.fd = IoUtils.newFileDescriptor(fd);
    107             this.channel = new WriteOnlyFileChannel(new FdCloser(this.fd), fd);
    108         }
    109 
    110         @Override protected void implCloseSelectableChannel() throws IOException {
    111             channel.close();
    112         }
    113 
    114         @Override protected void implConfigureBlocking(boolean blocking) throws IOException {
    115             IoUtils.setBlocking(getFD(), blocking);
    116         }
    117 
    118         public int write(ByteBuffer buffer) throws IOException {
    119             return channel.write(buffer);
    120         }
    121 
    122         public long write(ByteBuffer[] buffers) throws IOException {
    123             return channel.write(buffers);
    124         }
    125 
    126         public long write(ByteBuffer[] buffers, int offset, int length) throws IOException {
    127             return channel.write(buffers, offset, length);
    128         }
    129 
    130         public FileDescriptor getFD() {
    131             return fd;
    132         }
    133     }
    134 }
    135