/** * Copyright 2014 Ricardo Padilha * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package net.dsys.snio.impl.channel; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.GatheringByteChannel; import java.nio.channels.Pipe; import java.nio.channels.Pipe.SinkChannel; import java.nio.channels.Pipe.SourceChannel; import java.nio.channels.ScatteringByteChannel; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.spi.SelectorProvider; /** * This class encapsulates opposite endpoints of two different * {@link Pipe}s, to simulate a {@link SelectableChannel} without * network overhead. * * @author Ricardo Padilha */ final class PipeSelectableChannel extends SelectableChannel implements ScatteringByteChannel, GatheringByteChannel { // These two belong to symmetrical pipes private final SinkChannel out; private final SourceChannel in; PipeSelectableChannel(final SinkChannel out, final SourceChannel in) { if (out == null) { throw new NullPointerException("out == null"); } if (in == null) { throw new NullPointerException("in == null"); } if ((in.validOps() & out.validOps()) != 0) { throw new IllegalArgumentException("sink and source have overlapping validOps"); } this.out = out; this.in = in; } /** * {@inheritDoc} */ @Override public SelectorProvider provider() { return out.provider(); } /** * {@inheritDoc} */ @Override public int validOps() { return in.validOps() | out.validOps(); } /** * {@inheritDoc} */ @Override public boolean isRegistered() { return in.isRegistered() || out.isRegistered(); } /** * {@inheritDoc} */ @Override public SelectionKey keyFor(final Selector sel) { final SelectionKey kout = out.keyFor(sel); final SelectionKey kin = in.keyFor(sel); if (kout != null && kin != null) { throw new IllegalStateException("sink and source registered with the same selector"); } if (kout != null) { return kout; } return kin; } /** * {@inheritDoc} */ @Override public SelectionKey register(final Selector sel, final int ops, final Object att) throws ClosedChannelException { if ((in.validOps() & ops) != 0) { if (out.keyFor(sel) != null) { throw new IllegalArgumentException("cannot register with selector - sink is already registered"); } return in.register(sel, ops, att); } if ((out.validOps() & ops) != 0) { if (in.keyFor(sel) != null) { throw new IllegalArgumentException("cannot register with selector - source is already registered"); } return out.register(sel, ops, att); } throw new IllegalArgumentException("unsupported ops: " + ops); } /** * {@inheritDoc} */ @Override public SelectableChannel configureBlocking(final boolean block) throws IOException { in.configureBlocking(block); out.configureBlocking(block); return this; } /** * {@inheritDoc} */ @Override public boolean isBlocking() { return in.isBlocking() && out.isBlocking(); } /** * {@inheritDoc} */ @Override public Object blockingLock() { // XXX: what about in's blockingLock() ? return out.blockingLock(); } /** * {@inheritDoc} */ @Override protected void implCloseChannel() throws IOException { in.close(); out.close(); } /** * {@inheritDoc} */ @Override public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { return in.read(dsts, offset, length); } /** * {@inheritDoc} */ @Override public long read(final ByteBuffer[] dsts) throws IOException { return in.read(dsts); } /** * {@inheritDoc} */ @Override public int read(final ByteBuffer dst) throws IOException { return in.read(dst); } /** * {@inheritDoc} */ @Override public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException { return out.write(srcs, offset, length); } /** * {@inheritDoc} */ @Override public long write(final ByteBuffer[] srcs) throws IOException { return out.write(srcs); } /** * {@inheritDoc} */ @Override public int write(final ByteBuffer src) throws IOException { return out.write(src); } }