pax_global_header00006660000000000000000000000064125701606070014516gustar00rootroot0000000000000052 comment=351c62bab19eaeb09655486fe4e1f0d7099825ff xnio-3.3.2.Final/000077500000000000000000000000001257016060700135305ustar00rootroot00000000000000xnio-3.3.2.Final/.gitignore000066400000000000000000000000761257016060700155230ustar00rootroot00000000000000.project .classpath .settings *.iml target .idea *.ipr *~ out xnio-3.3.2.Final/LICENSE.txt000066400000000000000000000261361257016060700153630ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] 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. xnio-3.3.2.Final/api/000077500000000000000000000000001257016060700143015ustar00rootroot00000000000000xnio-3.3.2.Final/api/pom.xml000066400000000000000000000154051257016060700156230ustar00rootroot00000000000000 4.0.0 xnio-api jar XNIO API The API JAR of the XNIO project http://www.jboss.org/xnio false org.jboss.xnio xnio-all 3.3.2.Final org.jboss.logging jboss-logging provided org.jboss.logmanager jboss-logmanager test org.jboss.logging jboss-logging-processor provided org.jboss.logging jboss-logging-annotations provided junit junit test org.jmock jmock test org.jmock jmock-junit4 test org.jboss.byteman byteman test org.jboss.byteman byteman-bmunit test testng org.testng org.jboss.byteman byteman-install test ${project.basedir}/src/main/resources true org.jboss.bridger bridger ${version.bridger.plugin} weave process-classes transform maven-jar-plugin java/** org.xnio.Version ${project.version} ${project.artifactId} maven-surefire-plugin ${version.surefire.plugin} java.util.logging.manager org.jboss.logmanager.LogManager **/*TestCase.java true true maven-javadoc-plugin false false net.gleamynode.apiviz.APIviz org.jboss.apiviz apiviz 1.3.2.GA ${project.version}
${project.version}
${project.version}
Copyright © 2014 JBoss, a division of Red Hat, Inc.]]> http://java.sun.com/javase/7/docs/api/
xnio-3.3.2.Final/api/src/000077500000000000000000000000001257016060700150705ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/000077500000000000000000000000001257016060700160145ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/java/000077500000000000000000000000001257016060700167355ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/java/java/000077500000000000000000000000001257016060700176565ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/java/java/nio/000077500000000000000000000000001257016060700204435ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/java/java/nio/channels/000077500000000000000000000000001257016060700222365ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/java/java/nio/channels/FileChannel.java000066400000000000000000000060001257016060700252450ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 java.nio.channels; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.spi.AbstractInterruptibleChannel; import java.nio.file.OpenOption; import java.nio.file.Path; /** * Compatibility stub. */ public abstract class FileChannel extends AbstractInterruptibleChannel implements GatheringByteChannel, ScatteringByteChannel { protected FileChannel() {} public static FileChannel open(Path path, OpenOption... options) throws IOException {return null;}; public abstract int read(ByteBuffer dst) throws IOException; public abstract long read(ByteBuffer[] dsts, int offset, int length) throws IOException; public final long read(ByteBuffer[] dsts) throws IOException { return 0L; } public abstract int write(ByteBuffer src) throws IOException; public abstract long write(ByteBuffer[] srcs, int offset, int length) throws IOException; public final long write(ByteBuffer[] srcs) throws IOException { return 0L; } public abstract long position() throws IOException; public abstract FileChannel position(long newPosition) throws IOException; public abstract long size() throws IOException; public abstract FileChannel truncate(long size) throws IOException; public abstract void force(boolean metaData) throws IOException; public abstract long transferTo(long position, long count, WritableByteChannel target) throws IOException; public abstract long transferFrom(ReadableByteChannel src, long position, long count) throws IOException; public abstract int read(ByteBuffer dst, long position) throws IOException; public abstract int write(ByteBuffer src, long position) throws IOException; public abstract MappedByteBuffer map(MapMode mode, long position, long size) throws IOException; public abstract FileLock lock(long position, long size, boolean shared) throws IOException; public final FileLock lock() throws IOException { return null; }; public abstract FileLock tryLock(long position, long size, boolean shared) throws IOException; public final FileLock tryLock() throws IOException { return null; } public static class MapMode { public static final MapMode READ_ONLY = null; public static final MapMode READ_WRITE = null; public static final MapMode PRIVATE = null; } } xnio-3.3.2.Final/api/src/main/java/org/000077500000000000000000000000001257016060700175245ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/java/org/xnio/000077500000000000000000000000001257016060700205015ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/java/org/xnio/AbstractConvertingIoFuture.java000066400000000000000000000054241257016060700266360ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.util.concurrent.TimeUnit; import java.io.IOException; /** * An {@code IoFuture} implementation that wraps a different type of {@code IoFuture}. Used to create general wrappers * that convert one channel type to another. * * @param the type of this future result * @param the type of the delegate result */ public abstract class AbstractConvertingIoFuture implements IoFuture { /** * The delegate future result. */ protected final IoFuture delegate; protected AbstractConvertingIoFuture(final IoFuture delegate) { this.delegate = delegate; } protected IoFuture getDelegate() { return delegate; } public IoFuture cancel() { delegate.cancel(); return this; } public Status getStatus() { return delegate.getStatus(); } public Status await() { return delegate.await(); } public Status await(final long time, final TimeUnit timeUnit) { return delegate.await(time, timeUnit); } public Status awaitInterruptibly() throws InterruptedException { return delegate.awaitInterruptibly(); } public Status awaitInterruptibly(final long time, final TimeUnit timeUnit) throws InterruptedException { return delegate.awaitInterruptibly(time, timeUnit); } public IOException getException() throws IllegalStateException { return delegate.getException(); } public T get() throws IOException { return convert(delegate.get()); } public T getInterruptibly() throws IOException, InterruptedException { return convert(delegate.getInterruptibly()); } abstract protected T convert(D arg) throws IOException; public IoFuture addNotifier(final Notifier notifier, A attachment) { delegate.addNotifier(new Notifier() { public void notify(final IoFuture future, A attachment) { notifier.notify(AbstractConvertingIoFuture.this, attachment); } }, attachment); return this; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/AbstractIoFuture.java000066400000000000000000000266711257016060700246060ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.io.IOException; import java.util.ArrayList; import java.util.List; import java.util.Collections; import java.util.concurrent.TimeUnit; import java.util.concurrent.CancellationException; import java.util.concurrent.Executor; import static org.xnio._private.Messages.futureMsg; /** * An abstract base class for {@code IoFuture} objects. Used to easily produce implementations. * * @param the type of result that this operation produces */ public abstract class AbstractIoFuture implements IoFuture { private final Object lock = new Object(); private Status status = Status.WAITING; private Object result; private List notifierList; private List cancellables; private static final List CANCEL_REQUESTED = Collections.emptyList(); /** * Construct a new instance. */ protected AbstractIoFuture() { } /** * {@inheritDoc} */ public Status getStatus() { synchronized (lock) { return status; } } /** * {@inheritDoc} */ public Status await() { synchronized (lock) { boolean intr = Thread.interrupted(); try { if (status == Status.WAITING) { Xnio.checkBlockingAllowed(); do { try { lock.wait(); } catch (InterruptedException e) { intr = true; } } while (status == Status.WAITING); } } finally { if (intr) { Thread.currentThread().interrupt(); } } return status; } } /** * {@inheritDoc} */ public Status await(long time, final TimeUnit timeUnit) { if (time < 0L) { time = 0L; } long duration = timeUnit.toNanos(time); long now = System.nanoTime(); long waitTime; Status status; synchronized (lock) { boolean intr = Thread.interrupted(); try { if ((status = this.status) == Status.WAITING && (waitTime = duration / 1000000L) > 0L) { Xnio.checkBlockingAllowed(); do { try { lock.wait(waitTime); } catch (InterruptedException e) { intr = true; } finally { // decrease duration by the elapsed time duration += now - (now = System.nanoTime()); } } while ((status = this.status) == Status.WAITING && (waitTime = duration / 1000000L) > 0L); } } finally { if (intr) { Thread.currentThread().interrupt(); } } return status; } } /** * {@inheritDoc} */ public Status awaitInterruptibly() throws InterruptedException { synchronized (lock) { if (status == Status.WAITING) { Xnio.checkBlockingAllowed(); do { lock.wait(); } while (status == Status.WAITING); } return status; } } /** * {@inheritDoc} */ public Status awaitInterruptibly(long time, final TimeUnit timeUnit) throws InterruptedException { if (time < 0L) { time = 0L; } long duration = timeUnit.toNanos(time); long now = System.nanoTime(); long waitTime; Status status; synchronized (lock) { if ((status = this.status) == Status.WAITING && (waitTime = duration / 1000000L) > 0L) { Xnio.checkBlockingAllowed(); do { lock.wait(waitTime); // decrease duration by the elapsed time duration += now - (now = System.nanoTime()); } while ((status = this.status) == Status.WAITING && (waitTime = duration / 1000000L) > 0L); } return status; } } /** * {@inheritDoc} */ @SuppressWarnings({"unchecked"}) public T get() throws IOException, CancellationException { synchronized (lock) { switch (await()) { case DONE: return (T) result; case FAILED: throw (IOException) result; case CANCELLED: throw futureMsg.opCancelled(); default: throw new IllegalStateException(); } } } /** * {@inheritDoc} */ @SuppressWarnings({"unchecked"}) public T getInterruptibly() throws IOException, InterruptedException, CancellationException { synchronized (lock) { switch (awaitInterruptibly()) { case DONE: return (T) result; case FAILED: throw (IOException) result; case CANCELLED: throw futureMsg.opCancelled(); default: throw new IllegalStateException(); } } } /** * {@inheritDoc} */ public IOException getException() throws IllegalStateException { synchronized (lock) { if (status == Status.FAILED) { return (IOException) result; } else { throw new IllegalStateException(); } } } /** * {@inheritDoc} */ public IoFuture addNotifier(final Notifier notifier, final A attachment) { final Runnable runnable = new Runnable() { public void run() { try { notifier.notify(AbstractIoFuture.this, attachment); } catch (Throwable t) { futureMsg.notifierFailed(t, notifier); } } }; synchronized (lock) { if (status == Status.WAITING) { if (notifierList == null) { notifierList = new ArrayList(); } notifierList.add(runnable); return this; } } runNotifier(runnable); return this; } private void runAllNotifiers() { if (notifierList != null) { for (final Runnable runnable : notifierList) { runNotifier(runnable); } notifierList = null; } } /** * Set the exception for this operation. Any threads blocking on this instance will be unblocked. * * @param exception the exception to set * @return {@code false} if the operation was already completed, {@code true} otherwise */ protected boolean setException(IOException exception) { synchronized (lock) { if (status == Status.WAITING) { status = Status.FAILED; result = exception; cancellables = null; runAllNotifiers(); lock.notifyAll(); return true; } else { return false; } } } /** * Set the result for this operation. Any threads blocking on this instance will be unblocked. * * @param result the result to set * @return {@code false} if the operation was already completed, {@code true} otherwise */ protected boolean setResult(T result) { synchronized (lock) { if (status == Status.WAITING) { status = Status.DONE; this.result = result; cancellables = null; runAllNotifiers(); lock.notifyAll(); return true; } else { return false; } } } /** * Acknowledge the cancellation of this operation. * * @return {@code false} if the operation was already completed, {@code true} otherwise */ protected boolean setCancelled() { synchronized (lock) { if (status == Status.WAITING) { status = Status.CANCELLED; cancellables = null; runAllNotifiers(); lock.notifyAll(); return true; } else { return false; } } } /** * Cancel an operation. The actual cancel may be synchronous or asynchronous. Implementers will use this method * to initiate the cancel; use the {@link #setCancelled()} method to indicate that the cancel was successful. The * default implementation calls any registered cancel handlers. * * @return this {@code IoFuture} instance */ public IoFuture cancel() { final List cancellables; synchronized (lock) { cancellables = this.cancellables; if (cancellables == null || cancellables == CANCEL_REQUESTED) { return this; } this.cancellables = CANCEL_REQUESTED; } for (Cancellable cancellable : cancellables) { cancellable.cancel(); } return this; } /** * Add a cancellation handler. The argument will be cancelled whenever this {@code IoFuture} is cancelled. If * the {@code IoFuture} is already cancelled when this method is called, the handler will be called directly. * * @param cancellable the cancel handler */ protected void addCancelHandler(final Cancellable cancellable) { synchronized (lock) { switch (status) { case CANCELLED: break; case WAITING: final List cancellables = this.cancellables; if (cancellables == CANCEL_REQUESTED) { break; } else { ((cancellables == null) ? (this.cancellables = new ArrayList()) : cancellables).add(cancellable); } default: return; } } cancellable.cancel(); } /** * Run a notifier. Implementors will run the notifier, preferably in another thread. The default implementation * runs the notifier using the {@code Executor} retrieved via {@link #getNotifierExecutor()}. * * @param runnable */ protected void runNotifier(final Runnable runnable) { getNotifierExecutor().execute(runnable); } /** * Get the executor used to run asynchronous notifiers. By default, this implementation simply returns the direct * executor. * * @return the executor to use */ protected Executor getNotifierExecutor() { return IoUtils.directExecutor(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/AutomaticReference.java000066400000000000000000000115611257016060700251150ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import static java.security.AccessController.doPrivileged; import java.lang.ref.PhantomReference; import java.lang.ref.ReferenceQueue; import java.security.PrivilegedAction; import java.util.Collections; import java.util.IdentityHashMap; import java.util.Set; /** * An automatic reference is a phantom reference which is automatically freed by a background thread when it is * enqueued. Since this type of garbage collection imposes considerable overhead, it should only be used sparingly, * when it is impossible to achieve correctness any other way. * * @author David M. Lloyd */ public abstract class AutomaticReference extends PhantomReference { static final Object PERMIT = new Object(); // todo: we can do better than this... private static final Set> LIVE_SET = Collections.synchronizedSet(Collections.newSetFromMap(new IdentityHashMap, Boolean>())); /** * Get the security authorization permit to create automatic references. * * @return the permit * @throws SecurityException if a security manager is enabled and the caller does not have the {@code createAutomaticReference} {@link RuntimePermission} */ public static Object getPermit() { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(new RuntimePermission("createAutomaticReference")); } return PERMIT; } private static ReferenceQueue checkPermit(Object permit) { if (permit == PERMIT) { // only initialize the cleaner on the first valid permit return Cleaner.QUEUE; } else { throw new SecurityException("Unauthorized subclass of " + AutomaticReference.class); } } /** * Always returns {@code null}. * * @return {@code null} */ public final T get() { return null; } /** * Not supported. * * @throws UnsupportedOperationException always */ public final void clear() { throw new UnsupportedOperationException(); } /** * Determine whether this reference has been enqueued by the garbage collector. * * @return {@code true} if the reference has been enqueued, {@code false} otherwise */ public final boolean isEnqueued() { return super.isEnqueued(); } /** * Not supported. * * @return nothing * @throws UnsupportedOperationException always */ public final boolean enqueue() { throw new UnsupportedOperationException(); } /** * Construct a new instance. In order to maximize performance, the only security check performed by * this constructor is to verify the {@code permit} which was passed in. * * @param referent the object to monitor * @param permit the permit object originally acquired from {@link #getPermit()} */ protected AutomaticReference(final T referent, final Object permit) { super(referent, checkPermit(permit)); LIVE_SET.add(this); } /** * Free this reference. This method will be called from a dedicated thread or threads so this method * should execute as quickly as possible. */ protected abstract void free(); static class Cleaner implements Runnable { private static final ReferenceQueue QUEUE; static { QUEUE = new ReferenceQueue<>(); doPrivileged(new PrivilegedAction() { public Void run() { final Thread thr = new Thread(new Cleaner(), "XNIO cleaner thread"); thr.setDaemon(true); thr.setContextClassLoader(null); thr.start(); return null; } }); } public void run() { AutomaticReference ref; for (;;) try { ref = (AutomaticReference) QUEUE.remove(); try { ref.free(); } finally { LIVE_SET.remove(ref); } } catch (Throwable ignored) { } } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/Bits.java000066400000000000000000000226141257016060700222520ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; /** * General bit-affecting utility methods. * * @author David M. Lloyd */ public final class Bits { private Bits() {} //--- Bit mask methods /** * Get an integer bit mask consisting of 1 bits in the given range. The returned {@code int} * will have bits {@code low} through {@code high} set, and all other bits clear. * * @param low the low bit value * @param high the high bit value * @return the bit mask */ public static int intBitMask(int low, int high) { assert low >= 0; assert low <= high; assert high < 32; return (high == 31 ? 0 : (1 << high + 1)) - (1 << low); } /** * Get a long bit mask consisting of 1 bits in the given range. The returned {@code long} * will have bits {@code low} through {@code high} set, and all other bits clear. * * @param low the low bit value * @param high the high bit value * @return the bit mask */ public static long longBitMask(int low, int high) { assert low >= 0; assert low <= high; assert high < 64; return (high == 63 ? 0L : (1L << (long) high + 1L)) - (1L << (long) low); } //--- Flags methods /** * Determine if any of the {@code flags} in the given {@code var} are set. * * @param var the value to test * @param flags the flags to test for * @return {@code true} if any of {@code flags} are in {@code var}, {@code false} otherwise */ public static boolean anyAreSet(int var, int flags) { return (var & flags) != 0; } /** * Determine if all of the {@code flags} in the given {@code var} are set. * * @param var the value to test * @param flags the flags to test for * @return {@code true} if all of {@code flags} are in {@code var}, {@code false} otherwise */ public static boolean allAreSet(int var, int flags) { return (var & flags) == flags; } /** * Determine if any of the {@code flags} in the given {@code var} are clear. * * @param var the value to test * @param flags the flags to test for * @return {@code true} if not all of {@code flags} are in {@code var}, {@code false} otherwise */ public static boolean anyAreClear(int var, int flags) { return (var & flags) != flags; } /** * Determine if all of the {@code flags} in the given {@code var} are clear. * * @param var the value to test * @param flags the flags to test for * @return {@code true} if none of {@code flags} are in {@code var}, {@code false} otherwise */ public static boolean allAreClear(int var, int flags) { return (var & flags) == 0; } /** * Determine if any of the {@code flags} in the given {@code var} are set. * * @param var the value to test * @param flags the flags to test for * @return {@code true} if any of {@code flags} are in {@code var}, {@code false} otherwise */ public static boolean anyAreSet(long var, long flags) { return (var & flags) != 0; } /** * Determine if all of the {@code flags} in the given {@code var} are set. * * @param var the value to test * @param flags the flags to test for * @return {@code true} if all of {@code flags} are in {@code var}, {@code false} otherwise */ public static boolean allAreSet(long var, long flags) { return (var & flags) == flags; } /** * Determine if any of the {@code flags} in the given {@code var} are clear. * * @param var the value to test * @param flags the flags to test for * @return {@code true} if not all of {@code flags} are in {@code var}, {@code false} otherwise */ public static boolean anyAreClear(long var, long flags) { return (var & flags) != flags; } /** * Determine if all of the {@code flags} in the given {@code var} are clear. * * @param var the value to test * @param flags the flags to test for * @return {@code true} if none of {@code flags} are in {@code var}, {@code false} otherwise */ public static boolean allAreClear(long var, long flags) { return (var & flags) == 0; } //--- Signed/unsigned methods /** * Convert a signed value to unsigned. * * @param v the signed byte * @return the unsigned byte, as an int */ public static int unsigned(byte v) { return v & 0xff; } /** * Convert a signed value to unsigned. * * @param v the signed short * @return the unsigned short, as an int */ public static int unsigned(short v) { return v & 0xffff; } /** * Convert a signed value to unsigned. * * @param v the signed int * @return the unsigned int, as a long */ public static long unsigned(int v) { return v & 0xffffffffL; } //--- Byte array read methods /** * Get a 16-bit signed little-endian short value from a byte array. * * @param b the byte array * @param off the offset in the array * @return the signed short value */ public static short shortFromBytesLE(byte[] b, int off) { return (short) (b[off + 1] << 8 | b[off] & 0xff); } /** * Get a 16-bit signed big-endian short value from a byte array. * * @param b the byte array * @param off the offset in the array * @return the signed short value */ public static short shortFromBytesBE(byte[] b, int off) { return (short) (b[off] << 8 | b[off + 1] & 0xff); } /** * Get a 16-bit signed little-endian char value from a byte array. * * @param b the byte array * @param off the offset in the array * @return the signed char value */ public static char charFromBytesLE(byte[] b, int off) { return (char) (b[off + 1] << 8 | b[off] & 0xff); } /** * Get a 16-bit signed big-endian char value from a byte array. * * @param b the byte array * @param off the offset in the array * @return the signed char value */ public static char charFromBytesBE(byte[] b, int off) { return (char) (b[off] << 8 | b[off + 1] & 0xff); } /** * Get a 24-bit signed little-endian int value from a byte array. * * @param b the byte array * @param off the offset in the array * @return the signed medium value as an int */ public static int mediumFromBytesLE(byte[] b, int off) { return (b[off + 2] & 0xff) << 16 | (b[off + 1] & 0xff) << 8 | b[off] & 0xff; } /** * Get a 24-bit signed big-endian int value from a byte array. * * @param b the byte array * @param off the offset in the array * @return the signed medium value as an int */ public static int mediumFromBytesBE(byte[] b, int off) { return (b[off] & 0xff) << 16 | (b[off + 1] & 0xff) << 8 | b[off + 2] & 0xff; } /** * Get a 32-bit signed little-endian int value from a byte array. * * @param b the byte array * @param off the offset in the array * @return the signed int value */ public static int intFromBytesLE(byte[] b, int off) { return b[off + 3] << 24 | (b[off + 2] & 0xff) << 16 | (b[off + 1] & 0xff) << 8 | b[off] & 0xff; } /** * Get a 32-bit signed big-endian int value from a byte array. * * @param b the byte array * @param off the offset in the array * @return the signed int value */ public static int intFromBytesBE(byte[] b, int off) { return b[off] << 24 | (b[off + 1] & 0xff) << 16 | (b[off + 2] & 0xff) << 8 | b[off + 3] & 0xff; } /** * Get a 64-bit signed little-endian long value from a byte array. * * @param b the byte array * @param off the offset in the array * @return the signed long value */ public static long longFromBytesLE(byte[] b, int off) { return (b[off + 7] & 0xffL) << 56L | (b[off + 6] & 0xffL) << 48L | (b[off + 5] & 0xffL) << 40L | (b[off + 4] & 0xffL) << 32L | (b[off + 3] & 0xffL) << 24L | (b[off + 2] & 0xffL) << 16L | (b[off + 1] & 0xffL) << 8L | b[off] & 0xffL; } /** * Get a 64-bit signed big-endian long value from a byte array. * * @param b the byte array * @param off the offset in the array * @return the signed long value */ public static long longFromBytesBE(byte[] b, int off) { return (b[off] & 0xffL) << 56L | (b[off + 1] & 0xffL) << 48L | (b[off + 2] & 0xffL) << 40L | (b[off + 3] & 0xffL) << 32L | (b[off + 4] & 0xffL) << 24L | (b[off + 5] & 0xffL) << 16L | (b[off + 6] & 0xffL) << 8L | b[off + 7] & 0xffL; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/BrokenPipeException.java000066400000000000000000000046541257016060700252720ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import java.io.IOException; /** * An exception that signifies that a pipe, stream, or channel was closed from the read side while the write side was * still writing. * * @author David M. Lloyd */ public class BrokenPipeException extends IOException { /** * Constructs a {@code BrokenPipeException} with no detail message. The cause is not initialized, and may * subsequently be initialized by a call to {@link #initCause(Throwable) initCause}. */ public BrokenPipeException() { } /** * Constructs a {@code BrokenPipeException} with the specified detail message. The cause is not initialized, and may * subsequently be initialized by a call to {@link #initCause(Throwable) initCause}. * * @param msg the detail message */ public BrokenPipeException(final String msg) { super(msg); } /** * Constructs a {@code BrokenPipeException} with the specified cause. The detail message is set to: *
(cause == null ? null : cause.toString())
* (which typically contains the class and detail message of {@code cause}). * * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) */ public BrokenPipeException(final Throwable cause) { super(cause); } /** * Constructs a {@code BrokenPipeException} with the specified detail message and cause. * * @param msg the detail message * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) */ public BrokenPipeException(final String msg, final Throwable cause) { super(msg, cause); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/BufferAllocator.java000066400000000000000000000034671257016060700244300ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import java.nio.Buffer; import java.nio.ByteBuffer; /** * A simple allocator for buffers. * * @param the buffer type * * @author David M. Lloyd */ public interface BufferAllocator { /** * Allocate a buffer of the given size. * * @param size the size * @return the buffer * @throws IllegalArgumentException if the given buffer size is less than zero */ B allocate(int size) throws IllegalArgumentException; /** * A simple allocator for heap-array-backed byte buffers. */ BufferAllocator BYTE_BUFFER_ALLOCATOR = new BufferAllocator() { public ByteBuffer allocate(final int size) { return ByteBuffer.allocate(size); } }; /** * A simple allocator for direct byte buffers. */ BufferAllocator DIRECT_BYTE_BUFFER_ALLOCATOR = new BufferAllocator() { public ByteBuffer allocate(final int size) { return ByteBuffer.allocateDirect(size); } }; } xnio-3.3.2.Final/api/src/main/java/org/xnio/Buffers.java000066400000000000000000002463031257016060700227500ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.io.DataInput; import java.io.DataOutput; import java.io.InputStream; import java.io.InterruptedIOException; import java.io.OutputStream; import java.nio.Buffer; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.IntBuffer; import java.nio.LongBuffer; import java.nio.ReadOnlyBufferException; import java.nio.ShortBuffer; import java.nio.BufferOverflowException; import java.nio.charset.CharsetDecoder; import java.nio.charset.CoderResult; import java.util.Arrays; import java.io.IOException; import java.util.Random; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import static org.xnio._private.Messages.msg; /** * Buffer utility methods. * * @apiviz.exclude */ public final class Buffers { private Buffers() {} /** * Flip a buffer. * * @see Buffer#flip() * @param the buffer type * @param buffer the buffer to flip * @return the buffer instance */ public static T flip(T buffer) { buffer.flip(); return buffer; } /** * Clear a buffer. * * @see Buffer#clear() * @param the buffer type * @param buffer the buffer to clear * @return the buffer instance */ public static T clear(T buffer) { buffer.clear(); return buffer; } /** * Set the buffer limit. * * @see Buffer#limit(int) * @param the buffer type * @param buffer the buffer to set * @param limit the new limit * @return the buffer instance */ public static T limit(T buffer, int limit) { buffer.limit(limit); return buffer; } /** * Set the buffer mark. * * @see Buffer#mark() * @param the buffer type * @param buffer the buffer to mark * @return the buffer instance */ public static T mark(T buffer) { buffer.mark(); return buffer; } /** * Set the buffer position. * * @see Buffer#position(int) * @param the buffer type * @param buffer the buffer to set * @param position the new position * @return the buffer instance */ public static T position(T buffer, int position) { buffer.position(position); return buffer; } /** * Reset the buffer. * * @see Buffer#reset() * @param the buffer type * @param buffer the buffer to reset * @return the buffer instance */ public static T reset(T buffer) { buffer.reset(); return buffer; } /** * Rewind the buffer. * * @see Buffer#rewind() * @param the buffer type * @param buffer the buffer to rewind * @return the buffer instance */ public static T rewind(T buffer) { buffer.rewind(); return buffer; } /** * Slice the buffer. The original buffer's position will be moved up past the slice that was taken. * * @see ByteBuffer#slice() * @param buffer the buffer to slice * @param sliceSize the size of the slice * @return the buffer slice */ public static ByteBuffer slice(ByteBuffer buffer, int sliceSize) { final int oldRem = buffer.remaining(); if (sliceSize > oldRem || sliceSize < -oldRem) { throw msg.bufferUnderflow(); } final int oldPos = buffer.position(); final int oldLim = buffer.limit(); if (sliceSize < 0) { // count from end (sliceSize is NEGATIVE) buffer.limit(oldLim + sliceSize); try { return buffer.slice(); } finally { buffer.limit(oldLim); buffer.position(oldLim + sliceSize); } } else { // count from start buffer.limit(oldPos + sliceSize); try { return buffer.slice(); } finally { buffer.limit(oldLim); buffer.position(oldPos + sliceSize); } } } /** * Copy a portion of the buffer into a newly allocated buffer. The original buffer's position will be moved up past the copy that was taken. * * @param buffer the buffer to slice * @param count the size of the copy * @param allocator the buffer allocator to use * @return the buffer slice */ public static ByteBuffer copy(ByteBuffer buffer, int count, BufferAllocator allocator) { final int oldRem = buffer.remaining(); if (count > oldRem || count < -oldRem) { throw msg.bufferUnderflow(); } final int oldPos = buffer.position(); final int oldLim = buffer.limit(); if (count < 0) { // count from end (sliceSize is NEGATIVE) final ByteBuffer target = allocator.allocate(-count); buffer.position(oldLim + count); try { target.put(buffer); return target; } finally { buffer.limit(oldLim); buffer.position(oldLim + count); } } else { // count from start final ByteBuffer target = allocator.allocate(count); buffer.limit(oldPos + count); try { target.put(buffer); return target; } finally { buffer.limit(oldLim); buffer.position(oldPos + count); } } } /** * Copy as many bytes as possible from {@code source} into {@code destination}. * * @param destination the destination buffer * @param source the source buffer * @return the number of bytes put into the destination buffer */ public static int copy(final ByteBuffer destination, final ByteBuffer source) { final int sr = source.remaining(); final int dr = destination.remaining(); if (dr >= sr) { destination.put(source); return sr; } else { destination.put(slice(source, dr)); return dr; } } /** * Copy as many bytes as possible from {@code sources} into {@code destinations} in a "scatter" fashion. * * @param destinations the destination buffers * @param offset the offset into the destination buffers array * @param length the number of buffers to update * @param source the source buffer * @return the number of bytes put into the destination buffers */ public static int copy(final ByteBuffer[] destinations, final int offset, final int length, final ByteBuffer source) { int t = 0; for (int i = 0; i < length; i ++) { final ByteBuffer buffer = destinations[i + offset]; final int rem = buffer.remaining(); if (rem == 0) { continue; } else if (rem < source.remaining()) { buffer.put(slice(source, rem)); t += rem; } else { t += source.remaining(); buffer.put(source); return t; } } return t; } /** * Copy as many bytes as possible from {@code sources} into {@code destination} in a "gather" fashion. * * @param destination the destination buffer * @param sources the source buffers * @param offset the offset into the source buffers array * @param length the number of buffers to read from * @return the number of bytes put into the destination buffers */ public static int copy(final ByteBuffer destination, final ByteBuffer[] sources, final int offset, final int length) { int t = 0; for (int i = 0; i < length; i ++) { final ByteBuffer buffer = sources[i + offset]; final int rem = buffer.remaining(); if (rem == 0) { continue; } else if (rem > destination.remaining()) { t += destination.remaining(); destination.put(slice(buffer, destination.remaining())); return t; } else { destination.put(buffer); t += rem; } } return t; } /** * Copy as many bytes as possible from {@code sources} into {@code destinations} by a combined "scatter"/"gather" operation. * * @param destinations the destination buffers * @param destOffset the offset into the destination buffers array * @param destLength the number of buffers to write to * @param sources the source buffers * @param srcOffset the offset into the source buffers array * @param srcLength the number of buffers to read from * @return the number of bytes put into the destination buffers */ public static long copy(final ByteBuffer[] destinations, final int destOffset, final int destLength, final ByteBuffer[] sources, final int srcOffset, final int srcLength) { long t = 0L; int s = 0, d = 0; if (destLength == 0 || srcLength == 0) { return 0L; } ByteBuffer source = sources[srcOffset]; ByteBuffer dest = destinations[destOffset]; while (s < srcLength && d < destLength) { source = sources[srcOffset + s]; dest = destinations[destOffset + d]; final int sr = source.remaining(); final int dr = dest.remaining(); if (sr < dr) { dest.put(source); s++; t += sr; } else if (sr > dr) { dest.put(slice(source, dr)); d++; t += dr; } else { dest.put(source); s++; d++; t += sr; } } return t; } /** * Copy at most {@code count} bytes from {@code source} into {@code destination}. * * @param count the maximum number of bytes to copy * @param destination the destination buffer * @param source the source buffer * @return the number of bytes put into the destination buffer */ public static int copy(int count, final ByteBuffer destination, final ByteBuffer source) { int cnt = count >= 0? Math.min(Math.min(count, source.remaining()), destination.remaining()): Math.max(Math.max(count, - source.remaining()), - destination.remaining()); final ByteBuffer copy = slice(source, cnt); destination.put(copy); return copy.position(); // cnt could be negative, so it is safer to return copy.position() instead of cnt } /** * Copy at most {@code count} bytes from {@code sources} into {@code destinations} in a "scatter" fashion. * * @param count the maximum number of bytes to copy * @param destinations the destination buffers * @param offset the offset into the destination buffers array * @param length the number of buffers to update * @param source the source buffer * @return the number of bytes put into the destination buffers */ public static int copy(int count, final ByteBuffer[] destinations, final int offset, final int length, final ByteBuffer source) { if (source.remaining() > count) { final int oldLimit = source.limit(); if (count < 0) { // count from end (count is NEGATIVE) throw msg.copyNegative(); } else { try { source.limit(source.position() + count); return copy(destinations, offset, length, source); } finally { source.limit(oldLimit); } } } else { return copy(destinations, offset, length, source); } } /** * Copy at most {@code count} bytes from {@code sources} into {@code destination} in a "gather" fashion. * * @param count the maximum number of bytes to copy * @param destination the destination buffer * @param sources the source buffers * @param offset the offset into the source buffers array * @param length the number of buffers to read from * @return the number of bytes put into the destination buffers */ public static int copy(int count, final ByteBuffer destination, final ByteBuffer[] sources, final int offset, final int length) { if (destination.remaining() > count) { if (count < 0) { // count from end (count is NEGATIVE) throw msg.copyNegative(); } else { final int oldLimit = destination.limit(); try { destination.limit(destination.position() + Math.min(count, destination.remaining())); return copy(destination, sources, offset, length); } finally { destination.limit(oldLimit); } } } else { return copy(destination, sources, offset, length); } } /** * Copy at most {@code count} bytes from {@code sources} into {@code destinations} by a combined "scatter"/"gather" operation. * * @param count the maximum number of bytes to copy * @param destinations the destination buffers * @param destOffset the offset into the destination buffers array * @param destLength the number of buffers to write to * @param sources the source buffers * @param srcOffset the offset into the source buffers array * @param srcLength the number of buffers to read from * @return the number of bytes put into the destination buffers */ public static long copy(long count, final ByteBuffer[] destinations, final int destOffset, final int destLength, final ByteBuffer[] sources, final int srcOffset, final int srcLength) { long t = 0L; int s = 0, d = 0; if (count < 0) { // count from end (count is NEGATIVE) throw msg.copyNegative(); } if (destLength == 0 || srcLength == 0 || count == 0L) { return 0L; } while (s < srcLength && d < destLength) { final ByteBuffer source = sources[srcOffset + s]; final ByteBuffer dest = destinations[destOffset + d]; final int sr = source.remaining(); final int dr = (int) Math.min(count, (long) dest.remaining()); if (sr < dr) { dest.put(source); s++; t += sr; count -= (long)sr; } else if (sr > dr) { dest.put(slice(source, dr)); d++; t += dr; count -= (long)dr; } else { dest.put(source); s++; d++; t += sr; count -= (long)sr; } } return t; } /** * Fill a buffer with a repeated value. * * @param buffer the buffer to fill * @param value the value to fill * @param count the number of bytes to fill * @return the buffer instance */ public static ByteBuffer fill(ByteBuffer buffer, int value, int count) { if (count > buffer.remaining()) { throw msg.bufferUnderflow(); } if (buffer.hasArray()) { final int offs = buffer.arrayOffset(); Arrays.fill(buffer.array(), offs + buffer.position(), offs + buffer.limit(), (byte) value); skip(buffer, count); } else { for (int i = count; i > 0; i--) { buffer.put((byte)value); } } return buffer; } /** * Slice the buffer. The original buffer's position will be moved up past the slice that was taken. * * @see CharBuffer#slice() * @param buffer the buffer to slice * @param sliceSize the size of the slice * @return the buffer slice */ public static CharBuffer slice(CharBuffer buffer, int sliceSize) { if (sliceSize > buffer.remaining() || sliceSize < -buffer.remaining()) { throw msg.bufferUnderflow(); } final int oldPos = buffer.position(); final int oldLim = buffer.limit(); if (sliceSize < 0) { // count from end (sliceSize is NEGATIVE) buffer.limit(oldLim + sliceSize); try { return buffer.slice(); } finally { buffer.limit(oldLim); buffer.position(oldLim + sliceSize); } } else { // count from start buffer.limit(oldPos + sliceSize); try { return buffer.slice(); } finally { buffer.limit(oldLim); buffer.position(oldPos + sliceSize); } } } /** * Fill a buffer with a repeated value. * * @param buffer the buffer to fill * @param value the value to fill * @param count the number of chars to fill * @return the buffer instance */ public static CharBuffer fill(CharBuffer buffer, int value, int count) { if (count > buffer.remaining()) { throw msg.bufferUnderflow(); } if (buffer.hasArray()) { final int offs = buffer.arrayOffset(); Arrays.fill(buffer.array(), offs + buffer.position(), offs + buffer.limit(), (char) value); skip(buffer, count); } else { for (int i = count; i > 0; i--) { buffer.put((char)value); } } return buffer; } /** * Slice the buffer. The original buffer's position will be moved up past the slice that was taken. * * @see ShortBuffer#slice() * @param buffer the buffer to slice * @param sliceSize the size of the slice * @return the buffer slice */ public static ShortBuffer slice(ShortBuffer buffer, int sliceSize) { if (sliceSize > buffer.remaining() || sliceSize < -buffer.remaining()) { throw msg.bufferUnderflow(); } final int oldPos = buffer.position(); final int oldLim = buffer.limit(); if (sliceSize < 0) { // count from end (sliceSize is NEGATIVE) buffer.limit(oldLim + sliceSize); try { return buffer.slice(); } finally { buffer.limit(oldLim); buffer.position(oldLim + sliceSize); } } else { // count from start buffer.limit(oldPos + sliceSize); try { return buffer.slice(); } finally { buffer.limit(oldLim); buffer.position(oldPos + sliceSize); } } } /** * Fill a buffer with a repeated value. * * @param buffer the buffer to fill * @param value the value to fill * @param count the number of shorts to fill * @return the buffer instance */ public static ShortBuffer fill(ShortBuffer buffer, int value, int count) { if (count > buffer.remaining()) { throw msg.bufferUnderflow(); } if (buffer.hasArray()) { final int offs = buffer.arrayOffset(); Arrays.fill(buffer.array(), offs + buffer.position(), offs + buffer.limit(), (short) value); skip(buffer, count); } else { for (int i = count; i > 0; i--) { buffer.put((short)value); } } return buffer; } /** * Slice the buffer. The original buffer's position will be moved up past the slice that was taken. * * @see IntBuffer#slice() * @param buffer the buffer to slice * @param sliceSize the size of the slice * @return the buffer slice */ public static IntBuffer slice(IntBuffer buffer, int sliceSize) { if (sliceSize > buffer.remaining() || sliceSize < -buffer.remaining()) { throw msg.bufferUnderflow(); } final int oldPos = buffer.position(); final int oldLim = buffer.limit(); if (sliceSize < 0) { // count from end (sliceSize is NEGATIVE) buffer.limit(oldLim + sliceSize); try { return buffer.slice(); } finally { buffer.limit(oldLim); buffer.position(oldLim + sliceSize); } } else { // count from start buffer.limit(oldPos + sliceSize); try { return buffer.slice(); } finally { buffer.limit(oldLim); buffer.position(oldPos + sliceSize); } } } /** * Fill a buffer with a repeated value. * * @param buffer the buffer to fill * @param value the value to fill * @param count the number of ints to fill * @return the buffer instance */ public static IntBuffer fill(IntBuffer buffer, int value, int count) { if (count > buffer.remaining()) { throw msg.bufferUnderflow(); } if (buffer.hasArray()) { final int offs = buffer.arrayOffset(); Arrays.fill(buffer.array(), offs + buffer.position(), offs + buffer.limit(), value); skip(buffer, count); } else { for (int i = count; i > 0; i--) { buffer.put(value); } } return buffer; } /** * Slice the buffer. The original buffer's position will be moved up past the slice that was taken. * * @see LongBuffer#slice() * @param buffer the buffer to slice * @param sliceSize the size of the slice * @return the buffer slice */ public static LongBuffer slice(LongBuffer buffer, int sliceSize) { if (sliceSize > buffer.remaining() || sliceSize < -buffer.remaining()) { throw msg.bufferUnderflow(); } final int oldPos = buffer.position(); final int oldLim = buffer.limit(); if (sliceSize < 0) { // count from end (sliceSize is NEGATIVE) buffer.limit(oldLim + sliceSize); try { return buffer.slice(); } finally { buffer.limit(oldLim); buffer.position(oldLim + sliceSize); } } else { // count from start buffer.limit(oldPos + sliceSize); try { return buffer.slice(); } finally { buffer.limit(oldLim); buffer.position(oldPos + sliceSize); } } } /** * Fill a buffer with a repeated value. * * @param buffer the buffer to fill * @param value the value to fill * @param count the number of longs to fill * @return the buffer instance */ public static LongBuffer fill(LongBuffer buffer, long value, int count) { if (count > buffer.remaining()) { throw msg.bufferUnderflow(); } if (buffer.hasArray()) { final int offs = buffer.arrayOffset(); Arrays.fill(buffer.array(), offs + buffer.position(), offs + buffer.limit(), value); skip(buffer, count); } else { for (int i = count; i > 0; i--) { buffer.put(value); } } return buffer; } /** * Advance a buffer's position relative to its current position. * * @see Buffer#position(int) * @param the buffer type * @param buffer the buffer to set * @param cnt the distance to skip * @return the buffer instance * @throws BufferUnderflowException if there are fewer than {@code cnt} bytes remaining */ public static T skip(T buffer, int cnt) throws BufferUnderflowException { if (cnt < 0) { throw msg.parameterOutOfRange("cnt"); } if (cnt > buffer.remaining()) { throw msg.bufferUnderflow(); } buffer.position(buffer.position() + cnt); return buffer; } /** * Attempt to advance a buffer's position relative to its current position. * * @see Buffer#position(int) * @param buffer the buffer to set * @param cnt the distance to skip * @return the actual number of bytes skipped */ public static int trySkip(Buffer buffer, int cnt) { if (cnt < 0) { throw msg.parameterOutOfRange("cnt"); } final int rem = buffer.remaining(); if (cnt > rem) { cnt = rem; } buffer.position(buffer.position() + cnt); return cnt; } /** * Attempt to advance a series of buffers' overall position relative to its current position. * * @see Buffer#position(int) * @param buffers the buffers to set * @param offs the offset into the buffers array * @param len the number of buffers to consider * @param cnt the distance to skip * @return the actual number of bytes skipped */ public static long trySkip(Buffer[] buffers, int offs, int len, long cnt) { if (cnt < 0L) { throw msg.parameterOutOfRange("cnt"); } if (len < 0) { throw msg.parameterOutOfRange("len"); } if (offs < 0) { throw msg.parameterOutOfRange("offs"); } if (offs > buffers.length) { throw msg.parameterOutOfRange("offs"); } if (offs + len > buffers.length) { throw msg.parameterOutOfRange("offs"); } long c = 0L; for (int i = 0; i < len; i ++) { final Buffer buffer = buffers[offs + i]; final int rem = buffer.remaining(); if (rem < cnt) { buffer.position(buffer.position() + rem); cnt -= (long) rem; c += (long) rem; } else { buffer.position(buffer.position() + (int) cnt); return c + cnt; } } return c; } /** * Rewind a buffer's position relative to its current position. * * @see Buffer#position(int) * @param the buffer type * @param buffer the buffer to set * @param cnt the distance to skip backwards * @return the buffer instance */ public static T unget(T buffer, int cnt) { if (cnt < 0) { throw msg.parameterOutOfRange("cnt"); } if (cnt > buffer.position()) { throw msg.bufferUnderflow(); } buffer.position(buffer.position() - cnt); return buffer; } /** * Take a certain number of bytes from the buffer and return them in an array. * * @param buffer the buffer to read * @param cnt the number of bytes to take * @return the bytes */ public static byte[] take(ByteBuffer buffer, int cnt) { if (cnt < 0) { throw msg.parameterOutOfRange("cnt"); } if (buffer.hasArray()) { final int pos = buffer.position(); final int lim = buffer.limit(); if (lim - pos < cnt) { throw new BufferUnderflowException(); } final byte[] array = buffer.array(); final int offset = buffer.arrayOffset(); buffer.position(pos + cnt); final int start = offset + pos; return Arrays.copyOfRange(array, start, start + cnt); } final byte[] bytes = new byte[cnt]; buffer.get(bytes); return bytes; } /** * Take a certain number of chars from the buffer and return them in an array. * * @param buffer the buffer to read * @param cnt the number of chars to take * @return the chars */ public static char[] take(CharBuffer buffer, int cnt) { if (cnt < 0) { throw msg.parameterOutOfRange("cnt"); } if (buffer.hasArray()) { final int pos = buffer.position(); final int lim = buffer.limit(); if (lim - pos < cnt) { throw new BufferUnderflowException(); } final char[] array = buffer.array(); final int offset = buffer.arrayOffset(); buffer.position(pos + cnt); final int start = offset + pos; return Arrays.copyOfRange(array, start, start + cnt); } final char[] chars = new char[cnt]; buffer.get(chars); return chars; } /** * Take a certain number of shorts from the buffer and return them in an array. * * @param buffer the buffer to read * @param cnt the number of shorts to take * @return the shorts */ public static short[] take(ShortBuffer buffer, int cnt) { if (cnt < 0) { throw msg.parameterOutOfRange("cnt"); } if (buffer.hasArray()) { final int pos = buffer.position(); final int lim = buffer.limit(); if (lim - pos < cnt) { throw new BufferUnderflowException(); } final short[] array = buffer.array(); final int offset = buffer.arrayOffset(); buffer.position(pos + cnt); final int start = offset + pos; return Arrays.copyOfRange(array, start, start + cnt); } final short[] shorts = new short[cnt]; buffer.get(shorts); return shorts; } /** * Take a certain number of ints from the buffer and return them in an array. * * @param buffer the buffer to read * @param cnt the number of ints to take * @return the ints */ public static int[] take(IntBuffer buffer, int cnt) { if (cnt < 0) { throw msg.parameterOutOfRange("cnt"); } if (buffer.hasArray()) { final int pos = buffer.position(); final int lim = buffer.limit(); if (lim - pos < cnt) { throw new BufferUnderflowException(); } final int[] array = buffer.array(); final int offset = buffer.arrayOffset(); buffer.position(pos + cnt); final int start = offset + pos; return Arrays.copyOfRange(array, start, start + cnt); } final int[] ints = new int[cnt]; buffer.get(ints); return ints; } /** * Take a certain number of longs from the buffer and return them in an array. * * @param buffer the buffer to read * @param cnt the number of longs to take * @return the longs */ public static long[] take(LongBuffer buffer, int cnt) { if (cnt < 0) { throw msg.parameterOutOfRange("cnt"); } if (buffer.hasArray()) { final int pos = buffer.position(); final int lim = buffer.limit(); if (lim - pos < cnt) { throw new BufferUnderflowException(); } final long[] array = buffer.array(); final int offset = buffer.arrayOffset(); buffer.position(pos + cnt); final int start = offset + pos; return Arrays.copyOfRange(array, start, start + cnt); } final long[] longs = new long[cnt]; buffer.get(longs); return longs; } private static final byte[] NO_BYTES = new byte[0]; /** * Take all of the remaining bytes from the buffer and return them in an array. * * @param buffer the buffer to read * @return the bytes */ public static byte[] take(ByteBuffer buffer) { final int remaining = buffer.remaining(); if (remaining == 0) return NO_BYTES; if (buffer.hasArray()) { final int pos = buffer.position(); final int lim = buffer.limit(); final byte[] array = buffer.array(); final int offset = buffer.arrayOffset(); buffer.position(lim); return Arrays.copyOfRange(array, offset + pos, offset + lim); } final byte[] bytes = new byte[remaining]; buffer.get(bytes); return bytes; } /** * Take all of the remaining bytes from the buffers and return them in an array. * * @param buffers the buffer to read * @param offs the offset into the array * @param len the number of buffers * @return the bytes */ public static byte[] take(final ByteBuffer[] buffers, final int offs, final int len) { if (len == 1) return take(buffers[offs]); final long remaining = Buffers.remaining(buffers, offs, len); if (remaining == 0L) return NO_BYTES; if (remaining > Integer.MAX_VALUE) throw new OutOfMemoryError("Array too large"); final byte[] bytes = new byte[(int) remaining]; int o = 0; int rem; ByteBuffer buffer; for (int i = 0; i < len; i ++) { buffer = buffers[i + offs]; rem = buffer.remaining(); buffer.get(bytes, o, rem); o += rem; } return bytes; } /** * Take all of the remaining chars from the buffer and return them in an array. * * @param buffer the buffer to read * @return the chars */ public static char[] take(CharBuffer buffer) { final char[] chars = new char[buffer.remaining()]; buffer.get(chars); return chars; } /** * Take all of the remaining shorts from the buffer and return them in an array. * * @param buffer the buffer to read * @return the shorts */ public static short[] take(ShortBuffer buffer) { final short[] shorts = new short[buffer.remaining()]; buffer.get(shorts); return shorts; } /** * Take all of the remaining ints from the buffer and return them in an array. * * @param buffer the buffer to read * @return the ints */ public static int[] take(IntBuffer buffer) { final int[] ints = new int[buffer.remaining()]; buffer.get(ints); return ints; } /** * Take all of the remaining longs from the buffer and return them in an array. * * @param buffer the buffer to read * @return the longs */ public static long[] take(LongBuffer buffer) { final long[] longs = new long[buffer.remaining()]; buffer.get(longs); return longs; } /** * Create an object that returns the dumped form of the given byte buffer when its {@code toString()} method is called. * Useful for logging byte buffers; if the {@code toString()} method is never called, the process of dumping the * buffer is never performed. * * @param buffer the buffer * @param indent the indentation to use * @param columns the number of 8-byte columns * @return a stringable object */ public static Object createDumper(final ByteBuffer buffer, final int indent, final int columns) { if (columns <= 0) { throw msg.parameterOutOfRange("columns"); } if (indent < 0) { throw msg.parameterOutOfRange("indent"); } return new Object() { public String toString() { StringBuilder b = new StringBuilder(); try { dump(buffer, b, indent, columns); } catch (IOException e) { // ignore, not possible! } return b.toString(); } }; } /** * Dump a byte buffer to the given target. * * @param buffer the buffer * @param dest the target * @param indent the indentation to use * @param columns the number of 8-byte columns * @throws IOException if an error occurs during append */ public static void dump(final ByteBuffer buffer, final Appendable dest, final int indent, final int columns) throws IOException { if (columns <= 0) { throw msg.parameterOutOfRange("columns"); } if (indent < 0) { throw msg.parameterOutOfRange("indent"); } final int pos = buffer.position(); final int remaining = buffer.remaining(); final int rowLength = (8 << (columns - 1)); final int n = Math.max(Integer.toString(buffer.remaining(), 16).length(), 4); for (int idx = 0; idx < remaining; idx += rowLength) { // state: start of line for (int i = 0; i < indent; i ++) { dest.append(' '); } final String s = Integer.toString(idx, 16); for (int i = n - s.length(); i > 0; i --) { dest.append('0'); } dest.append(s); dest.append(" - "); appendHexRow(buffer, dest, pos + idx, columns); appendTextRow(buffer, dest, pos + idx, columns); dest.append('\n'); } } private static void appendHexRow(final ByteBuffer buffer, final Appendable dest, final int startPos, final int columns) throws IOException { final int limit = buffer.limit(); int pos = startPos; for (int c = 0; c < columns; c ++) { for (int i = 0; i < 8; i ++) { if (pos >= limit) { dest.append(" "); } else { final int v = buffer.get(pos++) & 0xff; final String hexVal = Integer.toString(v, 16); if (v < 16) { dest.append('0'); } dest.append(hexVal); } dest.append(' '); } dest.append(' '); dest.append(' '); } } private static void appendTextRow(final ByteBuffer buffer, final Appendable dest, final int startPos, final int columns) throws IOException { final int limit = buffer.limit(); int pos = startPos; dest.append('['); dest.append(' '); for (int c = 0; c < columns; c ++) { for (int i = 0; i < 8; i ++) { if (pos >= limit) { dest.append(' '); } else { final char v = (char) (buffer.get(pos++) & 0xff); if (Character.isISOControl(v)) { dest.append('.'); } else { dest.append(v); } } } dest.append(' '); } dest.append(']'); } /** * Create an object that returns the dumped form of the given character buffer when its {@code toString()} method is called. * Useful for logging character buffers; if the {@code toString()} method is never called, the process of dumping the * buffer is never performed. * * @param buffer the buffer * @param indent the indentation to use * @param columns the number of 8-byte columns * @return a stringable object */ public static Object createDumper(final CharBuffer buffer, final int indent, final int columns) { if (columns <= 0) { throw msg.parameterOutOfRange("columns"); } if (indent < 0) { throw msg.parameterOutOfRange("indent"); } return new Object() { public String toString() { StringBuilder b = new StringBuilder(); try { dump(buffer, b, indent, columns); } catch (IOException e) { // ignore, not possible! } return b.toString(); } }; } /** * Dump a character buffer to the given target. * * @param buffer the buffer * @param dest the target * @param indent the indentation to use * @param columns the number of 8-byte columns * @throws IOException if an error occurs during append */ public static void dump(final CharBuffer buffer, final Appendable dest, final int indent, final int columns) throws IOException { if (columns <= 0) { throw msg.parameterOutOfRange("columns"); } if (indent < 0) { throw msg.parameterOutOfRange("indent"); } final int pos = buffer.position(); final int remaining = buffer.remaining(); final int rowLength = (8 << (columns - 1)); final int n = Math.max(Integer.toString(buffer.remaining(), 16).length(), 4); for (int idx = 0; idx < remaining; idx += rowLength) { // state: start of line for (int i = 0; i < indent; i ++) { dest.append(' '); } final String s = Integer.toString(idx, 16); for (int i = n - s.length(); i > 0; i --) { dest.append('0'); } dest.append(s); dest.append(" - "); appendHexRow(buffer, dest, pos + idx, columns); appendTextRow(buffer, dest, pos + idx, columns); dest.append('\n'); } } private static void appendHexRow(final CharBuffer buffer, final Appendable dest, final int startPos, final int columns) throws IOException { final int limit = buffer.limit(); int pos = startPos; for (int c = 0; c < columns; c ++) { for (int i = 0; i < 8; i ++) { if (pos >= limit) { dest.append(" "); } else { final char v = buffer.get(pos++); final String hexVal = Integer.toString(v, 16); dest.append("0000".substring(hexVal.length())); dest.append(hexVal); } dest.append(' '); } dest.append(' '); dest.append(' '); } } private static void appendTextRow(final CharBuffer buffer, final Appendable dest, final int startPos, final int columns) throws IOException { final int limit = buffer.limit(); int pos = startPos; dest.append('['); dest.append(' '); for (int c = 0; c < columns; c ++) { for (int i = 0; i < 8; i ++) { if (pos >= limit) { dest.append(' '); } else { final char v = buffer.get(pos++); if (Character.isISOControl(v) || Character.isHighSurrogate(v) || Character.isLowSurrogate(v)) { dest.append('.'); } else { dest.append(v); } } } dest.append(' '); } dest.append(']'); } /** * The empty byte buffer. */ public static final ByteBuffer EMPTY_BYTE_BUFFER = ByteBuffer.allocate(0); /** * The empty pooled byte buffer. Freeing or discarding this buffer has no effect. */ public static final Pooled EMPTY_POOLED_BYTE_BUFFER = emptyPooledByteBuffer(); /** * Determine whether any of the buffers has remaining data. * * @param buffers the buffers * @param offs the offset into the buffers array * @param len the number of buffers to check * @return {@code true} if any of the selected buffers has remaining data */ public static boolean hasRemaining(final Buffer[] buffers, final int offs, final int len) { for (int i = 0; i < len; i ++) { if (buffers[i + offs].hasRemaining()) { return true; } } return false; } /** * Determine whether any of the buffers has remaining data. * * @param buffers the buffers * @return {@code true} if any of the selected buffers has remaining data */ public static boolean hasRemaining(final Buffer[] buffers) { return hasRemaining(buffers, 0, buffers.length); } /** * Get the total remaining size of all the given buffers. * * @param buffers the buffers * @param offs the offset into the buffers array * @param len the number of buffers to check * @return the number of remaining elements */ public static long remaining(final Buffer[] buffers, final int offs, final int len) { long t = 0L; for (int i = 0; i < len; i ++) { t += buffers[i + offs].remaining(); } return t; } /** * Get the total remaining size of all the given buffers. * * @param buffers the buffers * @return the number of remaining elements */ public static long remaining(final Buffer[] buffers) { return remaining(buffers, 0, buffers.length); } /** * Put the string into the byte buffer, encoding it using "modified UTF-8" encoding. * * @param dest the byte buffer * @param orig the source bytes * @return the byte buffer * @throws BufferOverflowException if there is not enough space in the buffer for the complete string * @see DataOutput#writeUTF(String) */ public static ByteBuffer putModifiedUtf8(ByteBuffer dest, String orig) throws BufferOverflowException { final char[] chars = orig.toCharArray(); for (char c : chars) { if (c > 0 && c <= 0x7f) { dest.put((byte) c); } else if (c <= 0x07ff) { dest.put((byte)(0xc0 | 0x1f & c >> 6)); dest.put((byte)(0x80 | 0x3f & c)); } else { dest.put((byte)(0xe0 | 0x0f & c >> 12)); dest.put((byte)(0x80 | 0x3f & c >> 6)); dest.put((byte)(0x80 | 0x3f & c)); } } return dest; } /** * Get a 0-terminated string from the byte buffer, decoding it using "modified UTF-8" encoding. * * @param src the source buffer * @return the string * @throws BufferUnderflowException if the end of the buffer was reached before encountering a {@code 0} */ public static String getModifiedUtf8Z(ByteBuffer src) throws BufferUnderflowException { final StringBuilder builder = new StringBuilder(); for (;;) { final int ch = readUTFChar(src); if (ch == -1) { return builder.toString(); } builder.append((char) ch); } } /** * Get a modified UTF-8 string from the remainder of the buffer. * * @param src the buffer * @return the modified UTF-8 string * @throws BufferUnderflowException if the buffer ends abruptly in the midst of a single character */ public static String getModifiedUtf8(ByteBuffer src) throws BufferUnderflowException { final StringBuilder builder = new StringBuilder(); while (src.hasRemaining()) { final int ch = readUTFChar(src); if (ch == -1) { builder.append('\0'); } else { builder.append((char) ch); } } return builder.toString(); } private static int readUTFChar(final ByteBuffer src) throws BufferUnderflowException { final int a = src.get() & 0xff; if (a == 0) { return -1; } else if (a < 0x80) { return (char)a; } else if (a < 0xc0) { return '?'; } else if (a < 0xe0) { final int b = src.get() & 0xff; if ((b & 0xc0) != 0x80) { return '?'; } return (a & 0x1f) << 6 | b & 0x3f; } else if (a < 0xf0) { final int b = src.get() & 0xff; if ((b & 0xc0) != 0x80) { return '?'; } final int c = src.get() & 0xff; if ((c & 0xc0) != 0x80) { return '?'; } return (a & 0x0f) << 12 | (b & 0x3f) << 6 | c & 0x3f; } return '?'; } /** * Read an ASCIIZ ({@code NUL}-terminated) string from a byte buffer, appending the results to the given string * builder. If no {@code NUL} character is encountered, {@code false} is returned, indicating that more data needs * to be acquired before the operation can be complete. On return, there may be data remaining * in the source buffer. If an invalid byte is read, the character {@code '?'} is written * to the string builder in its place. * * @param src the source buffer * @param builder the destination builder * @return {@code true} if the entire string was read, {@code false} if more data is needed */ public static boolean readAsciiZ(final ByteBuffer src, final StringBuilder builder) { return readAsciiZ(src, builder, '?'); } /** * Read an ASCIIZ ({@code NUL}-terminated) string from a byte buffer, appending the results to the given string * builder. If no {@code NUL} character is encountered, {@code false} is returned, indicating that more data needs * to be acquired before the operation can be complete. On return, there may be data remaining * in the source buffer. If an invalid byte is read, the character designated by {@code replacement} is written * to the string builder in its place. * * @param src the source buffer * @param builder the destination builder * @param replacement the replacement character for invalid bytes * @return {@code true} if the entire string was read, {@code false} if more data is needed */ public static boolean readAsciiZ(final ByteBuffer src, final StringBuilder builder, final char replacement) { for (;;) { if (! src.hasRemaining()) { return false; } final byte b = src.get(); if (b == 0) { return true; } builder.append(b < 0 ? replacement : (char) b); } } /** * Read a single line of ASCII text from a byte buffer, appending the results to the given string * builder. If no {@code EOL} character is encountered, {@code false} is returned, indicating that more data needs * to be acquired before the operation can be complete. On return, there may be data remaining * in the source buffer. If an invalid byte is read, the character {@code '?'} is written * to the string builder in its place. The {@code EOL} character will be included in the resultant string. * * @param src the source buffer * @param builder the destination builder * @return {@code true} if the entire string was read, {@code false} if more data is needed */ public static boolean readAsciiLine(final ByteBuffer src, final StringBuilder builder) { return readAsciiLine(src, builder, '?', '\n'); } /** * Read a single line of ASCII text from a byte buffer, appending the results to the given string * builder. If no {@code EOL} character is encountered, {@code false} is returned, indicating that more data needs * to be acquired before the operation can be complete. On return, there may be data remaining * in the source buffer. If an invalid byte is read, the character designated by {@code replacement} is written * to the string builder in its place. The {@code EOL} character will be included in the resultant string. * * @param src the source buffer * @param builder the destination builder * @param replacement the replacement character for invalid bytes * @return {@code true} if the entire string was read, {@code false} if more data is needed */ public static boolean readAsciiLine(final ByteBuffer src, final StringBuilder builder, final char replacement) { return readAsciiLine(src, builder, replacement, '\n'); } /** * Read a single line of ASCII text from a byte buffer, appending the results to the given string * builder, using the given delimiter character instead of {@code EOL}. If no delimiter character is encountered, * {@code false} is returned, indicating that more data needs * to be acquired before the operation can be complete. On return, there may be data remaining * in the source buffer. If an invalid byte is read, the character designated by {@code replacement} is written * to the string builder in its place. The delimiter character will be included in the resultant string. * * @param src the source buffer * @param builder the destination builder * @param replacement the replacement character for invalid bytes * @param delimiter the character which marks the end of the line * @return {@code true} if the entire string was read, {@code false} if more data is needed */ public static boolean readAsciiLine(final ByteBuffer src, final StringBuilder builder, final char replacement, final char delimiter) { for (;;) { if (! src.hasRemaining()) { return false; } final byte b = src.get(); builder.append(b < 0 ? replacement : (char) b); if (b == delimiter) { return true; } } } /** * Read the remainder of a buffer as ASCII text, appending the results to the given string * builder. If an invalid byte is read, the character {@code '?'} is written * to the string builder in its place. * * @param src the source buffer * @param builder the destination builder */ public static void readAscii(final ByteBuffer src, final StringBuilder builder) { readAscii(src, builder, '?'); } /** * Read the remainder of a buffer as ASCII text, appending the results to the given string * builder. If an invalid byte is read, the character designated by {@code replacement} is written * to the string builder in its place. * * @param src the source buffer * @param builder the destination builder * @param replacement the replacement character for invalid bytes */ public static void readAscii(final ByteBuffer src, final StringBuilder builder, final char replacement) { for (;;) { if (! src.hasRemaining()) { return; } final byte b = src.get(); builder.append(b < 0 ? replacement : (char) b); } } /** * Read the remainder of a buffer as ASCII text, up to a certain limit, appending the results to the given string * builder. If an invalid byte is read, the character designated by {@code replacement} is written * to the string builder in its place. * * @param src the source buffer * @param builder the destination builder * @param limit the maximum number of characters to write * @param replacement the replacement character for invalid bytes */ public static void readAscii(final ByteBuffer src, final StringBuilder builder, int limit, final char replacement) { while (limit > 0) { if (! src.hasRemaining()) { return; } final byte b = src.get(); builder.append(b < 0 ? replacement : (char) b); limit--; } } /** * Read a {@code NUL}-terminated Latin-1 string from a byte buffer, appending the results to the given string * builder. If no {@code NUL} character is encountered, {@code false} is returned, indicating that more data needs * to be acquired before the operation can be complete. On return, there may be data remaining * in the source buffer. * * @param src the source buffer * @param builder the destination builder * @return {@code true} if the entire string was read, {@code false} if more data is needed */ public static boolean readLatin1Z(final ByteBuffer src, final StringBuilder builder) { for (;;) { if (! src.hasRemaining()) { return false; } final byte b = src.get(); if (b == 0) { return true; } builder.append((char) (b & 0xff)); } } /** * Read a single line of Latin-1 text from a byte buffer, appending the results to the given string * builder. If no {@code EOL} character is encountered, {@code false} is returned, indicating that more data needs * to be acquired before the operation can be complete. On return, there may be data remaining * in the source buffer. The {@code EOL} character will be included in the resultant string. * * @param src the source buffer * @param builder the destination builder * @return {@code true} if the entire string was read, {@code false} if more data is needed */ public static boolean readLatin1Line(final ByteBuffer src, final StringBuilder builder) { for (;;) { if (! src.hasRemaining()) { return false; } final byte b = src.get(); builder.append((char) (b & 0xff)); if (b == '\n') { return true; } } } /** * Read a single line of Latin-1 text from a byte buffer, appending the results to the given string * builder. If no delimiter character is encountered, {@code false} is returned, indicating that more data needs * to be acquired before the operation can be complete. On return, there may be data remaining * in the source buffer. The delimiter character will be included in the resultant string. * * @param src the source buffer * @param builder the destination builder * @param delimiter the character which marks the end of the line * @return {@code true} if the entire string was read, {@code false} if more data is needed */ public static boolean readLatin1Line(final ByteBuffer src, final StringBuilder builder, final char delimiter) { for (;;) { if (! src.hasRemaining()) { return false; } final byte b = src.get(); builder.append((char) (b & 0xff)); if (b == delimiter) { return true; } } } /** * Read the remainder of a buffer as Latin-1 text, appending the results to the given string * builder. * * @param src the source buffer * @param builder the destination builder */ public static void readLatin1(final ByteBuffer src, final StringBuilder builder) { for (;;) { if (! src.hasRemaining()) { return; } final byte b = src.get(); builder.append((char) (b & 0xff)); } } /** * Read a {@code NUL}-terminated {@link DataInput modified UTF-8} string from a byte buffer, appending the results to the given string * builder. If no {@code NUL} byte is encountered, {@code false} is returned, indicating that more data needs * to be acquired before the operation can be complete. On return, there may be data remaining * in the source buffer. If an invalid byte sequence is read, the character {@code '?'} is written * to the string builder in its place. * * @param src the source buffer * @param builder the destination builder * @return {@code true} if the entire string was read, {@code false} if more data is needed */ public static boolean readModifiedUtf8Z(final ByteBuffer src, final StringBuilder builder) { return readModifiedUtf8Z(src, builder, '?'); } /** * Read a {@code NUL}-terminated {@link DataInput modified UTF-8} string from a byte buffer, appending the results to the given string * builder. If no {@code NUL} byte is encountered, {@code false} is returned, indicating that more data needs * to be acquired before the operation can be complete. On return, there may be data remaining * in the source buffer. If an invalid byte sequence is read, the character designated by {@code replacement} is written * to the string builder in its place. * * @param src the source buffer * @param builder the destination builder * @param replacement the replacement character to use * @return {@code true} if the entire string was read, {@code false} if more data is needed */ public static boolean readModifiedUtf8Z(final ByteBuffer src, final StringBuilder builder, final char replacement) { for (;;) { if (! src.hasRemaining()) { return false; } final int a = src.get() & 0xff; if (a == 0) { return true; } else if (a < 0x80) { builder.append((char)a); } else if (a < 0xc0) { builder.append(replacement); } else if (a < 0xe0) { if (src.hasRemaining()) { final int b = src.get() & 0xff; if ((b & 0xc0) != 0x80) { builder.append(replacement); } else { builder.append((char) ((a & 0x1f) << 6 | b & 0x3f)); } } else { unget(src, 1); return false; } } else if (a < 0xf0) { if (src.hasRemaining()) { final int b = src.get() & 0xff; if ((b & 0xc0) != 0x80) { builder.append(replacement); } else { if (src.hasRemaining()) { final int c = src.get() & 0xff; if ((c & 0xc0) != 0x80) { builder.append(replacement); } else { builder.append((char) ((a & 0x0f) << 12 | (b & 0x3f) << 6 | c & 0x3f)); } } else { unget(src, 2); return false; } } } else { unget(src, 1); return false; } } else { builder.append(replacement); } } } /** * Read a single line of {@link DataInput modified UTF-8} text from a byte buffer, appending the results to the given string * builder. If no {@code EOL} character is encountered, {@code false} is returned, indicating that more data needs * to be acquired before the operation can be complete. On return, there may be data remaining * in the source buffer. If an invalid byte is read, the character {@code '?'} is written * to the string builder in its place. The {@code EOL} character will be included in the resultant string. * * @param src the source buffer * @param builder the destination builder * @return {@code true} if the entire string was read, {@code false} if more data is needed */ public static boolean readModifiedUtf8Line(final ByteBuffer src, final StringBuilder builder) { return readModifiedUtf8Line(src, builder, '?'); } /** * Read a single line of {@link DataInput modified UTF-8} text from a byte buffer, appending the results to the given string * builder. If no {@code EOL} character is encountered, {@code false} is returned, indicating that more data needs * to be acquired before the operation can be complete. On return, there may be data remaining * in the source buffer. If an invalid byte is read, the character designated by {@code replacement} is written * to the string builder in its place. The {@code EOL} character will be included in the resultant string. * * @param src the source buffer * @param builder the destination builder * @param replacement the replacement character for invalid bytes * @return {@code true} if the entire string was read, {@code false} if more data is needed */ public static boolean readModifiedUtf8Line(final ByteBuffer src, final StringBuilder builder, final char replacement) { return readModifiedUtf8Line(src, builder, replacement, '\n'); } /** * Read a single line of {@link DataInput modified UTF-8} text from a byte buffer, appending the results to the given string * builder. If no {@code EOL} character is encountered, {@code false} is returned, indicating that more data needs * to be acquired before the operation can be complete. On return, there may be data remaining * in the source buffer. If an invalid byte is read, the character designated by {@code replacement} is written * to the string builder in its place. The delimiter character will be included in the resultant string. * * @param src the source buffer * @param builder the destination builder * @param replacement the replacement character for invalid bytes * @param delimiter the character which marks the end of the line * @return {@code true} if the entire string was read, {@code false} if more data is needed */ public static boolean readModifiedUtf8Line(final ByteBuffer src, final StringBuilder builder, final char replacement, final char delimiter) { for (;;) { if (! src.hasRemaining()) { return false; } final int a = src.get() & 0xff; if (a < 0x80) { builder.append((char)a); if (a == delimiter) { return true; } } else if (a < 0xc0) { builder.append(replacement); } else if (a < 0xe0) { if (src.hasRemaining()) { final int b = src.get() & 0xff; if ((b & 0xc0) != 0x80) { builder.append(replacement); } else { final char ch = (char) ((a & 0x1f) << 6 | b & 0x3f); builder.append(ch); if (ch == delimiter) { return true; } } } else { unget(src, 1); return false; } } else if (a < 0xf0) { if (src.hasRemaining()) { final int b = src.get() & 0xff; if ((b & 0xc0) != 0x80) { builder.append(replacement); } else { if (src.hasRemaining()) { final int c = src.get() & 0xff; if ((c & 0xc0) != 0x80) { builder.append(replacement); } else { final char ch = (char) ((a & 0x0f) << 12 | (b & 0x3f) << 6 | c & 0x3f); builder.append(ch); if (ch == delimiter) { return true; } } } else { unget(src, 2); return false; } } } else { unget(src, 1); return false; } } else { builder.append(replacement); } } } /** * Read a single line of text from a byte buffer, appending the results to the given string * builder. If no {@code EOL} character is encountered, {@code false} is returned, indicating that more data needs * to be acquired before the operation can be complete. On return, there may be data remaining * in the source buffer. Invalid bytes are handled according to the policy specified by the {@code decoder} instance. * Since this method decodes only one character at a time, it should not be expected to have the same performance * as the other optimized, character set-specific methods specified in this class. * The {@code EOL} character will be included in the resultant string. * * @param src the source buffer * @param builder the destination builder * @param decoder the decoder to use * @return {@code true} if the entire string was read, {@code false} if more data is needed */ public static boolean readLine(final ByteBuffer src, final StringBuilder builder, final CharsetDecoder decoder) { return readLine(src, builder, decoder, '\n'); } /** * Read a single line of text from a byte buffer, appending the results to the given string * builder. If no delimiter character is encountered, {@code false} is returned, indicating that more data needs * to be acquired before the operation can be complete. On return, there may be data remaining * in the source buffer. Invalid bytes are handled according to the policy specified by the {@code decoder} instance. * Since this method decodes only one character at a time, it should not be expected to have the same performance * as the other optimized, character set-specific methods specified in this class. The delimiter character will be * included in the resultant string. * * @param src the source buffer * @param builder the destination builder * @param decoder the decoder to use * @param delimiter the character which marks the end of the line * @return {@code true} if the entire string was read, {@code false} if more data is needed */ public static boolean readLine(final ByteBuffer src, final StringBuilder builder, final CharsetDecoder decoder, final char delimiter) { final CharBuffer oneChar = CharBuffer.allocate(1); for (;;) { final CoderResult coderResult = decoder.decode(src, oneChar, false); if (coderResult.isUnderflow()) { if (oneChar.hasRemaining()) { return false; } } else if (oneChar.hasRemaining()) { throw new IllegalStateException(); } final char ch = oneChar.get(0); builder.append(ch); if (ch == delimiter) { return true; } oneChar.clear(); } } /** * Create a pooled wrapper around a buffer. The buffer is unreferenced for garbage collection when * freed or discarded. * * @param buffer the buffer to wrap * @param the buffer type * @return the pooled wrapper */ public static Pooled pooledWrapper(final B buffer) { return new Pooled() { private volatile B buf = buffer; public void discard() { buf = null; } public void free() { buf = null; } public B getResource() throws IllegalStateException { final B buffer = buf; if (buffer == null) { throw new IllegalStateException(); } return buffer; } public void close() { free(); } public String toString() { return "Pooled wrapper around " + buffer; } }; } /** * Create a "pooled" empty buffer. Discarding or freeing the buffer has no effect; the returned buffer is * always empty. * * @return a new pooled empty buffer */ public static Pooled emptyPooledByteBuffer() { return new Pooled() { public void discard() { } public void free() { } public ByteBuffer getResource() throws IllegalStateException { return EMPTY_BYTE_BUFFER; } public void close() { } }; } /** * A buffer allocator which allocates slices off of the given buffer. Once the buffer is exhausted, further * attempts to allocate buffers will result in {@link BufferUnderflowException}. * * @param buffer the source buffer * @return the slice allocator */ public static BufferAllocator sliceAllocator(final ByteBuffer buffer) { return new BufferAllocator() { public ByteBuffer allocate(final int size) throws IllegalArgumentException { return Buffers.slice(buffer, size); } }; } /** * A buffer pool which allocates a new buffer on every allocate request, and discards buffers on free. * * @param allocator the buffer allocator * @param size the buffer size * @param the buffer type * @return the buffer pool */ public static Pool allocatedBufferPool(final BufferAllocator allocator, final int size) { return new Pool() { public Pooled allocate() { return pooledWrapper(allocator.allocate(size)); } }; } /** * A byte buffer pool which zeroes the content of the buffer before re-pooling it. * * @param delegate the delegate pool * @return the wrapper pool */ public static Pool secureBufferPool(final Pool delegate) { return new SecureByteBufferPool(delegate); } /** * Determine whether the given pool is a secure pool. Note that this test will fail if used on a pool * which wraps a secure pool. * * @param pool the pool to test * @return {@code true} if it is a secure pool instance */ public static boolean isSecureBufferPool(Pool pool) { return pool instanceof SecureByteBufferPool; } /** * Zero a buffer. Ensures that any potentially sensitive information in the buffer is * overwritten. * * @param buffer the buffer */ public static void zero(ByteBuffer buffer) { buffer.clear(); while (buffer.remaining() >= 8) { buffer.putLong(0L); } while (buffer.hasRemaining()) { buffer.put((byte) 0); } buffer.clear(); } /** * Zero a buffer. Ensures that any potentially sensitive information in the buffer is * overwritten. * * @param buffer the buffer */ public static void zero(CharBuffer buffer) { buffer.clear(); while (buffer.remaining() >= 32) { buffer.put("\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0"); } while (buffer.hasRemaining()) { buffer.put('\0'); } buffer.clear(); } /** * Determine whether the given buffers list is comprised solely of direct buffers or solely of heap buffers. * * @param buffers the buffers * @return {@code true} if all the buffers are direct, {@code false} if they are all heap buffers * @throws IllegalArgumentException if both direct and heap buffers were found, or if a buffer is {@code null} */ public static boolean isDirect(Buffer... buffers) throws IllegalArgumentException { return isDirect(buffers, 0, buffers.length); } /** * Determine whether the given buffers list is comprised solely of direct buffers or solely of heap buffers. * * @param buffers the buffers * @return {@code true} if all the buffers are direct, {@code false} if they are all heap buffers * @throws IllegalArgumentException if both direct and heap buffers were found, or if a buffer is {@code null} */ public static boolean isDirect(final Buffer[] buffers, final int offset, final int length) { boolean foundDirect = false; boolean foundHeap = false; for (int i = 0; i < length; i ++) { final Buffer buffer = buffers[i + offset]; if (buffer == null) { throw msg.nullParameter("buffer"); } if (buffer.isDirect()) { if (foundHeap) { throw msg.mixedDirectAndHeap(); } foundDirect = true; } else { if (foundDirect) { throw msg.mixedDirectAndHeap(); } foundHeap = true; } } return foundDirect; } /** * Assert the writability of the given buffers. * * @param buffers the buffers array * @param offs the offset in the array to start searching * @param len the number of buffers to check * @throws ReadOnlyBufferException if any of the buffers are read-only */ public static void assertWritable(Buffer[] buffers, int offs, int len) throws ReadOnlyBufferException { for (int i = 0; i < len; i ++) { if (buffers[i + offs].isReadOnly()) { throw msg.readOnlyBuffer(); } } } /** * Assert the writability of the given buffers. * * @param buffers the buffers array * @throws ReadOnlyBufferException if any of the buffers are read-only */ public static void assertWritable(Buffer... buffers) throws ReadOnlyBufferException { assertWritable(buffers, 0, buffers.length); } /** * Add {@code count} bytes of random data to the target buffer. * * @param target the target buffer * @param random the RNG * @param count the number of bytes to add */ public static void addRandom(ByteBuffer target, Random random, int count) { final byte[] bytes = new byte[count]; random.nextBytes(bytes); target.put(bytes); } /** * Add {@code count} bytes of random data to the target buffer using the thread-local RNG. * * @param target the target buffer * @param count the number of bytes to add */ public static void addRandom(ByteBuffer target, int count) { addRandom(target, IoUtils.getThreadLocalRandom(), count); } /** * Add a random amount of random data to the target buffer. * * @param target the target buffer * @param random the RNG */ public static void addRandom(ByteBuffer target, Random random) { if (target.remaining() == 0) { return; } addRandom(target, random, random.nextInt(target.remaining())); } /** * Add a random amount of random data to the target buffer using the thread-local RNG. * * @param target the target buffer */ public static void addRandom(ByteBuffer target) { addRandom(target, IoUtils.getThreadLocalRandom()); } /** * Fill a buffer from an input stream. Specially optimized for heap buffers. If a partial transfer occurs * due to interruption, the buffer's position is updated accordingly. * * @param target the target buffer * @param source the source stream * @return the number of bytes transferred, or {@code -1} if no bytes were moved due to end-of-stream * @throws IOException if the stream read fails */ public static int fillFromStream(ByteBuffer target, InputStream source) throws IOException { final int remaining = target.remaining(); if (remaining == 0) { return 0; } else { final int p = target.position(); if (target.hasArray()) { // fast path final int res; try { res = source.read(target.array(), p + target.arrayOffset(), remaining); } catch (InterruptedIOException e) { target.position(p + e.bytesTransferred); throw e; } if (res > 0) { target.position(p + res); } return res; } else { byte[] tmp = new byte[remaining]; final int res; try { res = source.read(tmp); } catch (InterruptedIOException e) { final int n = e.bytesTransferred; target.put(tmp, 0, n); target.position(p + n); throw e; } if (res > 0) { target.put(tmp, 0, res); } return res; } } } /** * Empty a buffer to an output stream. Specially optimized for heap buffers. If a partial transfer occurs * due to interruption, the buffer's position is updated accordingly. * * @param target the target stream * @param source the source buffer * @throws IOException if the stream write fails */ public static void emptyToStream(OutputStream target, ByteBuffer source) throws IOException { final int remaining = source.remaining(); if (remaining == 0) { return; } else { final int p = source.position(); if (source.hasArray()) { // fast path try { target.write(source.array(), p + source.arrayOffset(), remaining); } catch (InterruptedIOException e) { source.position(p + e.bytesTransferred); throw e; } source.position(source.limit()); return; } else { byte[] tmp = take(source); try { target.write(tmp); } catch (InterruptedIOException e) { source.position(p + e.bytesTransferred); throw e; } catch (IOException e) { source.position(p); throw e; } } } } private static class SecureByteBufferPool implements Pool { private final Pool delegate; SecureByteBufferPool(final Pool delegate) { this.delegate = delegate; } public Pooled allocate() { return new SecurePooledByteBuffer(delegate.allocate()); } } private static class SecurePooledByteBuffer implements Pooled { private static final AtomicIntegerFieldUpdater freedUpdater = AtomicIntegerFieldUpdater.newUpdater(SecurePooledByteBuffer.class, "freed"); private final Pooled allocated; @SuppressWarnings("unused") private volatile int freed; SecurePooledByteBuffer(final Pooled allocated) { this.allocated = allocated; } public void discard() { if (freedUpdater.compareAndSet(this, 0, 1)) { zero(allocated.getResource()); allocated.discard(); } } public void free() { if (freedUpdater.compareAndSet(this, 0, 1)) { zero(allocated.getResource()); allocated.free(); } } public ByteBuffer getResource() throws IllegalStateException { // trust the delegate to handle illegal state since we can't do it securely by ourselves return allocated.getResource(); } public void close() { free(); } public String toString() { return "Secure wrapper around " + allocated; } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/ByteBufferSlicePool.java000066400000000000000000000214311257016060700252140ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2010 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import java.nio.ByteBuffer; import java.security.AccessController; import java.util.ArrayDeque; import java.util.Collections; import java.util.HashSet; import java.util.Queue; import java.util.Set; import java.util.concurrent.ConcurrentLinkedQueue; import static org.xnio._private.Messages.msg; /** * A buffer pooled allocator. This pool uses a series of buffer regions to back the * returned pooled buffers. When the buffer is no longer needed, it should be freed back into the pool; failure * to do so will cause the corresponding buffer area to be unavailable until the buffer is garbage-collected. * * @author David M. Lloyd */ public final class ByteBufferSlicePool implements Pool { private static final int LOCAL_LENGTH; static { String value = AccessController.doPrivileged(new ReadPropertyAction("xnio.bufferpool.threadlocal.size", "12")); int val; try { val = Integer.parseInt(value); } catch (NumberFormatException ignored) { val = 12; } LOCAL_LENGTH = val; } private final Set refSet = Collections.synchronizedSet(new HashSet()); private final Queue sliceQueue; private final BufferAllocator allocator; private final int bufferSize; private final int buffersPerRegion; private final int threadLocalQueueSize; private final ThreadLocal localQueueHolder = new ThreadLocal() { protected ThreadLocalCache initialValue() { //noinspection serial return new ThreadLocalCache(this); } public void remove() { final ArrayDeque deque = get().queue; Slice slice = deque.poll(); while (slice != null) { doFree(slice); slice = deque.poll(); } super.remove(); } }; /** * Construct a new instance. * * @param allocator the buffer allocator to use * @param bufferSize the size of each buffer * @param maxRegionSize the maximum region size for each backing buffer * @param threadLocalQueueSize the number of buffers to cache on each thread */ public ByteBufferSlicePool(final BufferAllocator allocator, final int bufferSize, final int maxRegionSize, final int threadLocalQueueSize) { if (bufferSize <= 0) { throw msg.parameterOutOfRange("bufferSize"); } if (maxRegionSize < bufferSize) { throw msg.parameterOutOfRange("bufferSize"); } buffersPerRegion = maxRegionSize / bufferSize; this.bufferSize = bufferSize; this.allocator = allocator; sliceQueue = new ConcurrentLinkedQueue(); this.threadLocalQueueSize = threadLocalQueueSize; } /** * Construct a new instance. * * @param allocator the buffer allocator to use * @param bufferSize the size of each buffer * @param maxRegionSize the maximum region size for each backing buffer */ public ByteBufferSlicePool(final BufferAllocator allocator, final int bufferSize, final int maxRegionSize) { this(allocator, bufferSize, maxRegionSize, LOCAL_LENGTH); } /** * Construct a new instance, using a direct buffer allocator. * * @param bufferSize the size of each buffer * @param maxRegionSize the maximum region size for each backing buffer */ public ByteBufferSlicePool(final int bufferSize, final int maxRegionSize) { this(BufferAllocator.DIRECT_BYTE_BUFFER_ALLOCATOR, bufferSize, maxRegionSize); } /** {@inheritDoc} */ public Pooled allocate() { ThreadLocalCache localCache = localQueueHolder.get(); if(localCache.outstanding != threadLocalQueueSize) { localCache.outstanding++; } Slice slice = localCache.queue.poll(); if (slice != null) { return new PooledByteBuffer(slice, slice.slice()); } final Queue sliceQueue = this.sliceQueue; slice = sliceQueue.poll(); if (slice != null) { return new PooledByteBuffer(slice, slice.slice()); } synchronized (sliceQueue) { slice = sliceQueue.poll(); if (slice != null) { return new PooledByteBuffer(slice, slice.slice()); } final int bufferSize = this.bufferSize; final int buffersPerRegion = this.buffersPerRegion; final ByteBuffer region = allocator.allocate(buffersPerRegion * bufferSize); int idx = bufferSize; for (int i = 1; i < buffersPerRegion; i ++) { sliceQueue.add(new Slice(region, idx, bufferSize)); idx += bufferSize; } final Slice newSlice = new Slice(region, 0, bufferSize); return new PooledByteBuffer(newSlice, newSlice.slice()); } } /** * Return the size of the {@link ByteBuffer}s that are returned by {@link #allocate()}. */ public int getBufferSize() { return bufferSize; } private void doFree(Slice region) { final ThreadLocalCache localCache = localQueueHolder.get(); boolean cacheOk = false; if(localCache.outstanding > 0) { localCache.outstanding--; cacheOk = true; } ArrayDeque localQueue = localCache.queue; if (localQueue.size() == threadLocalQueueSize || !cacheOk) { sliceQueue.add(region); } else { localQueue.add(region); } } private final class PooledByteBuffer implements Pooled { private final Slice region; ByteBuffer buffer; PooledByteBuffer(final Slice region, final ByteBuffer buffer) { this.region = region; this.buffer = buffer; } public void discard() { final ByteBuffer buffer = this.buffer; this.buffer = null; if (buffer != null) { // free when GC'd, no sooner refSet.add(new Ref(buffer, region)); } } public void free() { ByteBuffer buffer = this.buffer; this.buffer = null; if (buffer != null) { // trust the user, repool the buffer doFree(region); } } public ByteBuffer getResource() { final ByteBuffer buffer = this.buffer; if (buffer == null) { throw msg.bufferFreed(); } return buffer; } public void close() { free(); } public String toString() { return "Pooled buffer " + buffer; } } private final class Slice { private final ByteBuffer parent; private Slice(final ByteBuffer parent, final int start, final int size) { this.parent = (ByteBuffer)parent.duplicate().position(start).limit(start+size); } ByteBuffer slice() { return parent.slice(); } } final class Ref extends AutomaticReference { private final Slice region; private Ref(final ByteBuffer referent, final Slice region) { super(referent, AutomaticReference.PERMIT); this.region = region; } protected void free() { doFree(region); refSet.remove(this); } } private final class ThreadLocalCache { private final ThreadLocal threadLocal; final ArrayDeque queue = new ArrayDeque(threadLocalQueueSize) { /** * This sucks but there's no other way to ensure these buffers are returned to the pool. */ protected void finalize() { threadLocal.remove(); } }; int outstanding = 0; private ThreadLocalCache(ThreadLocal threadLocal) { this.threadLocal = threadLocal; } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/ByteString.java000066400000000000000000001242701257016060700234440ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2009 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.io.IOException; import java.io.ObjectInputStream; import java.io.OutputStream; import java.nio.charset.StandardCharsets; import java.util.Arrays; import java.io.UnsupportedEncodingException; import java.io.Serializable; import java.nio.charset.Charset; import java.nio.ByteBuffer; import static java.lang.Integer.signum; import static java.lang.Math.abs; import static java.lang.Math.max; import static java.lang.Math.min; import static java.lang.System.arraycopy; import static org.xnio._private.Messages.msg; /** * An immutable string of bytes. Since instances of this class are guaranteed to be immutable, they are * safe to use as {@link Option} values and in an {@link OptionMap}. Some operations can treat this byte string * as an ASCII- or ISO-8858-1-encoded character string. */ public final class ByteString implements Comparable, Serializable, CharSequence { private static final long serialVersionUID = -5998895518404718196L; private final byte[] bytes; private final int offs; private final int len; private transient int hashCode; private transient int hashCodeIgnoreCase; private ByteString(final byte[] bytes, final int offs, final int len) { this.bytes = bytes; this.offs = offs; this.len = len; if (offs < 0) { throw msg.parameterOutOfRange("offs"); } if (len < 0) { throw msg.parameterOutOfRange("len"); } if (offs + len > bytes.length) { throw msg.parameterOutOfRange("offs"); } } private static int calcHashCode(final byte[] bytes, final int offs, final int len) { int hc = 31; final int end = offs + len; for (int i = offs; i < end; i++) { hc = (hc << 5) - hc + (bytes[i] & 0xff); } return hc == 0 ? Integer.MAX_VALUE : hc; } private static int calcHashCodeIgnoreCase(final byte[] bytes, final int offs, final int len) { int hc = 31; final int end = offs + len; for (int i = offs; i < end; i++) { hc = (hc << 5) - hc + (upperCase(bytes[i]) & 0xff); } return hc == 0 ? Integer.MAX_VALUE : hc; } private ByteString(final byte[] bytes) { this(bytes, 0, bytes.length); } /** * Create a byte string of the given literal bytes. The given array is copied. * * @param bytes the bytes * @return the byte string */ public static ByteString of(byte... bytes) { return new ByteString(bytes.clone()); } /** * Create a byte string from the given array segment. * * @param b the byte array * @param offs the offset into the array * @param len the number of bytes to copy * @return the new byte string */ public static ByteString copyOf(byte[] b, int offs, int len) { return new ByteString(Arrays.copyOfRange(b, offs, offs + len)); } /** * Get a byte string from the bytes of a character string. * * @param str the character string * @param charset the character set to use * @return the byte string * @throws UnsupportedEncodingException if the encoding is not supported */ public static ByteString getBytes(String str, String charset) throws UnsupportedEncodingException { return new ByteString(str.getBytes(charset)); } /** * Get a byte string from the bytes of a character string. * * @param str the character string * @param charset the character set to use * @return the byte string */ public static ByteString getBytes(String str, Charset charset) { return new ByteString(str.getBytes(charset)); } /** * Get a byte string from the bytes of the character string. The string must be a Latin-1 string. * * @param str the character string * @return the byte string */ public static ByteString getBytes(String str) { final int length = str.length(); return new ByteString(getStringBytes(false, new byte[length], 0, str, 0, length), 0, length); } /** * Get a byte string from all remaining bytes of a ByteBuffer. * * @param buffer the buffer * @return the byte string */ public static ByteString getBytes(ByteBuffer buffer) { return new ByteString(Buffers.take(buffer)); } /** * Get a byte string from a ByteBuffer. * * @param buffer the buffer * @param length the number of bytes to get * @return the byte string */ public static ByteString getBytes(ByteBuffer buffer, int length) { return new ByteString(Buffers.take(buffer, length)); } /** * Get a copy of the bytes of this ByteString. * * @return the copy */ public byte[] getBytes() { return Arrays.copyOfRange(bytes, offs, len); } /** * Copy the bytes of this ByteString into the destination array. If the array is too short to hold * the bytes, then only enough bytes to fill the array will be copied. * * @param dest the destination array * * @deprecated Replaced by {@link #copyTo(byte[])}. */ public void getBytes(byte[] dest) { copyTo(dest); } /** * Copy the bytes of this ByteString into the destination array. If the array is too short to hold * the bytes, then only enough bytes to fill the array will be copied. * * @param dest the destination array * @param offs the offset into the destination array * * @deprecated Replaced by {@link #copyTo(byte[],int)}. */ public void getBytes(byte[] dest, int offs) { copyTo(dest, offs); } /** * Copy the bytes of this ByteString into the destination array. If the array is too short to hold * the bytes, then only enough bytes to fill the array will be copied. * * @param dest the destination array * @param offs the offset into the destination array * @param len the maximum number of bytes to copy * * @deprecated Replaced by {@link #copyTo(byte[],int,int)}. */ public void getBytes(byte[] dest, int offs, int len) { copyTo(dest, offs, len); } /** * Copy {@code len} bytes from this string at offset {@code srcOffs} to the given array at the given offset. * * @param srcOffs the source offset * @param dst the destination * @param offs the destination offset * @param len the number of bytes to copy */ public void copyTo(int srcOffs, byte[] dst, int offs, int len) { arraycopy(bytes, srcOffs + this.offs, dst, offs, min(this.len, len)); } /** * Copy {@code len} bytes from this string to the given array at the given offset. * * @param dst the destination * @param offs the destination offset * @param len the number of bytes */ public void copyTo(byte[] dst, int offs, int len) { copyTo(0, dst, offs, len); } /** * Copy all the bytes from this string to the given array at the given offset. * * @param dst the destination * @param offs the destination offset */ public void copyTo(byte[] dst, int offs) { copyTo(dst, offs, dst.length - offs); } /** * Copy all the bytes from this string to the given array at the given offset. * * @param dst the destination */ public void copyTo(byte[] dst) { copyTo(dst, 0, dst.length); } /** * Append the bytes of this string into the given buffer. * * @param dest the target buffer */ public void appendTo(ByteBuffer dest) { dest.put(bytes, offs, len); } /** * Append as many bytes as possible to a byte buffer. * * @param offs the start offset * @param buffer the buffer to append to * @return the number of bytes appended */ public int tryAppendTo(final int offs, final ByteBuffer buffer) { final byte[] b = bytes; final int len = min(buffer.remaining(), b.length - offs); buffer.put(b, offs + this.offs, len); return len; } /** * Append to an output stream. * * @param output the stream to write to * @throws IOException if an error occurs */ public void writeTo(OutputStream output) throws IOException { // todo - determine if the output stream is trusted output.write(bytes, offs, len); } /** * Compare this string to another in a case-sensitive manner. * * @param other the other string * @return -1, 0, or 1 */ @Override public int compareTo(final ByteString other) { if (other == this) return 0; final int length = this.len; final int otherLength = other.len; final int len1 = min(length, otherLength); final byte[] bytes = this.bytes; final byte[] otherBytes = other.bytes; final int offs = this.offs; final int otherOffs = other.offs; int res; for (int i = 0; i < len1; i++) { res = signum(bytes[i + offs] - otherBytes[i + otherOffs]); if (res != 0) return res; } // shorter strings sort higher return signum(length - otherLength); } /** * Compare this string to another in a case-insensitive manner. * * @param other the other string * @return -1, 0, or 1 */ public int compareToIgnoreCase(final ByteString other) { if (other == this) return 0; if (other == this) return 0; final int length = this.len; final int otherLength = other.len; final int len1 = min(length, otherLength); final byte[] bytes = this.bytes; final byte[] otherBytes = other.bytes; final int offs = this.offs; final int otherOffs = other.offs; int res; for (int i = 0; i < len1; i++) { res = signum(upperCase(bytes[i + offs]) - upperCase(otherBytes[i + otherOffs])); if (res != 0) return res; } // shorter strings sort higher return signum(length - otherLength); } private static int upperCase(byte b) { return b >= 'a' && b <= 'z' ? b & 0xDF : b; } /** * Convert this byte string to a standard string. * * @param charset the character set to use * @return the standard string * @throws UnsupportedEncodingException if the charset is unknown */ public String toString(String charset) throws UnsupportedEncodingException { if ("ISO-8859-1".equalsIgnoreCase(charset) || "Latin-1".equalsIgnoreCase(charset) || "ISO-Latin-1".equals(charset)) return toString(); return new String(bytes, offs, len, charset); } /** * Get the number of bytes in this byte string. * * @return the number of bytes */ public int length() { return len; } /** * Decode this byte string as a Latin-1 string. * * @return the Latin-1-decoded version of this string */ @SuppressWarnings("deprecation") public String toString() { return new String(bytes, 0, offs, len); } /** * Decode this byte string as a UTF-8 string. * * @return the UTF-8-decoded version of this string */ public String toUtf8String() { return new String(bytes, offs, len, StandardCharsets.UTF_8); } /** * Get the byte at an index. * * @return the byte at an index */ public byte byteAt(int idx) { if (idx < 0 || idx > len) { throw new ArrayIndexOutOfBoundsException(); } return bytes[idx + offs]; } /** * Get the substring of this string starting at the given offset. * * @param offs the offset * @return the substring */ public ByteString substring(int offs) { return substring(offs, len - offs); } /** * Get the substring of this string starting at the given offset. * * @param offs the offset * @param len the substring length * @return the substring */ public ByteString substring(int offs, int len) { if (this.len - offs < len) { throw new IndexOutOfBoundsException(); } return new ByteString(bytes, this.offs + offs, len); } /** * Get the hash code for this ByteString. * * @return the hash code */ public int hashCode() { int hashCode = this.hashCode; if (hashCode == 0) { this.hashCode = hashCode = calcHashCode(bytes, offs, len); } return hashCode; } public int hashCodeIgnoreCase() { int hashCode = this.hashCodeIgnoreCase; if (hashCode == 0) { this.hashCodeIgnoreCase = hashCode = calcHashCodeIgnoreCase(bytes, offs, len); } return hashCode; } private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException { ois.defaultReadObject(); } private static boolean equals(byte[] a, int aoff, byte[] b, int boff, int len) { for (int i = 0; i < len; i ++) { if (a[i + aoff] != b[i + boff]) return false; } return true; } private static boolean equalsIgnoreCase(byte[] a, int aoff, byte[] b, int boff, int len) { for (int i = 0; i < len; i ++) { if (upperCase(a[i + aoff]) != upperCase(b[i + boff])) return false; } return true; } /** * Determine if this ByteString equals another ByteString. * * @param obj the other object * @return {@code true} if they are equal */ public boolean equals(final Object obj) { return (obj instanceof ByteString) && equals((ByteString) obj); } /** * Determine if this ByteString equals another ByteString. * * @param other the other object * @return {@code true} if they are equal */ public boolean equals(final ByteString other) { final int len = this.len; return this == other || other != null && len == other.len && equals(bytes, offs, other.bytes, other.offs, len); } /** * Determine if this ByteString equals another ByteString, ignoring case (ASCII). * * @param other the other object * @return {@code true} if they are equal */ public boolean equalsIgnoreCase(final ByteString other) { final int len = this.len; return this == other || other != null && len == other.len && equalsIgnoreCase(bytes, offs, other.bytes, other.offs, len); } /** * Get the unsigned {@code int} value of this string. If the value is greater than would fit in 32 bits, only * the low 32 bits are returned. Parsing stops on the first non-digit character. * * @param start the index to start at (must be less than or equal to length) * @return the value */ public int toInt(final int start) { final int len = this.len; if (start >= len) { return 0; } final byte[] bytes = this.bytes; int v = 0; byte b; for (int i = start + offs; i < len; i ++) { b = bytes[i]; if (b < '0' || b > '9') { return v; } v = (v << 3) + (v << 1) + (b - '0'); } return v; } /** * Get the unsigned {@code int} value of this string. If the value is greater than would fit in 32 bits, only * the low 32 bits are returned. Parsing stops on the first non-digit character. * * @return the value */ public int toInt() { return toInt(0); } /** * Get the unsigned {@code long} value of this string. If the value is greater than would fit in 64 bits, only * the low 64 bits are returned. Parsing stops on the first non-digit character. * * @param start the index to start at (must be less than or equal to length) * @return the value */ public long toLong(final int start) { final int len = this.len; if (start >= len) { return 0; } final byte[] bytes = this.bytes; long v = 0; byte b; for (int i = start; i < len; i ++) { b = bytes[i]; if (b < '0' || b > '9') { return v; } v = (v << 3) + (v << 1) + (b - '0'); } return v; } /** * Get the unsigned {@code long} value of this string. If the value is greater than would fit in 64 bits, only * the low 64 bits are returned. Parsing stops on the first non-digit character. * * @return the value */ public long toLong() { return toLong(0); } private static int decimalCount(int val) { assert val >= 0; // afaik no faster way exists to do this if (val < 10) return 1; if (val < 100) return 2; if (val < 1000) return 3; if (val < 10000) return 4; if (val < 100000) return 5; if (val < 1000000) return 6; if (val < 10000000) return 7; if (val < 100000000) return 8; if (val < 1000000000) return 9; return 10; } private static int decimalCount(long val) { assert val >= 0; // afaik no faster way exists to do this if (val < 10L) return 1; if (val < 100L) return 2; if (val < 1000L) return 3; if (val < 10000L) return 4; if (val < 100000L) return 5; if (val < 1000000L) return 6; if (val < 10000000L) return 7; if (val < 100000000L) return 8; if (val < 1000000000L) return 9; if (val < 10000000000L) return 10; if (val < 100000000000L) return 11; if (val < 1000000000000L) return 12; if (val < 10000000000000L) return 13; if (val < 100000000000000L) return 14; if (val < 1000000000000000L) return 15; if (val < 10000000000000000L) return 16; if (val < 100000000000000000L) return 17; if (val < 1000000000000000000L) return 18; return 19; } private static final ByteString ZERO = new ByteString(new byte[] { '0' }); /** * Get a string version of the given value. * * @param val the value * @return the string */ public static ByteString fromLong(long val) { if (val == 0) return ZERO; // afaik no faster way exists to do this int i = decimalCount(abs(val)); final byte[] b; if (val < 0) { b = new byte[++i]; b[0] = '-'; } else { b = new byte[i]; } long quo; // modulus int mod; do { quo = val / 10; mod = (int) (val - ((quo << 3) + (quo << 1))); b[--i] = (byte) (mod + '0'); val = quo; } while (i > 0); return new ByteString(b); } /** * Get a string version of the given value. * * @param val the value * @return the string */ public static ByteString fromInt(int val) { if (val == 0) return ZERO; // afaik no faster way exists to do this int i = decimalCount(abs(val)); final byte[] b; if (val < 0) { b = new byte[++i]; b[0] = '-'; } else { b = new byte[i]; } int quo; // modulus int mod; do { quo = val / 10; mod = val - ((quo << 3) + (quo << 1)); b[--i] = (byte) (mod + '0'); val = quo; } while (i > 0); return new ByteString(b); } /** * Determine whether this {@code ByteString} is equal (case-sensitively) to the given {@code String}. * * @param str the string to check * @return {@code true} if the given string is equal (case-sensitively) to this instance, {@code false} otherwise */ public boolean equalToString(String str) { if (str == null) return false; final byte[] bytes = this.bytes; final int length = bytes.length; if (str.length() != length) { return false; } char ch; final int end = offs + len; for (int i = offs; i < end; i++) { ch = str.charAt(i); if (ch > 0xff || bytes[i] != (byte) str.charAt(i)) { return false; } } return true; } /** * Determine whether this {@code ByteString} is equal (case-insensitively) to the given {@code String}. * * @param str the string to check * @return {@code true} if the given string is equal (case-insensitively) to this instance, {@code false} otherwise */ public boolean equalToStringIgnoreCase(String str) { if (str == null) return false; final byte[] bytes = this.bytes; final int length = bytes.length; if (str.length() != length) { return false; } char ch; final int end = offs + len; for (int i = offs; i < end; i++) { ch = str.charAt(i); if (ch > 0xff || upperCase(bytes[i]) != upperCase((byte) ch)) { return false; } } return true; } /** * Get the index of the given character in this string. * * @param c the character * @return the index, or -1 if it was not found */ public int indexOf(final char c) { return indexOf(c, 0); } /** * Get the index of the given character in this string. * * @param c the character * @return the index, or -1 if it was not found */ public int indexOf(final char c, int start) { if (c > 255) { return -1; } final int len = this.len; if (start > len) { return -1; } start = max(0, start) + offs; final byte[] bytes = this.bytes; final byte bc = (byte) c; final int end = start + len; for (int i = start; i < end; i++) { if (bytes[i] == bc) { return i; } } return -1; } /** * Get the last index of the given character in this string. * * @param c the character * @return the index, or -1 if it was not found */ public int lastIndexOf(final char c) { return lastIndexOf(c, length() - 1); } /** * Get the last index of the given character in this string. * * @param c the character * @return the index, or -1 if it was not found */ public int lastIndexOf(final char c, int start) { if (c > 255) { return -1; } final byte[] bytes = this.bytes; final int offs = this.offs; start = min(start, len - 1) + offs; final byte bc = (byte) c; for (int i = start; i >= offs; --i) { if (bytes[i] == bc) { return i; } } return -1; } // Linear array searches private static int arrayIndexOf(byte[] a, int aOffs, byte[] b, int bOffs, int bLen) { final int aLen = a.length - aOffs; if (bLen > aLen || aLen < 0) { return -1; } aOffs = max(0, aOffs); if (bLen == 0) { return aOffs; } final byte startByte = b[bOffs]; final int limit = aLen - bLen; OUTER: for (int i = aOffs; i < limit; i ++) { if (a[i] == startByte) { for (int j = 1; j < bLen; j ++) { if (a[i + j] != b[j + bOffs]) { continue OUTER; } } return i; } } return -1; } private static int arrayIndexOf(byte[] a, int aOffs, String string) { final int aLen = a.length - aOffs; final int bLen = string.length(); if (bLen > aLen || aLen < 0) { return -1; } aOffs = max(0, aOffs); if (bLen == 0) { return aOffs; } final char startChar = string.charAt(0); if (startChar > 0xff) { return -1; } char ch; final int limit = aLen - bLen; OUTER: for (int i = aOffs; i < limit; i ++) { if (a[i] == startChar) { for (int j = 1; j < bLen; j ++) { ch = string.charAt(j); if (ch > 0xff) { return -1; } if (a[i + j] != ch) { continue OUTER; } } return i; } } return -1; } private static int arrayIndexOfIgnoreCase(byte[] a, int aOffs, byte[] b, int bOffs, int bLen) { final int aLen = a.length - aOffs; if (bLen > aLen || aLen < 0) { return -1; } aOffs = max(0, aOffs); if (bLen == 0) { return aOffs; } final int startChar = upperCase(b[bOffs]); final int limit = aLen - bLen; OUTER: for (int i = aOffs; i < limit; i ++) { if (upperCase(a[i]) == startChar) { for (int j = 1; j < bLen; j ++) { if (upperCase(a[i + j]) != upperCase(b[j + bOffs])) { continue OUTER; } } return i; } } return -1; } private static int arrayIndexOfIgnoreCase(byte[] a, int aOffs, String string) { final int aLen = a.length - aOffs; final int bLen = string.length(); if (bLen > aLen || aLen < 0) { return -1; } aOffs = max(0, aOffs); if (bLen == 0) { return aOffs; } final char startChar = string.charAt(0); if (startChar > 0xff) { return -1; } final int startCP = upperCase((byte) startChar); final int limit = aLen - bLen; char ch; OUTER: for (int i = aOffs; i < limit; i ++) { if (upperCase(a[i]) == startCP) { for (int j = 1; j < bLen; j ++) { ch = string.charAt(j); if (ch > 0xff) { return -1; } // technically speaking, 'ı' (0x131) maps to I and 'ſ' (0x17F) maps to S, but this is unlikely to come up in ISO-8859-1 if (upperCase(a[i + j]) != upperCase((byte) ch)) { continue OUTER; } } return i; } } return -1; } private static int arrayLastIndexOf(byte[] a, int aOffs, byte[] b, final int bOffs, final int bLen) { final int aLen = a.length - aOffs; if (bLen > aLen || aLen < 0 || aOffs < 0) { return -1; } // move to the last possible position it could be aOffs = min(aLen - bLen, aOffs); if (bLen == 0) { return aOffs; } final byte startByte = b[0]; OUTER: for (int i = aOffs - 1; i >= 0; i --) { if (a[i] == startByte) { for (int j = 1; j < bLen; j++) { if (a[i + j] != b[bOffs + j]) { continue OUTER; } return i; } } } return -1; } private static int arrayLastIndexOf(byte[] a, int aOffs, String string) { final int aLen = a.length - aOffs; final int bLen = string.length(); if (bLen > aLen || aLen < 0 || aOffs < 0) { return -1; } // move to the last possible position it could be aOffs = min(aLen - bLen, aOffs); if (bLen == 0) { return aOffs; } final char startChar = string.charAt(0); if (startChar > 0xff) { return -1; } final byte startByte = (byte) startChar; char ch; OUTER: for (int i = aOffs - 1; i >= 0; i --) { if (a[i] == startByte) { for (int j = 1; j < bLen; j++) { ch = string.charAt(j); if (ch > 0xff) { return -1; } if (a[i + j] != (byte) ch) { continue OUTER; } return i; } } } return -1; } private static int arrayLastIndexOfIgnoreCase(byte[] a, int aOffs, byte[] b, final int bOffs, final int bLen) { final int aLen = a.length - aOffs; if (bLen > aLen || aLen < 0 || aOffs < 0) { return -1; } // move to the last possible position it could be aOffs = min(aLen - bLen, aOffs); if (bLen == 0) { return aOffs; } final int startCP = upperCase(b[bOffs]); OUTER: for (int i = aOffs - 1; i >= 0; i --) { if (upperCase(a[i]) == startCP) { for (int j = 1; j < bLen; j++) { if (upperCase(a[i + j]) != upperCase(b[j + bOffs])) { continue OUTER; } return i; } } } return -1; } private static int arrayLastIndexOfIgnoreCase(byte[] a, int aOffs, String string) { final int aLen = a.length - aOffs; final int bLen = string.length(); if (bLen > aLen || aLen < 0 || aOffs < 0) { return -1; } // move to the last possible position it could be aOffs = min(aLen - bLen, aOffs); if (bLen == 0) { return aOffs; } final char startChar = string.charAt(0); if (startChar > 0xff) { return -1; } final int startCP = upperCase((byte) startChar); char ch; OUTER: for (int i = aOffs - 1; i >= 0; i --) { if (upperCase(a[i]) == startCP) { for (int j = 1; j < bLen; j++) { ch = string.charAt(j); if (ch > 0xff) { return -1; } // technically speaking, 'ı' (0x131) maps to I and 'ſ' (0x17F) maps to S, but this is unlikely to come up in ISO-8859-1 if (upperCase(a[i + j]) != upperCase((byte) ch)) { continue OUTER; } return i; } } } return -1; } /** * Determine whether this string contains another string (case-sensitive). * * @param other the string to test * @return {@code true} if this string contains {@code other}, {@code false} otherwise */ public boolean contains(final ByteString other) { if (other == this) return true; if (other == null) return false; final byte[] otherBytes = other.bytes; return arrayIndexOf(bytes, offs, otherBytes, other.offs, other.len) != -1; } /** * Determine whether this string contains another string (case-sensitive). * * @param other the string to test * @return {@code true} if this string contains {@code other}, {@code false} otherwise */ public boolean contains(final String other) { return other != null && toString().contains(other); } /** * Determine whether this string contains another string (case-insensitive). * * @param other the string to test * @return {@code true} if this string contains {@code other}, {@code false} otherwise */ public boolean containsIgnoreCase(final ByteString other) { return other == this || other != null && arrayIndexOfIgnoreCase(bytes, offs, other.bytes, other.offs, other.len) != -1; } /** * Determine whether this string contains another string (case-sensitive). * * @param other the string to test * @return {@code true} if this string contains {@code other}, {@code false} otherwise */ public boolean containsIgnoreCase(final String other) { return arrayIndexOfIgnoreCase(bytes, offs, other) != -1; } public int indexOf(final ByteString other) { return arrayIndexOf(bytes, offs, other.bytes, other.offs, other.len); } public int indexOf(final ByteString other, int start) { if (start > len) return -1; if (start < 0) start = 0; return arrayIndexOf(bytes, offs + start, other.bytes, other.offs, other.len); } public int indexOf(final String other) { return arrayIndexOf(bytes, offs, other); } public int indexOf(final String other, int start) { if (start > len) return -1; if (start < 0) start = 0; return arrayIndexOf(bytes, offs + start, other); } public int indexOfIgnoreCase(final ByteString other) { return arrayIndexOfIgnoreCase(bytes, offs, other.bytes, other.offs, other.len); } public int indexOfIgnoreCase(final ByteString other, int start) { if (start > len) return -1; if (start < 0) start = 0; return arrayIndexOfIgnoreCase(bytes, offs + start, other.bytes, other.offs, other.len); } public int indexOfIgnoreCase(final String other) { return arrayIndexOfIgnoreCase(bytes, offs, other); } public int indexOfIgnoreCase(final String other, int start) { if (start > len) return -1; if (start < 0) start = 0; return arrayIndexOfIgnoreCase(bytes, offs + start, other); } public int lastIndexOf(final ByteString other) { return arrayLastIndexOf(bytes, offs, other.bytes, other.offs, other.len); } public int lastIndexOf(final ByteString other, int start) { if (start > len) return -1; if (start < 0) start = 0; return arrayLastIndexOf(bytes, offs + start, other.bytes, other.offs, other.len); } public int lastIndexOf(final String other) { return arrayLastIndexOf(bytes, offs, other); } public int lastIndexOf(final String other, int start) { return arrayLastIndexOf(bytes, offs + start, other); } public int lastIndexOfIgnoreCase(final ByteString other) { return arrayLastIndexOfIgnoreCase(bytes, offs, other.bytes, other.offs, other.len); } public int lastIndexOfIgnoreCase(final ByteString other, int start) { if (start > len) return -1; if (start < 0) start = 0; return arrayLastIndexOfIgnoreCase(bytes, offs + start, other.bytes, other.offs, other.len); } public int lastIndexOfIgnoreCase(final String other) { return arrayLastIndexOfIgnoreCase(bytes, offs, other); } public int lastIndexOfIgnoreCase(final String other, int start) { return arrayLastIndexOfIgnoreCase(bytes, offs + start, other); } public boolean regionMatches(boolean ignoreCase, int offset, byte[] other, int otherOffset, int len) { if (offset < 0 || otherOffset < 0 || offset + len > this.len || otherOffset + len > other.length) { return false; } if (ignoreCase) { return equalsIgnoreCase(bytes, offset + offs, other, otherOffset, len); } else { return equals(bytes, offset + offs, other, otherOffset, len); } } public boolean regionMatches(boolean ignoreCase, int offset, ByteString other, int otherOffset, int len) { if (offset < 0 || otherOffset < 0 || offset + len > this.len || otherOffset + len > other.len) { return false; } if (ignoreCase) { return equalsIgnoreCase(bytes, offset + offs, other.bytes, otherOffset, len); } else { return equals(bytes, offset + offs, other.bytes, otherOffset, len); } } public boolean regionMatches(boolean ignoreCase, int offset, String other, int otherOffset, int len) { if (offset < 0 || otherOffset < 0 || offset + len > this.len || otherOffset + len > other.length()) { return false; } if (ignoreCase) { return equalsIgnoreCase(bytes, offset + offs, other, otherOffset, len); } else { return equals(bytes, offset + offs, other, otherOffset, len); } } private static boolean equalsIgnoreCase(final byte[] a, int aOffs, String string, int stringOffset, int length) { char ch; for (int i = 0; i < length; i ++) { ch = string.charAt(i + stringOffset); if (ch > 0xff) { return false; } if (a[i + aOffs] != (byte) ch) { return false; } } return true; } private static boolean equals(final byte[] a, int aOffs, String string, int stringOffset, int length) { char ch; for (int i = 0; i < length; i ++) { ch = string.charAt(i + stringOffset); if (ch > 0xff) { return false; } if (upperCase(a[i + aOffs]) != upperCase((byte) ch)) { return false; } } return true; } public boolean startsWith(ByteString prefix) { return regionMatches(false, 0, prefix, 0, prefix.length()); } public boolean startsWith(String prefix) { return regionMatches(false, 0, prefix, 0, prefix.length()); } public boolean startsWith(char prefix) { return prefix <= 0xff && len > 0 && bytes[offs] == (byte) prefix; } public boolean startsWithIgnoreCase(ByteString prefix) { return regionMatches(true, 0, prefix, 0, prefix.length()); } public boolean startsWithIgnoreCase(String prefix) { return regionMatches(true, 0, prefix, 0, prefix.length()); } public boolean startsWithIgnoreCase(char prefix) { return prefix <= 0xff && len > 0 && upperCase(bytes[offs]) == upperCase((byte) prefix); } public boolean endsWith(ByteString suffix) { final int suffixLength = suffix.len; return regionMatches(false, len - suffixLength, suffix, 0, suffixLength); } public boolean endsWith(String suffix) { final int suffixLength = suffix.length(); return regionMatches(false, len - suffixLength, suffix, 0, suffixLength); } public boolean endsWith(char suffix) { final int len = this.len; return suffix <= 0xff && len > 0 && bytes[offs + len - 1] == (byte) suffix; } public boolean endsWithIgnoreCase(ByteString suffix) { final int suffixLength = suffix.length(); return regionMatches(true, len - suffixLength, suffix, 0, suffixLength); } public boolean endsWithIgnoreCase(String suffix) { final int suffixLength = suffix.length(); return regionMatches(true, len - suffixLength, suffix, 0, suffixLength); } public boolean endsWithIgnoreCase(char suffix) { final int len = this.len; return suffix <= 0xff && len > 0 && upperCase(bytes[offs + len - 1]) == upperCase((byte) suffix); } public ByteString concat(byte[] suffixBytes) { return concat(suffixBytes, 0, suffixBytes.length); } public ByteString concat(byte[] suffixBytes, int offs, int len) { if (len <= 0) { return this; } final int length = this.len; byte[] newBytes = Arrays.copyOfRange(bytes, this.offs, length + len); System.arraycopy(suffixBytes, offs, newBytes, length, len); return new ByteString(newBytes); } public ByteString concat(ByteString suffix) { return concat(suffix.bytes, suffix.offs, suffix.len); } public ByteString concat(ByteString suffix, int offs, int len) { return concat(suffix.bytes, offs + suffix.offs, min(len, suffix.len)); } public ByteString concat(String suffix) { return concat(suffix, 0, suffix.length()); } @SuppressWarnings("deprecation") private static byte[] getStringBytes(final boolean trust, final byte[] dst, final int dstOffs, final String src, final int srcOffs, final int len) { if (trust) { src.getBytes(srcOffs, srcOffs + len, dst, dstOffs); } else { for (int i = srcOffs; i < len; i++) { char c = src.charAt(i); if (c > 0xff) { throw new IllegalArgumentException("Invalid string contents"); } dst[i + dstOffs] = (byte) c; } } return dst; } public ByteString concat(String suffix, int offs, int len) { if (len <= 0) { return this; } final byte[] bytes = this.bytes; final int length = this.len; byte[] newBytes = Arrays.copyOfRange(bytes, offs, offs + length + len); getStringBytes(false, newBytes, length, suffix, offs, len); return new ByteString(newBytes); } public static ByteString concat(String prefix, ByteString suffix) { final int prefixLength = prefix.length(); final byte[] suffixBytes = suffix.bytes; final int suffixLength = suffixBytes.length; final byte[] newBytes = new byte[prefixLength + suffixLength]; getStringBytes(false, newBytes, 0, prefix, 0, prefixLength); System.arraycopy(suffixBytes, suffix.offs, newBytes, prefixLength, suffixLength); return new ByteString(newBytes); } public static ByteString concat(String prefix, String suffix) { final int prefixLength = prefix.length(); final int suffixLength = suffix.length(); final byte[] newBytes = new byte[prefixLength + suffixLength]; getStringBytes(false, newBytes, 0, prefix, 0, prefixLength); getStringBytes(false, newBytes, prefixLength, suffix, 0, suffixLength); return new ByteString(newBytes); } public char charAt(final int index) { if (index < 0 || index > len) { throw new ArrayIndexOutOfBoundsException(); } return (char) (bytes[index + offs] & 0xff); } public ByteString subSequence(final int start, final int end) { return substring(start, end); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/Cancellable.java000066400000000000000000000004071257016060700235320ustar00rootroot00000000000000 package org.xnio; /** * An operation which may be cancelled. */ public interface Cancellable { /** * Cancel an operation. The actual cancel may be synchronous or asynchronous. * * @return this instance */ Cancellable cancel(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/ChainedChannelListener.java000066400000000000000000000015111257016060700256740ustar00rootroot00000000000000 package org.xnio; import java.nio.channels.Channel; /** * A channel listener that chains calls to a number of other channel listeners. * * @author David M. Lloyd */ public final class ChainedChannelListener implements ChannelListener { private final ChannelListener[] listeners; /** * Construct a new instance. The given array will be copied. * * @param listeners the listeners to chain to */ public ChainedChannelListener(final ChannelListener... listeners) { this.listeners = listeners.clone(); } public void handleEvent(final T channel) { for (ChannelListener listener : listeners) { ChannelListeners.invokeChannelListener(channel, listener); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/ChannelDestination.java000066400000000000000000000017741257016060700251270ustar00rootroot00000000000000 package org.xnio; import java.nio.channels.Channel; import org.xnio.channels.BoundChannel; /** * A channel destination. This is the inverse of {@code ChannelSource}; it is used to accept a single connection from a remote * peer. * * @param the channel type * * @since 1.2 */ public interface ChannelDestination { /** * Accept a connection. The bind listener will be called when the channel is bound; the open listener will be called * when the connection is accepted. It is not guaranteed that the open listener will be called after the bind listener. * * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param bindListener the listener which will be notified when the channel is bound locally, or {@code null} for none * @return the future connection */ IoFuture accept(ChannelListener openListener, ChannelListener bindListener); } xnio-3.3.2.Final/api/src/main/java/org/xnio/ChannelExceptionHandler.java000066400000000000000000000010301257016060700260630ustar00rootroot00000000000000 package org.xnio; import java.io.IOException; import java.nio.channels.Channel; import java.util.EventListener; /** * An exception handler for utility channel listeners. * * @author David M. Lloyd */ public interface ChannelExceptionHandler extends EventListener { /** * Handle an exception on the channel. * * @param channel the channel * @param exception the exception */ void handleException(T channel, IOException exception); } xnio-3.3.2.Final/api/src/main/java/org/xnio/ChannelListener.java000066400000000000000000000052431257016060700244260ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2009 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.nio.channels.Channel; import java.util.EventListener; import org.jboss.logging.Logger; import static org.xnio._private.Messages.listenerMsg; /** * A listener for channel events. Possible channel events include: channel readable, channel writable, channel * opened, channel closed, channel bound, channel unbound. * * @param the channel type * * @since 2.0 */ public interface ChannelListener extends EventListener { /** * Handle the event on this channel. * * @param channel the channel event */ void handleEvent(T channel); /** * A setter for a channel listener. The indirection is necessary * because while covariance is supported on return types, contravariance is not supported on parameters. * * @param the channel type * * @since 2.0 */ interface Setter { /** * Set the listener, or {@code null} to ignore the associated event type. * * @param listener the new listener */ void set(ChannelListener listener); } /** * A simple implementation of {@link Setter}. * * @param the channel type * * @since 3.0 */ class SimpleSetter implements Setter { private ChannelListener channelListener; /** {@inheritDoc} */ public void set(final ChannelListener listener) { listenerMsg.logf(SimpleSetter.class.getName(), Logger.Level.TRACE, null, "Setting channel listener to %s", listener); channelListener = listener; } /** * Get the channel listener set on this setter. * * @return the channel listener */ public ChannelListener get() { return channelListener; } public String toString() { return "Simple channel listener setter (currently=" + channelListener + ")"; } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/ChannelListeners.java000066400000000000000000001357221257016060700246170ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import java.io.Closeable; import java.io.EOFException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.Channel; import java.nio.channels.FileChannel; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.Channels; import org.xnio.channels.ConnectedChannel; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; import org.xnio.channels.SuspendableReadChannel; import org.xnio.channels.SuspendableWriteChannel; import org.xnio.channels.WritableMessageChannel; import static org.xnio._private.Messages.listenerMsg; import static org.xnio._private.Messages.msg; /** * Channel listener utility methods. * * @author David M. Lloyd */ @SuppressWarnings("unused") public final class ChannelListeners { private static final ChannelListener NULL_LISTENER = new ChannelListener() { public void handleEvent(final Channel channel) { } public String toString() { return "Null channel listener"; } }; private static final ChannelListener.Setter NULL_SETTER = new ChannelListener.Setter() { public void set(final ChannelListener channelListener) { } public String toString() { return "Null channel listener setter"; } }; private static ChannelListener CLOSING_CHANNEL_LISTENER = new ChannelListener() { public void handleEvent(final Channel channel) { IoUtils.safeClose(channel); } public String toString() { return "Closing channel listener"; } }; private ChannelListeners() { } /** * Invoke a channel listener on a given channel, logging any errors. * * @param channel the channel * @param channelListener the channel listener * @param the channel type * @return {@code true} if the listener completed successfully, or {@code false} if it failed */ public static boolean invokeChannelListener(T channel, ChannelListener channelListener) { if (channelListener != null) try { listenerMsg.tracef("Invoking listener %s on channel %s", channelListener, channel); channelListener.handleEvent(channel); } catch (Throwable t) { listenerMsg.listenerException(t); return false; } return true; } /** * Invoke a channel listener on a given channel, logging any errors, using the given executor. * * @param executor the executor * @param channel the channel * @param channelListener the channel listener * @param the channel type */ public static void invokeChannelListener(Executor executor, T channel, ChannelListener channelListener) { try { executor.execute(getChannelListenerTask(channel, channelListener)); } catch (RejectedExecutionException ree) { invokeChannelListener(channel, channelListener); } } /** * Safely invoke a channel exception handler, logging any errors. * * @param channel the channel * @param exceptionHandler the exception handler * @param exception the exception to pass in * @param the exception type */ public static void invokeChannelExceptionHandler(final T channel, final ChannelExceptionHandler exceptionHandler, final IOException exception) { try { exceptionHandler.handleException(channel, exception); } catch (Throwable t) { listenerMsg.exceptionHandlerException(t); } } /** * Get a task which invokes the given channel listener on the given channel. * * @param channel the channel * @param channelListener the channel listener * @param the channel type * @return the runnable task */ public static Runnable getChannelListenerTask(final T channel, final ChannelListener channelListener) { return new Runnable() { public String toString() { return "Channel listener task for " + channel + " -> " + channelListener; } public void run() { invokeChannelListener(channel, channelListener); } }; } /** * Get a task which invokes the given channel listener on the given channel via its setter. * * @param channel the channel * @param setter the setter for the channel listener * @param the channel type * @return the runnable task */ public static Runnable getChannelListenerTask(final T channel, final ChannelListener.SimpleSetter setter) { return new Runnable() { public String toString() { return "Channel listener task for " + channel + " -> " + setter; } public void run() { invokeChannelListener(channel, setter.get()); } }; } /** * Get a channel listener which closes the channel when notified. * * @return the channel listener */ public static ChannelListener closingChannelListener() { return CLOSING_CHANNEL_LISTENER; } /** * Get a channel listener which closes the given resource when notified. * * @param resource the resource to close * @return the channel listener */ public static ChannelListener closingChannelListener(final Closeable resource) { return new ChannelListener() { public void handleEvent(final Channel channel) { IoUtils.safeClose(resource); } public String toString() { return "Closing channel listener for " + resource; } }; } /** * Get a channel listener which closes the given resources when notified. * * @param resources the resources to close * @return the channel listener */ public static ChannelListener closingChannelListener(final Closeable... resources) { return new ChannelListener() { public void handleEvent(final Channel channel) { IoUtils.safeClose(resources); } public String toString() { return "Closing channel listener for " + resources.length + " items"; } }; } /** * Get a channel listener which closes the given resource when notified. * * @param delegate the listener to call next * @param resource the resource to close * @return the channel listener */ public static ChannelListener closingChannelListener(final ChannelListener delegate, final Closeable resource) { return new ChannelListener() { public void handleEvent(final T channel) { IoUtils.safeClose(resource); delegate.handleEvent(channel); } public String toString() { return "Closing channel listener for " + resource + " -> " + delegate; } }; } /** * Get a channel listener which closes the given resource when notified. * * @param delegate the listener to call next * @param resources the resource to close * @return the channel listener */ public static ChannelListener closingChannelListener(final ChannelListener delegate, final Closeable... resources) { return new ChannelListener() { public void handleEvent(final T channel) { IoUtils.safeClose(resources); delegate.handleEvent(channel); } public String toString() { return "Closing channel listener for " + resources.length + " items -> " + delegate; } }; } /** * Get a channel listener which does nothing. * * @return the null channel listener */ public static ChannelListener nullChannelListener() { return NULL_LISTENER; } /** * Get a channel exception handler which closes the channel upon exception. * * @return the channel exception handler */ public static ChannelExceptionHandler closingChannelExceptionHandler() { return CLOSING_HANDLER; } /** * Create an open listener adapter which automatically accepts connections and invokes an open listener. * * @param openListener the channel open listener * @param the connected channel type * @return a channel accept listener */ public static ChannelListener> openListenerAdapter(final ChannelListener openListener) { if (openListener == null) { throw msg.nullParameter("openListener"); } return new ChannelListener>() { public void handleEvent(final AcceptingChannel channel) { try { final C accepted = channel.accept(); if (accepted != null) { invokeChannelListener(accepted, openListener); } } catch (IOException e) { listenerMsg.acceptFailed(channel, e); } } public String toString() { return "Accepting listener for " + openListener; } }; } /** * Get a setter based on an atomic reference field updater. Used by channel implementations to avoid having to * define an anonymous class for each listener field. * * @param channel the channel * @param updater the updater * @param the channel type * @param the holding class * @return the setter * @deprecated Not recommended as a security manager will enforce unreasonable restrictions on the updater. */ @Deprecated public static ChannelListener.Setter getSetter(final C channel, final AtomicReferenceFieldUpdater updater) { return new ChannelListener.Setter() { public void set(final ChannelListener channelListener) { updater.set(channel, channelListener); } public String toString() { return "Atomic reference field updater setter for " + updater; } }; } /** * Get a setter based on an atomic reference. Used by channel implementations to avoid having to * define an anonymous class for each listener field. * * @param atomicReference the atomic reference * @param the channel type * @return the setter */ public static ChannelListener.Setter getSetter(final AtomicReference> atomicReference) { return new ChannelListener.Setter() { public void set(final ChannelListener channelListener) { atomicReference.set(channelListener); } public String toString() { return "Atomic reference setter (currently=" + atomicReference.get() + ")"; } }; } /** * Get a channel listener setter which delegates to the given target setter with a different channel type. * * @param target the target setter * @param realChannel the channel to send in to the listener * @param the real channel type * @return the delegating setter */ public static ChannelListener.Setter getDelegatingSetter(final ChannelListener.Setter target, final T realChannel) { return target == null ? null : new DelegatingSetter(target, realChannel); } /** * Get a channel listener setter which does nothing. * * @param the channel type * @return a setter which does nothing */ @SuppressWarnings({ "unchecked" }) public static ChannelListener.Setter nullSetter() { return (ChannelListener.Setter) NULL_SETTER; } /** * Get a channel listener which executes a delegate channel listener via an executor. If an exception occurs * submitting the task, the associated channel is closed. * * @param listener the listener to invoke * @param executor the executor with which to invoke the listener * @param the channel type * @return a delegating channel listener */ public static ChannelListener executorChannelListener(final ChannelListener listener, final Executor executor) { return new ChannelListener() { public void handleEvent(final T channel) { try { executor.execute(getChannelListenerTask(channel, listener)); } catch (RejectedExecutionException e) { listenerMsg.executorSubmitFailed(e, channel); IoUtils.safeClose(channel); } } public String toString() { return "Executor channel listener -> " + listener; } }; } /** * A flushing channel listener. Flushes the channel and then calls the delegate listener. Calls the exception * handler if an exception occurs. The delegate listener should ensure that the channel write listener is appropriately set. *

* The returned listener is stateless and may be reused on any number of channels concurrently or sequentially. * * @param delegate the delegate listener * @param exceptionHandler the exception handler * @param the channel type * @return the flushing channel listener */ public static ChannelListener flushingChannelListener(final ChannelListener delegate, final ChannelExceptionHandler exceptionHandler) { return new ChannelListener() { public void handleEvent(final T channel) { final boolean result; try { result = channel.flush(); } catch (IOException e) { channel.suspendWrites(); invokeChannelExceptionHandler(channel, exceptionHandler, e); return; } if (result) { Channels.setWriteListener(channel, delegate); invokeChannelListener(channel, delegate); } else { Channels.setWriteListener(channel, this); channel.resumeWrites(); } } public String toString() { return "Flushing channel listener -> " + delegate; } }; } /** * A write shutdown channel listener. Shuts down and flushes the channel and calls the delegate listener. Calls * the exception handler if an exception occurs. When the delegate listener is called, the channel's write side will be shut down and flushed. * The delegate listener should ensure that the channel write listener is appropriately set. * * @param delegate the delegate listener * @param exceptionHandler the exception handler * @param the channel type * @return the channel listener */ public static ChannelListener writeShutdownChannelListener(final ChannelListener delegate, final ChannelExceptionHandler exceptionHandler) { final ChannelListener flushingListener = flushingChannelListener(delegate, exceptionHandler); return new ChannelListener() { public void handleEvent(final T channel) { try { channel.shutdownWrites(); } catch (IOException e) { invokeChannelExceptionHandler(channel, exceptionHandler, e); return; } invokeChannelListener(channel, flushingListener); } public String toString() { return "Write shutdown channel listener -> " + delegate; } }; } /** * A writing channel listener. Writes the buffer to the channel and then calls the delegate listener. Calls the exception * handler if an exception occurs. The delegate listener should ensure that the channel write listener is appropriately set. *

* The returned listener is stateful and will not execute properly if reused. * * @param pooled the buffer to write * @param delegate the delegate listener * @param exceptionHandler the exception handler * @param the channel type * @return the writing channel listener */ public static ChannelListener writingChannelListener(final Pooled pooled, final ChannelListener delegate, final ChannelExceptionHandler exceptionHandler) { return new ChannelListener() { public void handleEvent(final T channel) { final ByteBuffer buffer = pooled.getResource(); int result; boolean ok = false; do { try { result = channel.write(buffer); ok = true; } catch (IOException e) { channel.suspendWrites(); pooled.free(); invokeChannelExceptionHandler(channel, exceptionHandler, e); return; } finally { if (! ok) { pooled.free(); } } if (result == 0) { Channels.setWriteListener(channel, this); channel.resumeWrites(); return; } } while (buffer.hasRemaining()); pooled.free(); invokeChannelListener(channel, delegate); } public String toString() { return "Writing channel listener -> " + delegate; } }; } /** * A sending channel listener. Writes the buffer to the channel and then calls the delegate listener. Calls the exception * handler if an exception occurs. The delegate listener should ensure that the channel write listener is appropriately set. *

* The returned listener is stateful and will not execute properly if reused. * * @param pooled the buffer to send * @param delegate the delegate listener * @param exceptionHandler the exception handler * @param the channel type * @return the sending channel listener */ public static ChannelListener sendingChannelListener(final Pooled pooled, final ChannelListener delegate, final ChannelExceptionHandler exceptionHandler) { return new ChannelListener() { public void handleEvent(final T channel) { final ByteBuffer buffer = pooled.getResource(); boolean free = true; try { if (! (free = channel.send(buffer))) { Channels.setWriteListener(channel, this); channel.resumeWrites(); return; } } catch (IOException e) { channel.suspendWrites(); pooled.free(); invokeChannelExceptionHandler(channel, exceptionHandler, e); return; } finally { if (free) pooled.free(); } invokeChannelListener(channel, delegate); } public String toString() { return "Sending channel listener -> " + delegate; } }; } /** * A file-sending channel listener. Writes the file to the channel and then calls the delegate listener. Calls the exception * handler if an exception occurs. The delegate listener should ensure that the channel write listener is appropriately set. *

* The returned listener is stateful and will not execute properly if reused. * * @param source the file to read from * @param position the position in the source file to read from * @param count the number of bytes to read * @param delegate the listener to call when the file is sent * @param exceptionHandler the exception handler to call if a problem occurs * @param the channel type * @return the channel listener */ public static ChannelListener fileSendingChannelListener(final FileChannel source, final long position, final long count, final ChannelListener delegate, final ChannelExceptionHandler exceptionHandler) { if (count == 0L) { return delegatingChannelListener(delegate); } return new ChannelListener() { private long p = position; private long cnt = count; public void handleEvent(final T channel) { long result; long cnt = this.cnt; long p = this.p; try { do { try { result = channel.transferFrom(source, p, cnt); } catch (IOException e) { invokeChannelExceptionHandler(channel, exceptionHandler, e); return; } if (result == 0L) { Channels.setWriteListener(channel, this); channel.resumeWrites(); return; } p += result; cnt -= result; } while (cnt > 0L); // cnt is 0 invokeChannelListener(channel, delegate); return; } finally { this.p = p; this.cnt = cnt; } } public String toString() { return "File sending channel listener (" + source + ") -> " + delegate; } }; } /** * A file-receiving channel listener. Writes the file from the channel and then calls the delegate listener. Calls the exception * handler if an exception occurs. The delegate listener should ensure that the channel read listener is appropriately set. *

* The returned listener is stateful and will not execute properly if reused. * * @param target the file to write to * @param position the position in the target file to write to * @param count the number of bytes to write * @param delegate the listener to call when the file is sent * @param exceptionHandler the exception handler to call if a problem occurs * @param the channel type * @return the channel listener */ public static ChannelListener fileReceivingChannelListener(final FileChannel target, final long position, final long count, final ChannelListener delegate, final ChannelExceptionHandler exceptionHandler) { if (count == 0L) { return delegatingChannelListener(delegate); } return new ChannelListener() { private long p = position; private long cnt = count; public void handleEvent(final T channel) { long result; long cnt = this.cnt; long p = this.p; try { do { try { result = channel.transferTo(p, cnt, target); } catch (IOException e) { invokeChannelExceptionHandler(channel, exceptionHandler, e); return; } if (result == 0L) { Channels.setReadListener(channel, this); channel.resumeReads(); return; } p += result; cnt -= result; } while (cnt > 0L); // cnt = 0 invokeChannelListener(channel, delegate); return; } finally { this.p = p; this.cnt = cnt; } } public String toString() { return "File receiving channel listener (" + target + ") -> " + delegate; } }; } /** * A delegating channel listener which passes an event to another listener of the same or a super type. * * @param delegate the delegate channel listener * @param the channel type * @return the listener */ public static ChannelListener delegatingChannelListener(final ChannelListener delegate) { return new ChannelListener() { public void handleEvent(final T channel) { invokeChannelListener(channel, delegate); } public String toString() { return "Delegating channel listener -> " + delegate; } }; } /** * A delegating channel listener which passes an event to the listener stored in the given setter. * * @param channel the channel to pass in * @param setter the channel listener setter * @param the listener channel type * @param the passed in channel type * @return the listener */ public static ChannelListener delegatingChannelListener(final T channel, final ChannelListener.SimpleSetter setter) { return new SetterDelegatingListener(setter, channel); } /** * A write-suspending channel listener. The returned listener will suspend writes when called. Useful for chaining * writing listeners to a flush listener to this listener. The delegate listener should ensure that the channel write listener is appropriately set. * * @param delegate the delegate channel listener * @return the suspending channel listener */ public static ChannelListener writeSuspendingChannelListener(final ChannelListener delegate) { return new ChannelListener() { public void handleEvent(final T channel) { channel.suspendWrites(); invokeChannelListener(channel, delegate); } public String toString() { return "Write-suspending channel listener -> " + delegate; } }; } /** * A read-suspending channel listener. The returned listener will suspend read when called. * The delegate listener should ensure that the channel read listener is appropriately set. * * @param delegate the delegate channel listener * @return the suspending channel listener */ public static ChannelListener readSuspendingChannelListener(final ChannelListener delegate) { return new ChannelListener() { public void handleEvent(final T channel) { channel.suspendReads(); invokeChannelListener(channel, delegate); } public String toString() { return "Read-suspending channel listener -> " + delegate; } }; } static final class TransferListener implements ChannelListener { private final Pooled pooledBuffer; private final I source; private final O sink; private final ChannelListener sourceListener; private final ChannelListener sinkListener; private final ChannelExceptionHandler writeExceptionHandler; private final ChannelExceptionHandler readExceptionHandler; private long count; private volatile int state; TransferListener(final long count, final Pooled pooledBuffer, final I source, final O sink, final ChannelListener sourceListener, final ChannelListener sinkListener, final ChannelExceptionHandler writeExceptionHandler, final ChannelExceptionHandler readExceptionHandler, final int state) { this.count = count; this.pooledBuffer = pooledBuffer; this.source = source; this.sink = sink; this.sourceListener = sourceListener; this.sinkListener = sinkListener; this.writeExceptionHandler = writeExceptionHandler; this.readExceptionHandler = readExceptionHandler; this.state = state; } public void handleEvent(final Channel channel) { final ByteBuffer buffer = pooledBuffer.getResource(); int state = this.state; // always read after and write before state long count = this.count; long lres; int ires; switch (state) { case 0: { // read listener for (;;) { try { lres = source.transferTo(count, buffer, sink); } catch (IOException e) { readFailed(e); return; } if (lres == 0 && !buffer.hasRemaining()) { this.count = count; return; } if (lres == -1) { // possibly unexpected EOF if (count == Long.MAX_VALUE) { // it's OK; just be done done(); return; } else { readFailed(new EOFException()); return; } } if (count != Long.MAX_VALUE) { count -= lres; } while (buffer.hasRemaining()) { try { ires = sink.write(buffer); } catch (IOException e) { writeFailed(e); return; } if (count != Long.MAX_VALUE) { count -= ires; } if (ires == 0) { this.count = count; this.state = 1; source.suspendReads(); sink.resumeWrites(); return; } } if (count == 0) { done(); return; } } } case 1: { // write listener for (;;) { while (buffer.hasRemaining()) { try { ires = sink.write(buffer); } catch (IOException e) { writeFailed(e); return; } if (count != Long.MAX_VALUE) { count -= ires; } if (ires == 0) { return; } } try { lres = source.transferTo(count, buffer, sink); } catch (IOException e) { readFailed(e); return; } if (lres == 0 && !buffer.hasRemaining()) { this.count = count; this.state = 0; sink.suspendWrites(); source.resumeReads(); return; } if (lres == -1) { // possibly unexpected EOF if (count == Long.MAX_VALUE) { // it's OK; just be done done(); return; } else { readFailed(new EOFException()); return; } } if (count != Long.MAX_VALUE) { count -= lres; } if (count == 0) { done(); return; } } } } } private void writeFailed(final IOException e) { try { source.suspendReads(); sink.suspendWrites(); invokeChannelExceptionHandler(sink, writeExceptionHandler, e); } finally { pooledBuffer.free(); } } private void readFailed(final IOException e) { try { source.suspendReads(); sink.suspendWrites(); invokeChannelExceptionHandler(source, readExceptionHandler, e); } finally { pooledBuffer.free(); } } private void done() { try { final ChannelListener sourceListener = this.sourceListener; final ChannelListener sinkListener = this.sinkListener; final I source = this.source; final O sink = this.sink; Channels.setReadListener(source, sourceListener); if (sourceListener == null) { source.suspendReads(); } else { source.wakeupReads(); } Channels.setWriteListener(sink, sinkListener); if (sinkListener == null) { sink.suspendWrites(); } else { sink.wakeupWrites(); } } finally { pooledBuffer.free(); } } public String toString() { return "Transfer channel listener (" + source + " to " + sink + ") -> (" + sourceListener + " and " + sinkListener + ")"; } } /** * Initiate a low-copy transfer between two stream channels. The pool should be a direct buffer pool for best * performance. The channels will be closed when the transfer completes or if there is an error. * * @param source the source channel * @param sink the target channel * @param pool the pool from which the transfer buffer should be allocated * @param the source stream type * @param the sink stream type */ public static void initiateTransfer(final I source, final O sink, Pool pool) { initiateTransfer(Long.MAX_VALUE, source, sink, CLOSING_CHANNEL_LISTENER, CLOSING_CHANNEL_LISTENER, CLOSING_HANDLER, CLOSING_HANDLER, pool); } /** * Initiate a low-copy transfer between two stream channels. The pool should be a direct buffer pool for best * performance. * * @param count the number of bytes to transfer, or {@link Long#MAX_VALUE} to transfer all remaining bytes * @param source the source channel * @param sink the target channel * @param sourceListener the source listener to set and call when the transfer is complete, or {@code null} to clear the listener at that time * @param sinkListener the target listener to set and call when the transfer is complete, or {@code null} to clear the listener at that time * @param readExceptionHandler the read exception handler to call if an error occurs during a read operation * @param writeExceptionHandler the write exception handler to call if an error occurs during a write operation * @param pool the pool from which the transfer buffer should be allocated */ public static void initiateTransfer(long count, final I source, final O sink, final ChannelListener sourceListener, final ChannelListener sinkListener, final ChannelExceptionHandler readExceptionHandler, final ChannelExceptionHandler writeExceptionHandler, Pool pool) { if (pool == null) { throw msg.nullParameter("pool"); } final Pooled allocated = pool.allocate(); boolean free = true; try { final ByteBuffer buffer = allocated.getResource(); long transferred; for(;;) { try { transferred = source.transferTo(count, buffer, sink); } catch (IOException e) { invokeChannelExceptionHandler(source, readExceptionHandler, e); return; } if (transferred == 0 && !buffer.hasRemaining()) { break; } if (transferred == -1) { if (count == Long.MAX_VALUE) { Channels.setReadListener(source, sourceListener); if (sourceListener == null) { source.suspendReads(); } else { source.wakeupReads(); } Channels.setWriteListener(sink, sinkListener); if (sinkListener == null) { sink.suspendWrites(); } else { sink.wakeupWrites(); } } else { source.suspendReads(); sink.suspendWrites(); invokeChannelExceptionHandler(source, readExceptionHandler, new EOFException()); } return; } if (count != Long.MAX_VALUE) { count -= transferred; } while (buffer.hasRemaining()) { final int res; try { res = sink.write(buffer); } catch (IOException e) { invokeChannelExceptionHandler(sink, writeExceptionHandler, e); return; } if (res == 0) { // write first listener final TransferListener listener = new TransferListener(count, allocated, source, sink, sourceListener, sinkListener, writeExceptionHandler, readExceptionHandler, 1); source.suspendReads(); source.getReadSetter().set(listener); sink.getWriteSetter().set(listener); sink.resumeWrites(); free = false; return; } else if (count != Long.MAX_VALUE) { count -= res; } } if (count == 0) { //we are done Channels.setReadListener(source, sourceListener); if (sourceListener == null) { source.suspendReads(); } else { source.wakeupReads(); } Channels.setWriteListener(sink, sinkListener); if (sinkListener == null) { sink.suspendWrites(); } else { sink.wakeupWrites(); } return; } } // read first listener final TransferListener listener = new TransferListener(count, allocated, source, sink, sourceListener, sinkListener, writeExceptionHandler, readExceptionHandler, 0); sink.suspendWrites(); sink.getWriteSetter().set(listener); source.getReadSetter().set(listener); source.resumeReads(); free = false; return; } finally { if (free) allocated.free(); } } /** * Create a channel listener which automatically drains the given number of bytes from the channel and then calls * a listener. * * @param bytes the number of bytes to drain, or {@code Long.MAX_VALUE} to drain the channel completely * @param finishListener the listener to call when the drain is complete * @param exceptionHandler the handler to call if the drain fails * @param the channel type * @return the channel listener */ public static ChannelListener drainListener(long bytes, ChannelListener finishListener, ChannelExceptionHandler exceptionHandler) { return new DrainListener(finishListener, exceptionHandler, bytes); } private static class DelegatingSetter implements ChannelListener.Setter { private final ChannelListener.Setter setter; private final T realChannel; DelegatingSetter(final ChannelListener.Setter setter, final T realChannel) { this.setter = setter; this.realChannel = realChannel; } public void set(final ChannelListener channelListener) { setter.set(channelListener == null ? null : new DelegatingChannelListener(channelListener, realChannel)); } public String toString() { return "Delegating setter -> " + setter; } } private static class DelegatingChannelListener implements ChannelListener { private final ChannelListener channelListener; private final T realChannel; public DelegatingChannelListener(final ChannelListener channelListener, final T realChannel) { this.channelListener = channelListener; this.realChannel = realChannel; } public void handleEvent(final Channel channel) { invokeChannelListener(realChannel, channelListener); } public String toString() { return "Delegating channel listener -> " + channelListener; } } private static class SetterDelegatingListener implements ChannelListener { private final SimpleSetter setter; private final T channel; public SetterDelegatingListener(final SimpleSetter setter, final T channel) { this.setter = setter; this.channel = channel; } public void handleEvent(final C channel) { invokeChannelListener(this.channel, setter.get()); } public String toString() { return "Setter delegating channel listener -> " + setter; } } private static final ChannelExceptionHandler CLOSING_HANDLER = new ChannelExceptionHandler() { public void handleException(final Channel channel, final IOException exception) { IoUtils.safeClose(channel); } }; private static class DrainListener implements ChannelListener { private final ChannelListener finishListener; private final ChannelExceptionHandler exceptionHandler; private long count; private DrainListener(final ChannelListener finishListener, final ChannelExceptionHandler exceptionHandler, final long count) { this.finishListener = finishListener; this.exceptionHandler = exceptionHandler; this.count = count; } public void handleEvent(final T channel) { try { long count = this.count; try { long res; for (;;) { res = Channels.drain(channel, count); if (res == -1 || res == count) { this.count = 0L; invokeChannelListener(channel, finishListener); return; } else if (res == 0) { return; } else if (count < Long.MAX_VALUE) { // MAX_VALUE means drain to EOF count -= res; } } } finally { this.count = count; } } catch (IOException e) { this.count = 0L; if (exceptionHandler != null) { invokeChannelExceptionHandler(channel, exceptionHandler, e); } else { IoUtils.safeShutdownReads(channel); } } } public String toString() { return "Draining channel listener (" + count + " bytes) -> " + finishListener; } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/ChannelPipe.java000066400000000000000000000031151257016060700235320ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import org.xnio.channels.CloseableChannel; /** * A one-way pipe. * * @author David M. Lloyd */ public final class ChannelPipe { private final L leftSide; private final R rightSide; /** * Construct a new instance. * * @param leftSide the pipe left side * @param rightSide the pipe right side */ public ChannelPipe(final L leftSide, final R rightSide) { this.rightSide = rightSide; this.leftSide = leftSide; } /** * Get the pipe source. * * @return the pipe source */ public L getLeftSide() { return leftSide; } /** * Get the pipe sink. * * @return the pipe sink */ public R getRightSide() { return rightSide; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/ChannelSource.java000066400000000000000000000011371257016060700240770ustar00rootroot00000000000000 package org.xnio; import java.nio.channels.Channel; /** * A channel source. Instances of this interface are used to create a channel and associate it with a listener. Example * uses are to establish a TCP connection (as a client), open a serial port, etc. * * @param the type of channel */ public interface ChannelSource { /** * Open a channel. * * @param openListener the listener which will be notified when the channel is open * @return the future result of this operation */ IoFuture open(ChannelListener openListener); } xnio-3.3.2.Final/api/src/main/java/org/xnio/ClosedWorkerException.java000066400000000000000000000045521257016060700256340ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import java.io.IOException; /** * A channel open was attempted on a closed worker. * * @author David M. Lloyd */ public class ClosedWorkerException extends IOException { /** * Constructs a {@code ClosedWorkerException} with no detail message. The cause is not initialized, and may * subsequently be initialized by a call to {@link #initCause(Throwable) initCause}. */ public ClosedWorkerException() { } /** * Constructs a {@code ClosedWorkerException} with the specified detail message. The cause is not initialized, and * may subsequently be initialized by a call to {@link #initCause(Throwable) initCause}. * * @param msg the detail message */ public ClosedWorkerException(final String msg) { super(msg); } /** * Constructs a {@code ClosedWorkerException} with the specified cause. The detail message is set to: *

(cause == null ? null : cause.toString())
* (which typically contains the class and detail message of {@code cause}). * * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) */ public ClosedWorkerException(final Throwable cause) { super(cause); } /** * Constructs a {@code ClosedWorkerException} with the specified detail message and cause. * * @param msg the detail message * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) */ public ClosedWorkerException(final String msg, final Throwable cause) { super(msg, cause); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/Closer.java000066400000000000000000000005611257016060700225750ustar00rootroot00000000000000 package org.xnio; import java.io.Closeable; /** * A {@code Runnable} that closes some resource. * * @apiviz.exclude */ public final class Closer implements Runnable { private final Closeable resource; public Closer(final Closeable resource) { this.resource = resource; } public void run() { IoUtils.safeClose(resource); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/CompressionType.java000066400000000000000000000017041257016060700245110ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2012 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; /** * Supported compression types. * * @author David M. Lloyd */ public enum CompressionType { /** * ZLIB compatible compression. */ DEFLATE, /** * GZIP compatible compression. */ GZIP, ; } xnio-3.3.2.Final/api/src/main/java/org/xnio/Connection.java000066400000000000000000000140261257016060700234460ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.io.IOException; import java.net.SocketAddress; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import org.xnio.channels.CloseableChannel; import org.xnio.channels.ConnectedChannel; import static org.xnio.Bits.allAreClear; import static org.xnio.Bits.allAreSet; import static org.xnio.Bits.anyAreClear; /** * The base for all connections. * * @author David M. Lloyd */ public abstract class Connection implements CloseableChannel, ConnectedChannel { protected final XnioIoThread thread; @SuppressWarnings("unused") private volatile int state; private static final int FLAG_READ_CLOSED = 0b0001; private static final int FLAG_WRITE_CLOSED = 0b0010; private static final AtomicIntegerFieldUpdater stateUpdater = AtomicIntegerFieldUpdater.newUpdater(Connection.class, "state"); /** * Construct a new instance. * * @param thread the I/O thread of this connection */ protected Connection(final XnioIoThread thread) { this.thread = thread; } private static A castAddress(final Class type, SocketAddress address) { return type.isInstance(address) ? type.cast(address) : null; } public final A getPeerAddress(final Class type) { return castAddress(type, getPeerAddress()); } public final A getLocalAddress(final Class type) { return castAddress(type, getLocalAddress()); } public final XnioWorker getWorker() { return thread.getWorker(); } public XnioIoThread getIoThread() { return thread; } /** * Indicate that reads have been closed on this connection. * * @return {@code true} if read closure was successfully indicated; {@code false} if this method has already been called */ protected boolean readClosed() { int oldVal, newVal; do { oldVal = state; if (allAreSet(oldVal, FLAG_READ_CLOSED)) { return false; } newVal = oldVal | FLAG_READ_CLOSED; } while (! stateUpdater.compareAndSet(this, oldVal, newVal)); if (allAreSet(newVal, FLAG_READ_CLOSED | FLAG_WRITE_CLOSED)) { try { closeAction(); } catch (Throwable ignored) {} invokeCloseListener(); } return true; } /** * Indicate that writes have been closed on this connection. * * @return {@code true} if write closure was successfully indicated; {@code false} if this method has already been called */ protected boolean writeClosed() { int oldVal, newVal; do { oldVal = state; if (allAreSet(oldVal, FLAG_WRITE_CLOSED)) { return false; } newVal = oldVal | FLAG_WRITE_CLOSED; } while (! stateUpdater.compareAndSet(this, oldVal, newVal)); if (allAreSet(newVal, FLAG_READ_CLOSED | FLAG_WRITE_CLOSED)) { try { closeAction(); } catch (Throwable ignored) {} invokeCloseListener(); } return true; } public final void close() throws IOException { int oldVal, newVal; do { oldVal = state; if (allAreSet(oldVal, FLAG_WRITE_CLOSED | FLAG_READ_CLOSED)) { return; } newVal = oldVal | FLAG_READ_CLOSED | FLAG_WRITE_CLOSED; } while (! stateUpdater.compareAndSet(this, oldVal, newVal)); try { closeAction(); } finally { if (allAreClear(oldVal, FLAG_WRITE_CLOSED)) try { notifyWriteClosed(); } catch (Throwable ignored) { } if (allAreClear(oldVal, FLAG_READ_CLOSED)) try { notifyReadClosed(); } catch (Throwable ignored) { } invokeCloseListener(); } } /** * Determine whether reads have been shut down on this connection. * * @return {@code true} if reads were shut down */ public boolean isReadShutdown() { return allAreSet(state, FLAG_READ_CLOSED); } /** * Determine whether writes have been shut down on this connection. * * @return {@code true} if writes were shut down */ public boolean isWriteShutdown() { return allAreSet(state, FLAG_WRITE_CLOSED); } public boolean isOpen() { return anyAreClear(state, FLAG_READ_CLOSED | FLAG_WRITE_CLOSED); } /** * Indicate to conduit handlers that writes have been closed. */ protected abstract void notifyWriteClosed(); /** * Indicate to conduit handlers that reads have been closed. */ protected abstract void notifyReadClosed(); abstract void invokeCloseListener(); /** * The close action to perform on this connection. * * @throws IOException if close fails */ protected void closeAction() throws IOException {} public boolean supportsOption(final Option option) { return false; } public T getOption(final Option option) throws IOException { return null; } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return null; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/DelegatingChannelListener.java000066400000000000000000000032501257016060700264060ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import java.nio.channels.Channel; /** * A base class for a channel listener which performs an action and then calls a delegate listener. * * @author David M. Lloyd */ public abstract class DelegatingChannelListener implements ChannelListener { private final ChannelListener next; /** * Construct a new instance. The next listener must be for the same type as, or a supertype of, the channel * type handleable by this listener. * * @param next the next listener */ protected DelegatingChannelListener(final ChannelListener next) { this.next = next; } /** * Call the next listener. Does not throw exceptions. * * @param channel the channel to pass to the next listener */ protected void callNext(T channel) { ChannelListeners.invokeChannelListener(channel, next); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/FailedIoFuture.java000066400000000000000000000011731257016060700242150ustar00rootroot00000000000000 package org.xnio; import java.io.IOException; /** * An implementation of {@link IoFuture} that represents an immediately-failed operation. * * @param the type of result that this operation produces */ public class FailedIoFuture extends AbstractIoFuture { /** * Create an instance. * * @param e the failure cause */ public FailedIoFuture(IOException e) { setException(e); } /** * Cancel the operation. Since this operation is always complete, this is a no-op. * * @return this instance */ public IoFuture cancel() { return this; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/FileAccess.java000066400000000000000000000022741257016060700233520ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; /** * Possible file access modes. * * @author David M. Lloyd */ public enum FileAccess { READ_ONLY(true, false), READ_WRITE(true, true), WRITE_ONLY(false, true), ; private final boolean read; private final boolean write; private FileAccess(final boolean read, final boolean write) { this.read = read; this.write = write; } boolean isRead() { return read; } boolean isWrite() { return write; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/FileChangeCallback.java000066400000000000000000000020541257016060700247470ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.util.Collection; /** * Callback for file system change events * * @see FileSystemWatcher * @author Stuart Douglas */ public interface FileChangeCallback { /** * Method that is invoked when file system changes are detected. * * @param changes the file system changes */ void handleChanges(final Collection changes); } xnio-3.3.2.Final/api/src/main/java/org/xnio/FileChangeEvent.java000066400000000000000000000035661257016060700243450ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.io.File; /** * The event object that is fired when a file system change is detected. * * @see FileSystemWatcher * * @author Stuart Douglas */ public class FileChangeEvent { private final File file; private final Type type; /** * Construct a new instance. * * @param file the file which is being watched * @param type the type of event that was encountered */ public FileChangeEvent(File file, Type type) { this.file = file; this.type = type; } /** * Get the file which was being watched. * * @return the file which was being watched */ public File getFile() { return file; } /** * Get the type of event. * * @return the type of event */ public Type getType() { return type; } /** * Watched file event types. More may be added in the future. */ public static enum Type { /** * A file was added in a directory. */ ADDED, /** * A file was removed from a directory. */ REMOVED, /** * A file was modified in a directory. */ MODIFIED, } } xnio-3.3.2.Final/api/src/main/java/org/xnio/FileSystemWatcher.java000066400000000000000000000025631257016060700247540ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.io.Closeable; import java.io.File; /** * File system watcher service. This watcher can be used to receive notifications about a specific path. * * @author Stuart Douglas */ public interface FileSystemWatcher extends Closeable { /** * Watch the given path recursively, and invoke the callback when a change is made. * * @param file The path to watch * @param callback The callback */ public void watchPath(final File file, final FileChangeCallback callback); /** * Stop watching a path. * * @param file the path * @param callback the callback */ public void unwatchPath(final File file, final FileChangeCallback callback); } xnio-3.3.2.Final/api/src/main/java/org/xnio/FinishedIoFuture.java000066400000000000000000000035461257016060700245700ustar00rootroot00000000000000 package org.xnio; import java.io.IOException; import java.util.concurrent.CancellationException; import java.util.concurrent.TimeUnit; import static org.xnio.IoFuture.Status.DONE; /** * An implementation of {@link IoFuture} that represents an immediately-successful operation. * * @param the type of result that this operation produces */ public class FinishedIoFuture implements IoFuture { private final T result; /** * Create an instance. * * @param result the operation result */ public FinishedIoFuture(T result) { this.result = result; } /** * Cancel the operation. Since this operation is always complete, this is a no-op. * * @return this instance */ public IoFuture cancel() { return this; } @Override public Status getStatus() { return DONE; } @Override public Status await() { return DONE; } @Override public Status await(final long time, final TimeUnit timeUnit) { return DONE; } @Override public Status awaitInterruptibly() throws InterruptedException { return DONE; } @Override public Status awaitInterruptibly(final long time, final TimeUnit timeUnit) throws InterruptedException { return DONE; } @Override public T get() throws IOException, CancellationException { return result; } @Override public T getInterruptibly() throws IOException, InterruptedException, CancellationException { return result; } @Override public IOException getException() throws IllegalStateException { throw new IllegalStateException(); } @Override public IoFuture addNotifier(final Notifier notifier, final A attachment) { notifier.notify(this, attachment); return this; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/FutureResult.java000066400000000000000000000060371257016060700240230ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2009 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.util.concurrent.Executor; import java.io.IOException; /** * A result with a corresponding {@link org.xnio.IoFuture} instance. * * @param the {@code IoFuture} result type */ public class FutureResult implements Result { private final AbstractIoFuture ioFuture; /** * Construct a new instance. * * @param executor the executor to use to execute listener notifiers. */ public FutureResult(final Executor executor) { ioFuture = new AbstractIoFuture() { protected Executor getNotifierExecutor() { return executor; } }; } /** * Construct a new instance. The direct executor will be used to execute handler notifiers. */ public FutureResult() { this(IoUtils.directExecutor()); } /** * Get the {@code IoFuture} for this manager. * * @return the {@code IoFuture} */ public IoFuture getIoFuture() { return ioFuture; } /** * Add a cancellation handler. The argument will be cancelled whenever the {@code IoFuture} is cancelled. If * the {@code IoFuture} is already cancelled when this method is called, the handler will be called directly. * * @param cancellable the cancel handler */ public void addCancelHandler(final Cancellable cancellable) { ioFuture.addCancelHandler(cancellable); } /** * Set the result for this operation. Any threads blocking on this instance will be unblocked. * * @param result the result to set * @return {@code false} if the operation was already completed, {@code true} otherwise */ public boolean setResult(final T result) { return ioFuture.setResult(result); } /** * Set the exception for this operation. Any threads blocking on this instance will be unblocked. * * @param exception the exception to set * @return {@code false} if the operation was already completed, {@code true} otherwise */ public boolean setException(final IOException exception) { return ioFuture.setException(exception); } /** * Acknowledge the cancellation of this operation. * * @return {@code false} if the operation was already completed, {@code true} otherwise */ public boolean setCancelled() { return ioFuture.setCancelled(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/IoFuture.java000066400000000000000000000216041257016060700231110ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.util.EventListener; import java.util.concurrent.TimeUnit; import java.util.concurrent.CancellationException; import java.io.IOException; /** * The future result of an asynchronous request. Use instances of this interface to retrieve the final status of * an asynchronous operation. *

* It is recommended, due to the vagaries of the way generics work, that when you use {@code IoFuture} instances, you * use a wildcard to express the return type. This enables you to take advantage of covariance to retrofit * more specific types later on without breaking anything. *

* For example, if you have a method which returns a future {@code InputStream}, you might be tempted to declare it like * this: *

 * IoFuture<InputStream> getFutureInputStream();
 * 
* Now if you later decide that what you really need is a {@code DataInputStream} (which extends {@code InputStream}), * you're in trouble because you have written {@code IoFuture<InputStream>} everywhere, which cannot be assigned to or from * an {@code IoFuture<DataInputStream>}. *

* On the other hand, if you declare it like this: *

 * IoFuture<? extends InputStream> getFutureInputStream();
 * 
* Now you can change it at any time to {@code IoFuture<? extends DataInputStream>} without breaking the contract, since * it will be assignable to variables of type {@code IoFuture<? extends InputStream>}. * * @param the type of result that this operation produces * * @apiviz.landmark */ public interface IoFuture extends Cancellable { /** * The current status of an asynchronous operation. * * @apiviz.exclude */ enum Status { /** * The operation is still in progress. */ WAITING, /** * The operation has completed successfully. */ DONE, /** * The operation was cancelled. */ CANCELLED, /** * The operation did not succeed. */ FAILED, } /** {@inheritDoc} */ IoFuture cancel(); /** * Get the current status. * * @return the current status */ Status getStatus(); /** * Wait for the operation to complete. This method will block until the status changes from {@link Status#WAITING}. * * @return the new status */ Status await(); /** * Wait for the operation to complete, with a timeout. This method will block until the status changes from {@link Status#WAITING}, * or the given time elapses. If the time elapses before the operation is complete, {@link Status#WAITING} is * returned. * * @param time the amount of time to wait * @param timeUnit the time unit * @return the new status, or {@link Status#WAITING} if the timeout expired */ Status await(long time, TimeUnit timeUnit); /** * Wait for the operation to complete. This method will block until the status changes from {@link Status#WAITING}, * or the current thread is interrupted. * * @return the new status * @throws InterruptedException if the operation is interrupted */ Status awaitInterruptibly() throws InterruptedException; /** * Wait for the operation to complete, with a timeout. This method will block until the status changes from {@link Status#WAITING}, * the given time elapses, or the current thread is interrupted. If the time elapses before the operation is complete, {@link Status#WAITING} is * returned. * * @param time the amount of time to wait * @param timeUnit the time unit * @return the new status, or {@link Status#WAITING} if the timeout expired * @throws InterruptedException if the operation is interrupted */ Status awaitInterruptibly(long time, TimeUnit timeUnit) throws InterruptedException; /** * Get the result of the operation. If the operation is not complete, blocks until the operation completes. If * the operation fails, or has already failed at the time this method is called, the failure reason is thrown. * * @return the result of the operation * @throws IOException if the operation failed * @throws CancellationException if the operation was cancelled */ T get() throws IOException, CancellationException; /** * Get the result of the operation. If the operation is not complete, blocks until the operation completes. If * the operation fails, or has already failed at the time this method is called, the failure reason is thrown. If * the current thread is interrupted while waiting, an exception is thrown. * * @return the result of the operation * @throws IOException if the operation failed * @throws InterruptedException if the operation is interrupted * @throws CancellationException if the operation was cancelled */ T getInterruptibly() throws IOException, InterruptedException, CancellationException; /** * Get the failure reason. * * @return the failure reason * @throws IllegalStateException if the operation did not fail */ IOException getException() throws IllegalStateException; /** * Add a notifier to be called when this operation is complete. If the operation is already complete, the notifier * is called immediately, possibly in the caller's thread. The given attachment is provided to the notifier. * * @param notifier the notifier to be called * @param attachment the attachment to pass in to the notifier * @param
the attachment type * @return this instance */ IoFuture addNotifier(Notifier notifier, A attachment); /** * A notifier that handles changes in the status of an {@code IoFuture}. * * @param the type of result that the associated future operation produces * @param the attachment type * @apiviz.exclude */ interface Notifier extends EventListener { /** * Receive notification of the completion of an outstanding operation. * * @param ioFuture the future corresponding to this operation * @param attachment the attachment */ void notify(IoFuture ioFuture, final A attachment); } /** * A base notifier class that calls the designated handler method on notification. Use this class to reduce * boilerplate for standard {@link org.xnio.IoFuture.Notifier} implementations. * * @param the type of result that the associated future operation produces * @param the attachment type * * @since 1.1 * * @apiviz.exclude */ abstract class HandlingNotifier implements Notifier { /** * {@inheritDoc} */ public void notify(final IoFuture future, A attachment) { switch (future.getStatus()) { case CANCELLED: handleCancelled(attachment); break; case DONE: try { handleDone(future.get(), attachment); } catch (IOException e) { // not possible throw new IllegalStateException(); } break; case FAILED: handleFailed(future.getException(), attachment); break; default: // not possible throw new IllegalStateException(); } } /** * Handle cancellation. * * @param attachment the attachment */ public void handleCancelled(final A attachment) { } /** * Handle failure. * * @param exception the failure reason * @param attachment the attachment */ public void handleFailed(final IOException exception, final A attachment) { } /** * Handle completion. * * @param data the result * @param attachment the attachment */ public void handleDone(final T data, final A attachment) { } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/IoUtils.java000066400000000000000000000603421257016060700227410ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.io.Closeable; import java.io.IOException; import java.net.DatagramSocket; import java.net.ServerSocket; import java.net.Socket; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.ReadableByteChannel; import java.nio.channels.Selector; import java.nio.channels.Channel; import java.nio.channels.WritableByteChannel; import java.util.Random; import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.zip.ZipFile; import org.xnio.channels.SuspendableReadChannel; import java.util.logging.Handler; import static org.xnio._private.Messages.closeMsg; import static org.xnio._private.Messages.msg; /** * General I/O utility methods. * * @apiviz.exclude */ public final class IoUtils { private static final Executor NULL_EXECUTOR = new Executor() { private final String string = String.format("null executor <%s>", Integer.toHexString(hashCode())); public void execute(final Runnable command) { // no operation } public String toString() { return string; } }; private static final Executor DIRECT_EXECUTOR = new Executor() { private final String string = String.format("direct executor <%s>", Integer.toHexString(hashCode())); public void execute(final Runnable command) { command.run(); } public String toString() { return string; } }; private static final Closeable NULL_CLOSEABLE = new Closeable() { private final String string = String.format("null closeable <%s>", Integer.toHexString(hashCode())); public void close() throws IOException { // no operation } public String toString() { return string; } }; private static final Cancellable NULL_CANCELLABLE = new Cancellable() { public Cancellable cancel() { return this; } }; @SuppressWarnings("rawtypes") private static final IoUtils.ResultNotifier RESULT_NOTIFIER = new IoUtils.ResultNotifier(); private IoUtils() {} /** * Get the direct executor. This is an executor that executes the provided task in the same thread. * * @return a direct executor */ public static Executor directExecutor() { return DIRECT_EXECUTOR; } /** * Get the null executor. This is an executor that never actually executes the provided task. * * @return a null executor */ public static Executor nullExecutor() { return NULL_EXECUTOR; } /** * Get the null closeable. This is a simple {@code Closeable} instance that does nothing when its {@code close()} * method is invoked. * * @return the null closeable */ public static Closeable nullCloseable() { return NULL_CLOSEABLE; } /** * Close a resource, logging an error if an error occurs. * * @param resource the resource to close */ public static void safeClose(final Closeable resource) { try { if (resource != null) { closeMsg.closingResource(resource); resource.close(); } } catch (ClosedChannelException ignored) { } catch (Throwable t) { closeMsg.resourceCloseFailed(t, resource); } } /** * Close a series of resources, logging errors if they occur. * * @param resources the resources to close */ public static void safeClose(final Closeable... resources) { for (Closeable resource : resources) { safeClose(resource); } } /** * Close a resource, logging an error if an error occurs. * * @param resource the resource to close */ public static void safeClose(final Socket resource) { try { if (resource != null) { closeMsg.closingResource(resource); resource.close(); } } catch (ClosedChannelException ignored) { } catch (Throwable t) { closeMsg.resourceCloseFailed(t, resource); } } /** * Close a resource, logging an error if an error occurs. * * @param resource the resource to close */ public static void safeClose(final DatagramSocket resource) { try { if (resource != null) { closeMsg.closingResource(resource); resource.close(); } } catch (Throwable t) { closeMsg.resourceCloseFailed(t, resource); } } /** * Close a resource, logging an error if an error occurs. * * @param resource the resource to close */ public static void safeClose(final Selector resource) { try { if (resource != null) { closeMsg.closingResource(resource); resource.close(); } } catch (ClosedChannelException ignored) { } catch (Throwable t) { closeMsg.resourceCloseFailed(t, resource); } } /** * Close a resource, logging an error if an error occurs. * * @param resource the resource to close */ public static void safeClose(final ServerSocket resource) { try { if (resource != null) { closeMsg.closingResource(resource); resource.close(); } } catch (ClosedChannelException ignored) { } catch (Throwable t) { closeMsg.resourceCloseFailed(t, resource); } } /** * Close a resource, logging an error if an error occurs. * * @param resource the resource to close */ public static void safeClose(final ZipFile resource) { try { if (resource != null) { closeMsg.closingResource(resource); resource.close(); } } catch (Throwable t) { closeMsg.resourceCloseFailed(t, resource); } } /** * Close a resource, logging an error if an error occurs. * * @param resource the resource to close */ public static void safeClose(final Handler resource) { try { if (resource != null) { closeMsg.closingResource(resource); resource.close(); } } catch (Throwable t) { closeMsg.resourceCloseFailed(t, resource); } } /** * Close a future resource, logging an error if an error occurs. Attempts to cancel the operation if it is * still in progress. * * @param futureResource the resource to close */ public static void safeClose(final IoFuture futureResource) { if (futureResource != null) { futureResource.cancel().addNotifier(closingNotifier(), null); } } private static final IoFuture.Notifier ATTACHMENT_CLOSING_NOTIFIER = new IoFuture.Notifier() { public void notify(final IoFuture future, final Closeable attachment) { IoUtils.safeClose(attachment); } }; private static final IoFuture.Notifier CLOSING_NOTIFIER = new IoFuture.HandlingNotifier() { public void handleDone(final Closeable result, final Void attachment) { IoUtils.safeClose(result); } }; /** * Get a notifier that closes the attachment. * * @return a notifier which will close its attachment */ public static IoFuture.Notifier attachmentClosingNotifier() { return ATTACHMENT_CLOSING_NOTIFIER; } /** * Get a notifier that closes the result. * * @return a notifier which will close the result of the operation (if successful) */ public static IoFuture.Notifier closingNotifier() { return CLOSING_NOTIFIER; } /** * Get a notifier that runs the supplied action. * * @param runnable the notifier type * @param the future type (not used) * @return a notifier which will run the given command */ public static IoFuture.Notifier runnableNotifier(final Runnable runnable) { return new IoFuture.Notifier() { public void notify(final IoFuture future, final Void attachment) { runnable.run(); } }; } /** * Get the result notifier. This notifier will forward the result of the {@code IoFuture} to the attached * {@code Result}. * * @param the result type * @return the notifier */ @SuppressWarnings({ "unchecked" }) public static IoFuture.Notifier> resultNotifier() { return RESULT_NOTIFIER; } /** * Get the notifier that invokes the channel listener given as an attachment. * * @param the channel type * @return the notifier */ @SuppressWarnings({ "unchecked" }) public static IoFuture.Notifier> channelListenerNotifier() { return CHANNEL_LISTENER_NOTIFIER; } @SuppressWarnings("rawtypes") private static final IoFuture.Notifier CHANNEL_LISTENER_NOTIFIER = new IoFuture.HandlingNotifier>() { @SuppressWarnings({ "unchecked" }) public void handleDone(final Channel channel, final ChannelListener channelListener) { channelListener.handleEvent(channel); } }; /** * Get a {@code java.util.concurrent}-style {@code Future} instance wrapper for an {@code IoFuture} instance. * * @param ioFuture the {@code IoFuture} to wrap * @return a {@code Future} */ public static Future getFuture(final IoFuture ioFuture) { return new Future() { public boolean cancel(final boolean mayInterruptIfRunning) { ioFuture.cancel(); return ioFuture.await() == IoFuture.Status.CANCELLED; } public boolean isCancelled() { return ioFuture.getStatus() == IoFuture.Status.CANCELLED; } public boolean isDone() { return ioFuture.getStatus() == IoFuture.Status.DONE; } public T get() throws InterruptedException, ExecutionException { try { return ioFuture.getInterruptibly(); } catch (IOException e) { throw new ExecutionException(e); } } public T get(final long timeout, final TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { try { if (ioFuture.awaitInterruptibly(timeout, unit) == IoFuture.Status.WAITING) { throw msg.opTimedOut(); } return ioFuture.getInterruptibly(); } catch (IOException e) { throw new ExecutionException(e); } } public String toString() { return String.format("java.util.concurrent.Future wrapper <%s> for %s", Integer.toHexString(hashCode()), ioFuture); } }; } private static final IoFuture.Notifier COUNT_DOWN_NOTIFIER = new IoFuture.Notifier() { public void notify(final IoFuture future, final CountDownLatch latch) { latch.countDown(); } }; /** * Wait for all the futures to complete. * * @param futures the futures to wait for */ public static void awaitAll(IoFuture... futures) { final int len = futures.length; final CountDownLatch cdl = new CountDownLatch(len); for (IoFuture future : futures) { future.addNotifier(COUNT_DOWN_NOTIFIER, cdl); } boolean intr = false; try { while (cdl.getCount() > 0L) { try { cdl.await(); } catch (InterruptedException e) { intr = true; } } } finally { if (intr) { Thread.currentThread().interrupt(); } } } /** * Wait for all the futures to complete. * * @param futures the futures to wait for * @throws InterruptedException if the current thread is interrupted while waiting */ public static void awaitAllInterruptibly(IoFuture... futures) throws InterruptedException { final int len = futures.length; final CountDownLatch cdl = new CountDownLatch(len); for (IoFuture future : futures) { future.addNotifier(COUNT_DOWN_NOTIFIER, cdl); } cdl.await(); } /** * Create an {@code IoFuture} which wraps another {@code IoFuture}, but returns a different type. * * @param parent the original {@code IoFuture} * @param type the class of the new {@code IoFuture} * @param the type of the original result * @param the type of the wrapped result * @return a wrapper {@code IoFuture} */ public static IoFuture cast(final IoFuture parent, final Class type) { return new CastingIoFuture(parent, type); } /** * Safely shutdown reads on the given channel. * * @param channel the channel */ public static void safeShutdownReads(final SuspendableReadChannel channel) { if (channel != null) { try { channel.shutdownReads(); } catch (IOException e) { closeMsg.resourceReadShutdownFailed(null, null); } } } /** * Platform-independent channel-to-channel transfer method. Uses regular {@code read} and {@code write} operations * to move bytes from the {@code source} channel to the {@code sink} channel. After this call, the {@code throughBuffer} * should be checked for remaining bytes; if there are any, they should be written to the {@code sink} channel before * proceeding. This method may be used with NIO channels, XNIO channels, or a combination of the two. *

* If either or both of the given channels are blocking channels, then this method may block. * * @param source the source channel to read bytes from * @param count the number of bytes to transfer (must be >= {@code 0L}) * @param throughBuffer the buffer to transfer through (must not be {@code null}) * @param sink the sink channel to write bytes to * @return the number of bytes actually transferred (possibly 0) * @throws IOException if an I/O error occurs during the transfer of bytes */ public static long transfer(final ReadableByteChannel source, final long count, final ByteBuffer throughBuffer, final WritableByteChannel sink) throws IOException { long res; long total = 0L; throughBuffer.limit(0); while (total < count) { throughBuffer.compact(); try { if (count - total < (long) throughBuffer.remaining()) { throughBuffer.limit((int) (count - total)); } res = source.read(throughBuffer); if (res <= 0) { return total == 0L ? res : total; } } finally { throughBuffer.flip(); } res = sink.write(throughBuffer); if (res == 0) { return total; } total += res; } return total; } // nested classes private static class CastingIoFuture implements IoFuture { private final IoFuture parent; private final Class type; private CastingIoFuture(final IoFuture parent, final Class type) { this.parent = parent; this.type = type; } public IoFuture cancel() { parent.cancel(); return this; } public Status getStatus() { return parent.getStatus(); } public Status await() { return parent.await(); } public Status await(final long time, final TimeUnit timeUnit) { return parent.await(time, timeUnit); } public Status awaitInterruptibly() throws InterruptedException { return parent.awaitInterruptibly(); } public Status awaitInterruptibly(final long time, final TimeUnit timeUnit) throws InterruptedException { return parent.awaitInterruptibly(time, timeUnit); } public O get() throws IOException, CancellationException { return type.cast(parent.get()); } public O getInterruptibly() throws IOException, InterruptedException, CancellationException { return type.cast(parent.getInterruptibly()); } public IOException getException() throws IllegalStateException { return parent.getException(); } public IoFuture addNotifier(final Notifier notifier, final A attachment) { parent.addNotifier(new Notifier() { public void notify(final IoFuture future, final A attachment) { notifier.notify(CastingIoFuture.this, attachment); } }, attachment); return this; } } /** * Get a notifier which forwards the result to another {@code IoFuture}'s manager. * * @param the channel type * @return the notifier */ @SuppressWarnings({ "unchecked" }) public static IoFuture.Notifier> getManagerNotifier() { return MANAGER_NOTIFIER; } @SuppressWarnings("rawtypes") private static final ManagerNotifier MANAGER_NOTIFIER = new ManagerNotifier(); private static class ManagerNotifier extends IoFuture.HandlingNotifier> { public void handleCancelled(final FutureResult manager) { manager.setCancelled(); } public void handleFailed(final IOException exception, final FutureResult manager) { manager.setException(exception); } public void handleDone(final T result, final FutureResult manager) { manager.setResult(result); } } /** * A channel source which tries to acquire a channel from a delegate channel source the given number of times before * giving up. * * @param delegate the delegate channel source * @param maxTries the number of times to retry * @param the channel type * @return the retrying channel source */ public static ChannelSource getRetryingChannelSource(final ChannelSource delegate, final int maxTries) throws IllegalArgumentException { if (maxTries < 1) { throw msg.minRange("maxTries", 1); } return new RetryingChannelSource(maxTries, delegate); } private static class RetryingNotifier extends IoFuture.HandlingNotifier> { private volatile int remaining; private final int maxTries; private final Result result; private final ChannelSource delegate; private final ChannelListener openListener; RetryingNotifier(final int maxTries, final Result result, final ChannelSource delegate, final ChannelListener openListener) { this.maxTries = maxTries; this.result = result; this.delegate = delegate; this.openListener = openListener; remaining = maxTries; } public void handleFailed(final IOException exception, final Result attachment) { if (remaining-- == 0) { result.setException(new IOException("Failed to create channel after " + maxTries + " tries", exception)); return; } tryOne(attachment); } public void handleCancelled(final Result attachment) { result.setCancelled(); } public void handleDone(final T data, final Result attachment) { result.setResult(data); } void tryOne(final Result attachment) { final IoFuture ioFuture = delegate.open(openListener); ioFuture.addNotifier(this, attachment); } } private static class RetryingChannelSource implements ChannelSource { private final int maxTries; private final ChannelSource delegate; RetryingChannelSource(final int maxTries, final ChannelSource delegate) { this.maxTries = maxTries; this.delegate = delegate; } public IoFuture open(final ChannelListener openListener) { final FutureResult result = new FutureResult(); final IoUtils.RetryingNotifier notifier = new IoUtils.RetryingNotifier(maxTries, result, delegate, openListener); notifier.tryOne(result); return result.getIoFuture(); } } /** * A cancellable which closes the given resource on cancel. * * @param c the resource * @return the cancellable */ public static Cancellable closingCancellable(final Closeable c) { return new ClosingCancellable(c); } private static class ClosingCancellable implements Cancellable { private final Closeable c; ClosingCancellable(final Closeable c) { this.c = c; } public Cancellable cancel() { safeClose(c); return this; } } /** * Get the null cancellable. * * @return the null cancellable */ public static Cancellable nullCancellable() { return NULL_CANCELLABLE; } private static class ResultNotifier extends IoFuture.HandlingNotifier> { public void handleCancelled(final Result result) { result.setCancelled(); } public void handleFailed(final IOException exception, final Result result) { result.setException(exception); } public void handleDone(final T value, final Result result) { result.setResult(value); } } /** * Get a thread-local RNG. Do not share this instance with other threads. * * @return the thread-local RNG */ public static Random getThreadLocalRandom() { Random random = tlsRandom.get(); if (random == null) { random = new ThreadRandom(Thread.currentThread()); tlsRandom.set(random); } return random; } private static final ThreadLocal tlsRandom = new ThreadLocal(); private static final class ThreadRandom extends Random { private static final long serialVersionUID = -1765763476763499665L; private final Thread thread; private ThreadRandom(final Thread thread) { this.thread = thread; } protected int next(final int bits) { if (Thread.currentThread() != thread) { throw msg.randomWrongThread(); } return super.next(bits); } protected Object writeReplace() { return new Random(nextLong()); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/LocalSocketAddress.java000066400000000000000000000033711257016060700250610ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2010 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import java.net.SocketAddress; import static org.xnio._private.Messages.msg; /** * A socket address which is a local (UNIX domain) socket. * * @author David M. Lloyd */ public final class LocalSocketAddress extends SocketAddress { private static final long serialVersionUID = -596342428809783686L; private final String name; /** * Construct a new instance. * * @param name the name of this socket address */ public LocalSocketAddress(final String name) { if (name == null) { throw msg.nullParameter("name"); } this.name = name; } /** * Get the name (filesystem path) of this local socket address. * * @return the name */ public String getName() { return name; } /** * Get the string representation of this socket address (its name). * * @return the string representation */ public String toString() { return getName(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/MessageConnection.java000066400000000000000000000056771257016060700247670ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import org.xnio.channels.CloseListenerSettable; import org.xnio.conduits.ConduitReadableMessageChannel; import org.xnio.conduits.ConduitWritableMessageChannel; import org.xnio.conduits.MessageSinkConduit; import org.xnio.conduits.MessageSourceConduit; import static org.xnio._private.Messages.msg; /** * A message-oriented connection between peers. * * @author David M. Lloyd */ public abstract class MessageConnection extends Connection implements CloseListenerSettable { private ConduitReadableMessageChannel sourceChannel; private ConduitWritableMessageChannel sinkChannel; private ChannelListener closeListener; /** * Construct a new instance. * * @param thread the I/O thread */ protected MessageConnection(final XnioIoThread thread) { super(thread); } public void setCloseListener(final ChannelListener listener) { this.closeListener = listener; } public ChannelListener getCloseListener() { return closeListener; } public ChannelListener.Setter getCloseSetter() { return new Setter(this); } protected void setSourceConduit(MessageSourceConduit conduit) { this.sourceChannel = conduit == null ? null : new ConduitReadableMessageChannel(this, conduit); } protected void setSinkConduit(MessageSinkConduit conduit) { this.sinkChannel = conduit == null ? null : new ConduitWritableMessageChannel(this, conduit); } void invokeCloseListener() { ChannelListeners.invokeChannelListener(this, closeListener); } private static T notNull(T orig) throws IllegalStateException { if (orig == null) { throw msg.channelNotAvailable(); } return orig; } /** * Get the source channel. * * @return the source channel */ public ConduitReadableMessageChannel getSourceChannel() { return notNull(sourceChannel); } /** * Get the sink channel. * * @return the sink channel */ public ConduitWritableMessageChannel getSinkChannel() { return notNull(sinkChannel); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/ObjectProperties.java000066400000000000000000000113631257016060700246330ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2010, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xnio; import java.util.Collection; import java.util.Collections; import java.util.Enumeration; import java.util.Hashtable; import java.util.LinkedHashMap; import java.util.Map; import java.util.Set; /** * A Hashtable variant which keeps property names in order, for use by MBean {@code ObjectName}s. * * @author David M. Lloyd */ final class ObjectProperties extends Hashtable { private static final long serialVersionUID = -4691081844415343670L; private final Map realMap; public static Property property(String key, String value) { return new Property(key, value); } public static ObjectProperties properties(Property... properties) { return new ObjectProperties(properties); } public ObjectProperties(final int initialCapacity, final float loadFactor) { realMap = new LinkedHashMap(initialCapacity, loadFactor); } public ObjectProperties(final int initialCapacity) { realMap = new LinkedHashMap(initialCapacity); } public ObjectProperties() { realMap = new LinkedHashMap(); } public ObjectProperties(final Map t) { realMap = new LinkedHashMap(t); } public ObjectProperties(Property... properties) { realMap = new LinkedHashMap(properties.length); for (Property property : properties) { realMap.put(property.getKey(), property.getValue()); } } public int size() { return realMap.size(); } public boolean isEmpty() { return realMap.isEmpty(); } public Enumeration keys() { return Collections.enumeration(realMap.keySet()); } public Enumeration elements() { return Collections.enumeration(realMap.values()); } public boolean contains(final Object value) { return realMap.containsValue(value); } public boolean containsValue(final Object value) { return realMap.containsValue(value); } public boolean containsKey(final Object key) { return realMap.containsKey(key); } public String get(final Object key) { return realMap.get(key); } protected void rehash() { } public String put(final String key, final String value) { return realMap.put(key, value); } public String remove(final Object key) { return realMap.remove(key); } public void putAll(final Map t) { realMap.putAll(t); } public void clear() { realMap.clear(); } public Object clone() { return super.clone(); } public String toString() { return realMap.toString(); } public Set keySet() { return realMap.keySet(); } public Set> entrySet() { return realMap.entrySet(); } public Collection values() { return realMap.values(); } /** * A single property in a properties list. */ public static final class Property { private final String key; private final String value; public Property(final String key, final String value) { if (key == null) { throw new IllegalArgumentException("key is null"); } if (value == null) { throw new IllegalArgumentException("value is null"); } this.key = key; this.value = value; } public String getKey() { return key; } public String getValue() { return value; } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/Option.java000066400000000000000000000401301257016060700226120ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2010 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.io.InvalidObjectException; import java.io.ObjectStreamException; import java.io.Serializable; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; import static org.xnio._private.Messages.msg; /** * A strongly-typed option to configure an aspect of a service or connection. Options are immutable and use identity comparisons * and hash codes. Options should always be declared as public static final members in order to support serialization. * * @param the option value type */ public abstract class Option implements Serializable { private static final long serialVersionUID = -1564427329140182760L; private final Class declClass; private final String name; Option(final Class declClass, final String name) { if (declClass == null) { throw msg.nullParameter("declClass"); } if (name == null) { throw msg.nullParameter("name"); } this.declClass = declClass; this.name = name; } /** * Create an option with a simple type. The class object given must represent some immutable type, otherwise * unexpected behavior may result. * * @param declClass the declaring class of the option * @param name the (field) name of this option * @param type the class of the value associated with this option * @return the option instance */ public static Option simple(final Class declClass, final String name, final Class type) { return new SingleOption(declClass, name, type); } /** * Create an option with a sequence type. The class object given must represent some immutable type, otherwise * unexpected behavior may result. * * @param declClass the declaring class of the option * @param name the (field) name of this option * @param elementType the class of the sequence element value associated with this option * @return the option instance */ public static Option> sequence(final Class declClass, final String name, final Class elementType) { return new SequenceOption(declClass, name, elementType); } /** * Create an option with a class type. The class object given may represent any type. * * @param declClass the declaring class of the option * @param name the (field) name of this option * @param declType the class object for the type of the class object given * @param the type of the class object given * @return the option instance */ public static Option> type(final Class declClass, final String name, final Class declType) { return new TypeOption(declClass, name, declType); } /** * Create an option with a sequence-of-types type. The class object given may represent any type. * * @param declClass the declaring class of the option * @param name the (field) name of this option * @param elementDeclType the class object for the type of the sequence element class object given * @param the type of the sequence element class object given * @return the option instance */ public static Option>> typeSequence(final Class declClass, final String name, final Class elementDeclType) { return new TypeSequenceOption(declClass, name, elementDeclType); } /** * Get the name of this option. * * @return the option name */ public String getName() { return name; } /** * Get a human-readable string representation of this object. * * @return the string representation */ public String toString() { return declClass.getName() + "." + name; } /** * Get an option from a string name, using the given classloader. If the classloader is {@code null}, the bootstrap * classloader will be used. * * @param name the option string * @param classLoader the class loader * @return the option * @throws IllegalArgumentException if the given option name is not valid */ public static Option fromString(String name, ClassLoader classLoader) throws IllegalArgumentException { final int lastDot = name.lastIndexOf('.'); if (lastDot == -1) { throw msg.invalidOptionName(name); } final String fieldName = name.substring(lastDot + 1); final String className = name.substring(0, lastDot); final Class clazz; try { clazz = Class.forName(className, true, classLoader); } catch (ClassNotFoundException e) { throw msg.optionClassNotFound(className, classLoader); } final Field field; try { field = clazz.getField(fieldName); } catch (NoSuchFieldException e) { throw msg.noField(fieldName, clazz); } final int modifiers = field.getModifiers(); if (! Modifier.isPublic(modifiers)) { throw msg.fieldNotAccessible(fieldName, clazz); } if (! Modifier.isStatic(modifiers)) { throw msg.fieldNotStatic(fieldName, clazz); } final Option option; try { option = (Option) field.get(null); } catch (IllegalAccessException e) { throw msg.fieldNotAccessible(fieldName, clazz); } if (option == null) { throw msg.invalidNullOption(name); } return option; } /** * Return the given object as the type of this option. If the cast could not be completed, an exception is thrown. * * @param o the object to cast * @return the cast object * @throws ClassCastException if the object is not of a compatible type */ public abstract T cast(Object o) throws ClassCastException; /** * Return the given object as the type of this option. If the cast could not be completed, an exception is thrown. * * @param o the object to cast * @param defaultVal the value to return if {@code o} is {@code null} * * @return the cast object * * @throws ClassCastException if the object is not of a compatible type */ public final T cast(Object o, T defaultVal) throws ClassCastException { return o == null ? defaultVal : cast(o); } /** * Parse a string value for this option. * * @param string the string * @param classLoader the class loader to use to parse the value * @return the parsed value * @throws IllegalArgumentException if the argument could not be parsed */ public abstract T parseValue(String string, ClassLoader classLoader) throws IllegalArgumentException; /** * Resolve this instance for serialization. * * @return the resolved object * @throws java.io.ObjectStreamException if the object could not be resolved */ protected final Object readResolve() throws ObjectStreamException { try { final Field field = declClass.getField(name); final int modifiers = field.getModifiers(); if (! Modifier.isPublic(modifiers)) { throw new InvalidObjectException("Invalid Option instance (the field is not public)"); } if (! Modifier.isStatic(modifiers)) { throw new InvalidObjectException("Invalid Option instance (the field is not static)"); } final Option option = (Option) field.get(null); if (option == null) { throw new InvalidObjectException("Invalid null Option"); } return option; } catch (NoSuchFieldException e) { throw new InvalidObjectException("Invalid Option instance (no matching field)"); } catch (IllegalAccessException e) { throw new InvalidObjectException("Invalid Option instance (Illegal access on field get)"); } } /** * Create a builder for an immutable option set. * * @return the builder */ public static Option.SetBuilder setBuilder() { return new Option.SetBuilder(); } /** * A builder for an immutable option set. */ public static class SetBuilder { private List> optionSet = new ArrayList>(); SetBuilder() { } /** * Add an option to this set. * * @param option the option to add * @return this builder */ public Option.SetBuilder add(Option option) { if (option == null) { throw msg.nullParameter("option"); } optionSet.add(option); return this; } /** * Add options to this set. * * @param option1 the first option to add * @param option2 the second option to add * @return this builder */ public Option.SetBuilder add(Option option1, Option option2) { if (option1 == null) { throw msg.nullParameter("option1"); } if (option2 == null) { throw msg.nullParameter("option2"); } optionSet.add(option1); optionSet.add(option2); return this; } /** * Add options to this set. * * @param option1 the first option to add * @param option2 the second option to add * @param option3 the third option to add * @return this builder */ public Option.SetBuilder add(Option option1, Option option2, Option option3) { if (option1 == null) { throw msg.nullParameter("option1"); } if (option2 == null) { throw msg.nullParameter("option2"); } if (option3 == null) { throw msg.nullParameter("option3"); } optionSet.add(option1); optionSet.add(option2); optionSet.add(option3); return this; } /** * Add options to this set. * * @param options the options to add * @return this builder */ public Option.SetBuilder add(Option... options) { if (options == null) { throw msg.nullParameter("options"); } for (Option option : options) { add(option); } return this; } /** * Add all options from a collection to this set. * * @param options the options to add * @return this builder */ public Option.SetBuilder addAll(Collection> options) { if (options == null) { throw msg.nullParameter("option"); } for (Option option : options) { add(option); } return this; } /** * Create the immutable option set instance. * * @return the option set */ public Set> create() { return Collections.unmodifiableSet(new LinkedHashSet>(optionSet)); } } interface ValueParser { T parseValue(String string, ClassLoader classLoader) throws IllegalArgumentException; } private static final Map, Option.ValueParser> parsers; private static final Option.ValueParser noParser = new Option.ValueParser() { public Object parseValue(final String string, final ClassLoader classLoader) throws IllegalArgumentException { throw msg.noOptionParser(); } }; static { final Map, Option.ValueParser> map = new HashMap, Option.ValueParser>(); map.put(Byte.class, new Option.ValueParser() { public Byte parseValue(final String string, final ClassLoader classLoader) throws IllegalArgumentException { return Byte.decode(string.trim()); } }); map.put(Short.class, new Option.ValueParser() { public Short parseValue(final String string, final ClassLoader classLoader) throws IllegalArgumentException { return Short.decode(string.trim()); } }); map.put(Integer.class, new Option.ValueParser() { public Integer parseValue(final String string, final ClassLoader classLoader) throws IllegalArgumentException { return Integer.decode(string.trim()); } }); map.put(Long.class, new Option.ValueParser() { public Long parseValue(final String string, final ClassLoader classLoader) throws IllegalArgumentException { return Long.decode(string.trim()); } }); map.put(String.class, new Option.ValueParser() { public String parseValue(final String string, final ClassLoader classLoader) throws IllegalArgumentException { return string.trim(); } }); map.put(Boolean.class, new Option.ValueParser() { public Boolean parseValue(final String string, final ClassLoader classLoader) throws IllegalArgumentException { return Boolean.valueOf(string.trim()); } }); map.put(Property.class, new Option.ValueParser() { public Object parseValue(final String string, final ClassLoader classLoader) throws IllegalArgumentException { final int idx = string.indexOf('='); if (idx == -1) { throw msg.invalidOptionPropertyFormat(string); } return Property.of(string.substring(0, idx), string.substring(idx + 1, string.length())); } }); parsers = map; } static Option.ValueParser> getClassParser(final Class argType) { return new ValueParser>() { public Class parseValue(final String string, final ClassLoader classLoader) throws IllegalArgumentException { try { return Class.forName(string, false, classLoader).asSubclass(argType); } catch (ClassNotFoundException e) { throw msg.classNotFound(string, e); } catch (ClassCastException e) { throw msg.classNotInstance(string, argType); } } }; } static Option.ValueParser getEnumParser(final Class enumType) { return new ValueParser() { @SuppressWarnings("unchecked") public T parseValue(final String string, final ClassLoader classLoader) throws IllegalArgumentException { return enumType.cast(Enum.valueOf(enumType.asSubclass(Enum.class), string.trim())); } }; } @SuppressWarnings("unchecked") static Option.ValueParser getParser(final Class argType) { if (argType.isEnum()) { return getEnumParser(argType); } else { final Option.ValueParser value = parsers.get(argType); return (Option.ValueParser) (value == null ? noParser : value); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/OptionMap.java000066400000000000000000000444421257016060700232620ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2009 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.util.Iterator; import java.util.List; import java.util.ArrayList; import java.util.Map; import java.util.Collections; import java.util.IdentityHashMap; import java.util.Properties; import java.io.Serializable; import static org.xnio._private.Messages.msg; import static org.xnio._private.Messages.optionParseMsg; /** * An immutable map of options to option values. No {@code null} keys or values are permitted. */ public final class OptionMap implements Iterable>, Serializable { private static final long serialVersionUID = 3632842565346928132L; private final Map, Object> value; private OptionMap(final Map, Object> value) { this.value = value; } /** * Determine whether this option map contains the given option. * * @param option the option to check * @return {@code true} if the option is present in the option map */ public boolean contains(Option option) { return value.containsKey(option); } /** * Get the value of an option from this option map. * * @param option the option to get * @param the type of the option * @return the option value, or {@code null} if it is not present */ public T get(Option option) { return option.cast(value.get(option)); } /** * Get the value of an option from this option map, with a specified default if the value is missing. * * @param option the option to get * @param defaultValue the value to return if the option is not set * @param the type of the option * @return the option value, or {@code null} if it is not present */ public T get(Option option, T defaultValue) { final Object o = value.get(option); return o == null ? defaultValue : option.cast(o); } /** * Get a boolean value from this option map, with a specified default if the value is missing. * * @param option the option to get * @param defaultValue the default value if the option is not present * @return the result */ public boolean get(Option option, boolean defaultValue) { final Object o = value.get(option); return o == null ? defaultValue : option.cast(o).booleanValue(); } /** * Get a int value from this option map, with a specified default if the value is missing. * * @param option the option to get * @param defaultValue the default value if the option is not present * @return the result */ public int get(Option option, int defaultValue) { final Object o = value.get(option); return o == null ? defaultValue : option.cast(o).intValue(); } /** * Get a long value from this option map, with a specified default if the value is missing. * * @param option the option to get * @param defaultValue the default value if the option is not present * @return the result */ public long get(Option option, long defaultValue) { final Object o = value.get(option); return o == null ? defaultValue : option.cast(o).longValue(); } /** * Iterate over the options in this map. * * @return an iterator over the options */ public Iterator> iterator() { return Collections.unmodifiableCollection(value.keySet()).iterator(); } /** * Get the number of options stored in this map. * * @return the number of options */ public int size() { return value.size(); } /** * The empty option map. */ public static final OptionMap EMPTY = new OptionMap(Collections., Object>emptyMap()); /** * Create a new builder. * * @return a new builder */ public static Builder builder() { return new Builder(); } /** * Create a single-valued option map. * * @param option the option to put in the map * @param value the option value * @param the option value type * @return the option map * * @since 3.0 */ public static OptionMap create(Option option, T value) { if (option == null) { throw msg.nullParameter("option"); } if (value == null) { throw msg.nullParameter("value"); } return new OptionMap(Collections., Object>singletonMap(option, option.cast(value))); } /** * Create a two-valued option map. If both options are the same key, then only the second one is added * to the map. * * @param option1 the first option to put in the map * @param value1 the first option value * @param option2 the second option to put in the map * @param value2 the second option value * @param the first option value type * @param the second option value type * @return the option map * * @since 3.0 */ public static OptionMap create(Option option1, T1 value1, Option option2, T2 value2) { if (option1 == null) { throw msg.nullParameter("option1"); } if (value1 == null) { throw msg.nullParameter("value1"); } if (option2 == null) { throw msg.nullParameter("option2"); } if (value2 == null) { throw msg.nullParameter("value2"); } if (option1 == option2) { return create(option2, value2); } final IdentityHashMap, Object> map = new IdentityHashMap, Object>(2); map.put(option1, value1); map.put(option2, value2); return new OptionMap(map); } public String toString() { final StringBuilder builder = new StringBuilder(); builder.append('{'); final Iterator, Object>> iterator = value.entrySet().iterator(); while (iterator.hasNext()) { final Map.Entry, Object> entry = iterator.next(); builder.append(entry.getKey()).append("=>").append(entry.getValue()); if (iterator.hasNext()) { builder.append(','); } } builder.append('}'); return builder.toString(); } /** * Determine whether this option map is equal to another. * * @param other the other option map * @return {@code true} if they are equal, {@code false} otherwise */ public boolean equals(Object other) { return other instanceof OptionMap && equals((OptionMap)other); } /** * Determine whether this option map is equal to another. * * @param other the other option map * @return {@code true} if they are equal, {@code false} otherwise */ public boolean equals(OptionMap other) { return this == other || other != null && value.equals(other.value); } /** * Get the hash code for this option map. * * @return the hash code */ public int hashCode() { return value.hashCode(); } /** * A builder for immutable option maps. Create an instance with the {@link OptionMap#builder()} method. */ public static final class Builder { private Builder() { } private static class OVPair { Option option; T value; private OVPair(final Option option, final T value) { this.option = option; this.value = value; } } private List> list = new ArrayList>(); /** * Set a key-value pair, parsing the value from the given string. * * @param key the key * @param stringValue the string value * @param the option type * @return this builder */ public Builder parse(Option key, String stringValue) { set(key, key.parseValue(stringValue, key.getClass().getClassLoader())); return this; } /** * Set a key-value pair, parsing the value from the given string. * * @param key the key * @param stringValue the string value * @param classLoader the class loader to use for parsing the value * @param the option type * @return this builder */ public Builder parse(Option key, String stringValue, ClassLoader classLoader) { set(key, key.parseValue(stringValue, classLoader)); return this; } /** * Add all options from a properties file. Finds all entries which start with a given prefix followed by '.'; * the remainder of the property key (after the prefix) is the option name, and the value is the option value. *

If the prefix does not end with '.' character, a '.' will be appended to it before parsing. * * @param props the properties to read * @param prefix the prefix * @param optionClassLoader the class loader to use to resolve option names * @return this builder */ public Builder parseAll(Properties props, String prefix, ClassLoader optionClassLoader) { if (! prefix.endsWith(".")) { prefix = prefix + "."; } for (String name : props.stringPropertyNames()) { if (name.startsWith(prefix)) { final String optionName = name.substring(prefix.length()); try { final Option option = Option.fromString(optionName, optionClassLoader); parse(option, props.getProperty(name), optionClassLoader); } catch (IllegalArgumentException e) { optionParseMsg.invalidOptionInProperty(optionName, name, e); } } } return this; } /** * Add all options from a properties file. Finds all entries which start with a given prefix followed by '.'; * the remainder of the property key (after the prefix) is the option name, and the value is the option value. *

If the prefix does not end with '.' character, a '.' will be appended to it before parsing. * * @param props the properties to read * @param prefix the prefix * @return this builder */ public Builder parseAll(Properties props, String prefix) { if (! prefix.endsWith(".")) { prefix = prefix + "."; } for (String name : props.stringPropertyNames()) { if (name.startsWith(prefix)) { final String optionName = name.substring(prefix.length()); try { final Option option = Option.fromString(optionName, getClass().getClassLoader()); parse(option, props.getProperty(name)); } catch (IllegalArgumentException e) { optionParseMsg.invalidOptionInProperty(optionName, name, e); } } } return this; } /** * Set a key-value pair. * * @param key the key * @param value the value * @param the option type * @return this builder */ public Builder set(Option key, T value) { if (key == null) { throw msg.nullParameter("key"); } if (value == null) { throw msg.nullParameter("value"); } list.add(new OVPair(key, value)); return this; } /** * Set an int value for an Integer key. * * @param key the option * @param value the value * @return this builder */ public Builder set(Option key, int value) { if (key == null) { throw msg.nullParameter("key"); } list.add(new OVPair(key, Integer.valueOf(value))); return this; } /** * Set int values for an Integer sequence key. * * @param key the key * @param values the values * @return this builder */ public Builder setSequence(Option> key, int... values) { if (key == null) { throw msg.nullParameter("key"); } Integer[] a = new Integer[values.length]; for (int i = 0; i < values.length; i++) { a[i] = Integer.valueOf(values[i]); } list.add(new OVPair>(key, Sequence.of(a))); return this; } /** * Set a long value for a Long key. * * @param key the option * @param value the value * @return this builder */ public Builder set(Option key, long value) { if (key == null) { throw msg.nullParameter("key"); } list.add(new OVPair(key, Long.valueOf(value))); return this; } /** * Set long values for a Long sequence key. * * @param key the key * @param values the values * @return this builder */ public Builder setSequence(Option> key, long... values) { if (key == null) { throw msg.nullParameter("key"); } Long[] a = new Long[values.length]; for (int i = 0; i < values.length; i++) { a[i] = Long.valueOf(values[i]); } list.add(new OVPair>(key, Sequence.of(a))); return this; } /** * Set a boolean value for a Boolean key. * * @param key the option * @param value the value * @return this builder */ public Builder set(Option key, boolean value) { if (key == null) { throw msg.nullParameter("key"); } list.add(new OVPair(key, Boolean.valueOf(value))); return this; } /** * Set boolean values for an Boolean sequence key. * * @param key the key * @param values the values * @return this builder */ public Builder setSequence(Option> key, boolean... values) { if (key == null) { throw msg.nullParameter("key"); } Boolean[] a = new Boolean[values.length]; for (int i = 0; i < values.length; i++) { a[i] = Boolean.valueOf(values[i]); } list.add(new OVPair>(key, Sequence.of(a))); return this; } /** * Set a key-value pair, where the value is a sequence type. * * @param key the key * @param values the values * @param the option type * @return this builder */ public Builder setSequence(Option> key, T... values) { if (key == null) { throw msg.nullParameter("key"); } list.add(new OVPair>(key, Sequence.of(values))); return this; } private void copy(Map map, Option option) { set(option, option.cast(map.get(option))); } /** * Add all the entries of a map. Any keys of the map which are not valid {@link Option}s, or whose * values are not valid arguments for the given {@code Option}, will cause an exception to be thrown. * Any keys which occur more than once in this builder will be overwritten with the last occurring value. * * @param map the map * @return this builder * @throws ClassCastException if any entries of the map are not valid option-value pairs */ public Builder add(Map map) throws ClassCastException { for (Object key : map.keySet()) { final Option option = Option.class.cast(key); copy(map, option); } return this; } private void copy(OptionMap optionMap, Option option) { set(option, optionMap.get(option)); } /** * Add all entries from an existing option map to the one being built. * Any keys which occur more than once in this builder will be overwritten with the last occurring value. * * @param optionMap the original option map * @return this builder */ public Builder addAll(OptionMap optionMap) { for (Option option : optionMap) { copy(optionMap, option); } return this; } /** * Build a map that reflects the current state of this builder. * * @return the new immutable option map */ public OptionMap getMap() { final List> list = this.list; if (list.size() == 0) { return EMPTY; } else if (list.size() == 1) { final OVPair pair = list.get(0); return new OptionMap(Collections., Object>singletonMap(pair.option, pair.value)); } else { final Map, Object> map = new IdentityHashMap, Object>(); for (OVPair ovPair : list) { map.put(ovPair.option, ovPair.value); } return new OptionMap(map); } } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/Options.java000066400000000000000000000614211257016060700230030ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import org.xnio.channels.ReadTimeoutException; import org.xnio.channels.SuspendableWriteChannel; import org.xnio.channels.WriteTimeoutException; import org.xnio.sasl.SaslQop; import org.xnio.sasl.SaslStrength; import javax.net.ssl.KeyManager; import javax.net.ssl.TrustManager; import javax.security.sasl.Sasl; import org.xnio.ssl.SslConnection; /** * Common channel options. * * @apiviz.exclude */ public final class Options { private Options() {} /** * Enable or disable blocking I/O for a newly created channel thread. */ public static final Option ALLOW_BLOCKING = Option.simple(Options.class, "ALLOW_BLOCKING", Boolean.class); /** * Enable multicast support for a socket. The value type for this option is {@code boolean}. Note that some * implementations may add overhead when multicast sockets are in use. */ public static final Option MULTICAST = Option.simple(Options.class, "MULTICAST", Boolean.class); /** * Enable broadcast support for IP datagram sockets. The value type for this option is {@code boolean}. If you * intend to send datagrams to a broadcast address, this option must be enabled. */ public static final Option BROADCAST = Option.simple(Options.class, "BROADCAST", Boolean.class); /** * Configure a TCP socket to send an {@code RST} packet on close. The value type for this option is {@code boolean}. */ public static final Option CLOSE_ABORT = Option.simple(Options.class, "CLOSE_ABORT", Boolean.class); /** * The receive buffer size. The value type for this option is {@code int}. This may be used by an XNIO provider * directly, or it may be passed to the underlying operating system, depending on the channel type. Buffer * sizes must always be greater than 0. Note that this value is just a hint; if the application needs to know * what value was actually stored for this option, it must call {@code getOption(Options.RECEIVE_BUFFER)} on the * channel to verify. On most operating systems, the receive buffer size may not be changed on a socket after * it is connected; in these cases, calling {@code setOption(Options.RECEIVE_BUFFER, val)} will return {@code null}. */ public static final Option RECEIVE_BUFFER = Option.simple(Options.class, "RECEIVE_BUFFER", Integer.class); /** * Configure an IP socket to reuse addresses. The value type for this option is {@code boolean}. */ public static final Option REUSE_ADDRESSES = Option.simple(Options.class, "REUSE_ADDRESSES", Boolean.class); /** * The send buffer size. The value type for this option is {@code int}. This may be used by an XNIO provider * directly, or it may be passed to the underlying operating system, depending on the channel type. Buffer * sizes must always be greater than 0. Note that this value is just a hint; if the application needs to know * what value was actually stored for this option, it must call {@code getOption(Options.SEND_BUFFER)} on the * channel to verify. */ public static final Option SEND_BUFFER = Option.simple(Options.class, "SEND_BUFFER", Integer.class); /** * Configure a TCP socket to disable Nagle's algorithm. The value type for this option is {@code boolean}. */ public static final Option TCP_NODELAY = Option.simple(Options.class, "TCP_NODELAY", Boolean.class); /** * Set the multicast time-to-live field for datagram sockets. The value type for this option is {@code int}. */ public static final Option MULTICAST_TTL = Option.simple(Options.class, "MULTICAST_TTL", Integer.class); /** * Set the IP traffic class/type-of-service for the channel. The value type for this option is {@code int}. */ public static final Option IP_TRAFFIC_CLASS = Option.simple(Options.class, "IP_TRAFFIC_CLASS", Integer.class); /** * Configure a TCP socket to receive out-of-band data alongside regular data. The value type for this option is * {@code boolean}. */ public static final Option TCP_OOB_INLINE = Option.simple(Options.class, "TCP_OOB_INLINE", Boolean.class); /** * Configure a channel to send TCP keep-alive messages in an implementation-dependent manner. The value type for * this option is {@code boolean}. */ public static final Option KEEP_ALIVE = Option.simple(Options.class, "KEEP_ALIVE", Boolean.class); /** * Configure a server with the specified backlog. The value type for this option is {@code int}. */ public static final Option BACKLOG = Option.simple(Options.class, "BACKLOG", Integer.class); /** * Configure a read timeout for a socket, in milliseconds. If the given amount of time elapses without * a successful read taking place, the socket's next read will throw a {@link ReadTimeoutException}. */ public static final Option READ_TIMEOUT = Option.simple(Options.class, "READ_TIMEOUT", Integer.class); /** * Configure a write timeout for a socket, in milliseconds. If the given amount of time elapses without * a successful write taking place, the socket's next write will throw a {@link WriteTimeoutException}. */ public static final Option WRITE_TIMEOUT = Option.simple(Options.class, "WRITE_TIMEOUT", Integer.class); /** * The maximum inbound message size. * * @since 2.0 */ public static final Option MAX_INBOUND_MESSAGE_SIZE = Option.simple(Options.class, "MAX_INBOUND_MESSAGE_SIZE", Integer.class); /** * The maximum outbound message size. * * @since 2.0 */ public static final Option MAX_OUTBOUND_MESSAGE_SIZE = Option.simple(Options.class, "MAX_OUTBOUND_MESSAGE_SIZE", Integer.class); /** * Specify whether SSL should be enabled. If specified in conjunction with {@link #SSL_STARTTLS} then SSL will not * be negotiated until {@link org.xnio.channels.SslChannel#startHandshake()} or * {@link SslConnection#startHandshake()} is called. * * @since 3.0 */ public static final Option SSL_ENABLED = Option.simple(Options.class, "SSL_ENABLED", Boolean.class); /** * Specify the SSL client authentication mode. * * @since 2.0 */ public static final Option SSL_CLIENT_AUTH_MODE = Option.simple(Options.class, "SSL_CLIENT_AUTH_MODE", SslClientAuthMode.class); /** * Specify the cipher suites for an SSL/TLS session. If a listed cipher suites is not supported, it is ignored; however, if you * specify a list of cipher suites, none of which are supported, an exception will be thrown. * * @since 2.0 */ public static final Option> SSL_ENABLED_CIPHER_SUITES = Option.sequence(Options.class, "SSL_ENABLED_CIPHER_SUITES", String.class); /** * Get the supported cipher suites for an SSL/TLS session. This option is generally read-only. * * @since 2.0 */ public static final Option> SSL_SUPPORTED_CIPHER_SUITES = Option.sequence(Options.class, "SSL_SUPPORTED_CIPHER_SUITES", String.class); /** * Specify the enabled protocols for an SSL/TLS session. If a listed protocol is not supported, it is ignored; however, if you * specify a list of protocols, none of which are supported, an exception will be thrown. * * @since 2.0 */ public static final Option> SSL_ENABLED_PROTOCOLS = Option.sequence(Options.class, "SSL_ENABLED_PROTOCOLS", String.class); /** * Get the supported protocols for an SSL/TLS session. This option is generally read-only. * * @since 2.0 */ public static final Option> SSL_SUPPORTED_PROTOCOLS = Option.sequence(Options.class, "SSL_SUPPORTED_PROTOCOLS", String.class); /** * Specify the requested provider for an SSL/TLS session. * * @since 2.0 */ public static final Option SSL_PROVIDER = Option.simple(Options.class, "SSL_PROVIDER", String.class); /** * Specify the protocol name for an SSL context. * * @since 2.1 */ public static final Option SSL_PROTOCOL = Option.simple(Options.class, "SSL_PROTOCOL", String.class); /** * Enable or disable session creation for an SSL connection. Defaults to {@code true} to enable session creation. * * @since 2.0 */ public static final Option SSL_ENABLE_SESSION_CREATION = Option.simple(Options.class, "SSL_ENABLE_SESSION_CREATION", Boolean.class); /** * Specify whether SSL conversations should be in client or server mode. Defaults to {@code false} (use server mode). If * set to {@code true}, the client and server side swap negotiation roles. * * @since 2.0 */ public static final Option SSL_USE_CLIENT_MODE = Option.simple(Options.class, "SSL_USE_CLIENT_MODE", Boolean.class); /** * The size of the SSL client session cache. * * @since 3.0 */ public static final Option SSL_CLIENT_SESSION_CACHE_SIZE = Option.simple(Options.class, "SSL_CLIENT_SESSION_CACHE_SIZE", Integer.class); /** * The SSL client session timeout (in seconds). * * @since 3.0 */ public static final Option SSL_CLIENT_SESSION_TIMEOUT = Option.simple(Options.class, "SSL_CLIENT_SESSION_TIMEOUT", Integer.class); /** * The size of the SSL server session cache. * * @since 3.0 */ public static final Option SSL_SERVER_SESSION_CACHE_SIZE = Option.simple(Options.class, "SSL_SERVER_SESSION_CACHE_SIZE", Integer.class); /** * The SSL server session timeout (in seconds). * * @since 3.0 */ public static final Option SSL_SERVER_SESSION_TIMEOUT = Option.simple(Options.class, "SSL_SERVER_SESSION_TIMEOUT", Integer.class); /** * The possible key manager classes to use for a JSSE SSL context. * * @since 3.0 */ public static final Option>> SSL_JSSE_KEY_MANAGER_CLASSES = Option.typeSequence(Options.class, "SSL_JSSE_KEY_MANAGER_CLASSES", KeyManager.class); /** * The possible trust store classes to use for a JSSE SSL context. * * @since 3.0 */ public static final Option>> SSL_JSSE_TRUST_MANAGER_CLASSES = Option.typeSequence(Options.class, "SSL_JSSE_TRUST_MANAGER_CLASSES", TrustManager.class); /** * The configuration of a secure RNG for SSL usage. * * @since 3.0 */ public static final Option SSL_RNG_OPTIONS = Option.simple(Options.class, "SSL_RNG_OPTIONS", OptionMap.class); /** * The packet buffer size for SSL. * * @since 3.0 */ public static final Option SSL_PACKET_BUFFER_SIZE = Option.simple(Options.class, "SSL_PACKET_BUFFER_SIZE", Integer.class); /** * The application buffer size for SSL. * * @since 3.0 */ public static final Option SSL_APPLICATION_BUFFER_SIZE = Option.simple(Options.class, "SSL_APPLICATION_BUFFER_SIZE", Integer.class); /** * The size of the allocation region to use for SSL packet buffers. * * @since 3.0 */ public static final Option SSL_PACKET_BUFFER_REGION_SIZE = Option.simple(Options.class, "SSL_PACKET_BUFFER_REGION_SIZE", Integer.class); /** * The size of the allocation region to use for SSL application buffers. * * @since 3.0 */ public static final Option SSL_APPLICATION_BUFFER_REGION_SIZE = Option.simple(Options.class, "SSL_APPLICATION_BUFFER_REGION_SIZE", Integer.class); /** * Specify whether to use STARTTLS mode (in which a connection starts clear and switches to TLS on demand). * * @since 3.0 */ public static final Option SSL_STARTTLS = Option.simple(Options.class, "SSL_STARTTLS", Boolean.class); /** * Specify the (non-authoritative) name of the peer host to use for the purposes of session reuse, as well as * for the use of certain cipher suites (such as Kerberos). If not given, defaults to the host name of the * socket address of the peer. */ public static final Option SSL_PEER_HOST_NAME = Option.simple(Options.class, "SSL_PEER_HOST_NAME", String.class); /** * Specify the (non-authoritative) port number of the peer port number to use for the purposes of session reuse, as well as * for the use of certain cipher suites. If not given, defaults to the port number of the socket address of the peer. */ public static final Option SSL_PEER_PORT = Option.simple(Options.class, "SSL_PEER_PORT", Integer.class); /** * Hint to the SSL engine that the key manager implementation(s) is/are non-blocking, so they can be executed * in the I/O thread, possibly improving performance by decreasing latency. */ public static final Option SSL_NON_BLOCKING_KEY_MANAGER = Option.simple(Options.class, "SSL_NON_BLOCKING_KEY_MANAGER", Boolean.class); /** * Hint to the SSL engine that the trust manager implementation(s) is/are non-blocking, so they can be executed * in the I/O thread, possibly improving performance by decreasing latency. */ public static final Option SSL_NON_BLOCKING_TRUST_MANAGER = Option.simple(Options.class, "SSL_NON_BLOCKING_TRUST_MANAGER", Boolean.class); /** * Specify whether direct buffers should be used for socket communications. * * @since 3.0 */ public static final Option USE_DIRECT_BUFFERS = Option.simple(Options.class, "USE_DIRECT_BUFFERS", Boolean.class); /** * Determine whether the channel is encrypted, or employs some other level of security. The interpretation of this flag * is specific to the channel in question; however, whatever the channel type, this flag is generally read-only. */ public static final Option SECURE = Option.simple(Options.class, "SECURE", Boolean.class); /** * Specify whether SASL mechanisms which implement forward secrecy between sessions are required. * * @see Sasl#POLICY_FORWARD_SECRECY */ public static final Option SASL_POLICY_FORWARD_SECRECY = Option.simple(Options.class, "SASL_POLICY_FORWARD_SECRECY", Boolean.class); /** * Specify whether SASL mechanisms which are susceptible to active (non-dictionary) attacks are permitted. * * @see Sasl#POLICY_NOACTIVE */ public static final Option SASL_POLICY_NOACTIVE = Option.simple(Options.class, "SASL_POLICY_NOACTIVE", Boolean.class); /** * Specify whether SASL mechanisms which accept anonymous logins are permitted. * * @see Sasl#POLICY_NOANONYMOUS */ public static final Option SASL_POLICY_NOANONYMOUS = Option.simple(Options.class, "SASL_POLICY_NOANONYMOUS", Boolean.class); /** * Specify whether SASL mechanisms which are susceptible to passive dictionary attacks are permitted. * * @see Sasl#POLICY_NODICTIONARY */ public static final Option SASL_POLICY_NODICTIONARY = Option.simple(Options.class, "SASL_POLICY_NODICTIONARY", Boolean.class); /** * Specify whether SASL mechanisms which are susceptible to simple plain passive attacks are permitted. * * @see Sasl#POLICY_NOPLAINTEXT */ public static final Option SASL_POLICY_NOPLAINTEXT = Option.simple(Options.class, "SASL_POLICY_NOPLAINTEXT", Boolean.class); /** * Specify whether SASL mechanisms which pass client credentials are required. * * @see Sasl#POLICY_PASS_CREDENTIALS */ public static final Option SASL_POLICY_PASS_CREDENTIALS = Option.simple(Options.class, "SASL_POLICY_PASS_CREDENTIALS", Boolean.class); /** * Specify the SASL quality-of-protection to use. * * @see Sasl#QOP */ public static final Option> SASL_QOP = Option.sequence(Options.class, "SASL_QOP", SaslQop.class); /** * Specify the SASL cipher strength to use. * * @see Sasl#STRENGTH */ public static final Option SASL_STRENGTH = Option.simple(Options.class, "SASL_STRENGTH", SaslStrength.class); /** * Specify whether the SASL server must authenticate to the client. * * @see Sasl#SERVER_AUTH */ public static final Option SASL_SERVER_AUTH = Option.simple(Options.class, "SASL_SERVER_AUTH", Boolean.class); /** * Specify whether SASL mechanisms should attempt to reuse authenticated session information. * * @see Sasl#REUSE */ public static final Option SASL_REUSE = Option.simple(Options.class, "SASL_REUSE", Boolean.class); /** * A list of SASL mechanisms, in decreasing order of preference. */ public static final Option> SASL_MECHANISMS = Option.sequence(Options.class, "SASL_MECHANISMS", String.class); /** * A list of disallowed SASL mechanisms. */ public static final Option> SASL_DISALLOWED_MECHANISMS = Option.sequence(Options.class, "SASL_DISALLOWED_MECHANISMS", String.class); /** * A list of provider specific SASL properties. */ public static final Option> SASL_PROPERTIES = Option.sequence(Options.class, "SASL_PROPERTIES", Property.class); /** * The file access mode to use when opening a file. */ public static final Option FILE_ACCESS = Option.simple(Options.class, "FILE_ACCESS", FileAccess.class); /** * A flag which indicates that opened files should be appended to. Some platforms do not support both append and * {@link FileAccess#READ_WRITE} at the same time. */ public static final Option FILE_APPEND = Option.simple(Options.class, "FILE_APPEND", Boolean.class); /** * A flag which indicates that a file should be created if it does not exist ({@code true} by default for writing files, * {@code false} by default for reading files). */ public static final Option FILE_CREATE = Option.simple(Options.class, "FILE_CREATE", Boolean.class); /** * The stack size (in bytes) to attempt to use for worker threads. */ public static final Option STACK_SIZE = Option.simple(Options.class, "STACK_SIZE", Long.class); /** * The name to use for a newly created worker. If not specified, the string "XNIO" will be used. The worker name * is used as a part of the thread name for created threads, and for any management constructs. */ public static final Option WORKER_NAME = Option.simple(Options.class, "WORKER_NAME", String.class); /** * The thread priority for newly created worker threads. If not specified, the platform default value will be used. */ public static final Option THREAD_PRIORITY = Option.simple(Options.class, "THREAD_PRIORITY", Integer.class); /** * Specify whether worker threads should be daemon threads. Defaults to {@code false}. */ public static final Option THREAD_DAEMON = Option.simple(Options.class, "THREAD_DAEMON", Boolean.class); /** * Specify the number of I/O threads to create for the worker. If not specified, a default will be chosen. */ public static final Option WORKER_IO_THREADS = Option.simple(Options.class, "WORKER_IO_THREADS", Integer.class); /** * Specify the number of read threads to create for the worker. If not specified, a default will be chosen. * * @deprecated Use {@link #WORKER_IO_THREADS} instead. */ @Deprecated public static final Option WORKER_READ_THREADS = Option.simple(Options.class, "WORKER_READ_THREADS", Integer.class); /** * Specify the number of write threads to create for the worker. If not specified, a default will be chosen. * * @deprecated Use {@link #WORKER_IO_THREADS} instead. */ @Deprecated public static final Option WORKER_WRITE_THREADS = Option.simple(Options.class, "WORKER_WRITE_THREADS", Integer.class); /** * Specify whether a server, acceptor, or connector should be attached to write threads. By default, the establishing * phase of connections are attached to read threads. Use this option if the client or server writes a message * directly upon connect. */ public static final Option WORKER_ESTABLISH_WRITING = Option.simple(Options.class, "WORKER_ESTABLISH_WRITING", Boolean.class); /** * Specify the number of accept threads a single socket server should have. Specifying more than one can result in spurious wakeups * for a socket server under low connection volume, but higher throughput at high connection volume. The minimum value * is 1, and the maximum value is equal to the number of available worker threads. */ @Deprecated public static final Option WORKER_ACCEPT_THREADS = Option.simple(Options.class, "WORKER_ACCEPT_THREADS", Integer.class); /** * Specify the number of "core" threads for the worker task thread pool. */ public static final Option WORKER_TASK_CORE_THREADS = Option.simple(Options.class, "WORKER_TASK_CORE_THREADS", Integer.class); /** * Specify the maximum number of threads for the worker task thread pool. */ public static final Option WORKER_TASK_MAX_THREADS = Option.simple(Options.class, "WORKER_TASK_MAX_THREADS", Integer.class); /** * Specify the number of milliseconds to keep non-core task threads alive. */ public static final Option WORKER_TASK_KEEPALIVE = Option.simple(Options.class, "WORKER_TASK_KEEPALIVE", Integer.class); /** * Specify the maximum number of worker tasks to allow before rejecting. */ public static final Option WORKER_TASK_LIMIT = Option.simple(Options.class, "WORKER_TASK_LIMIT", Integer.class); /** * Specify that output should be buffered. The exact behavior of the buffering is not specified; it may flush based * on buffered size or time. An explicit {@link SuspendableWriteChannel#flush()} will still cause * the channel to flush its contents immediately. */ public static final Option CORK = Option.simple(Options.class, "CORK", Boolean.class); /** * The high water mark for a server's connections. Once this number of connections have been accepted, accepts * will be suspended for that server. */ public static final Option CONNECTION_HIGH_WATER = Option.simple(Options.class, "CONNECTION_HIGH_WATER", Integer.class); /** * The low water mark for a server's connections. Once the number of active connections have dropped below this * number, accepts can be resumed for that server. */ public static final Option CONNECTION_LOW_WATER = Option.simple(Options.class, "CONNECTION_LOW_WATER", Integer.class); /** * The compression level to apply for compressing streams and channels. */ public static final Option COMPRESSION_LEVEL = Option.simple(Options.class, "COMPRESSION_LEVEL", Integer.class); /** * The compression type to apply for compressing streams and channels. */ public static final Option COMPRESSION_TYPE = Option.simple(Options.class, "COMPRESSION_TYPE", CompressionType.class); /** * The number of balancing tokens, if connection-balancing is enabled. Must be less than the number of I/O threads, * or 0 to disable balancing and just accept opportunistically. */ public static final Option BALANCING_TOKENS = Option.simple(Options.class, "BALANCING_TOKENS", Integer.class); /** * The number of connections to create per connection-balancing token, if connection-balancing is enabled. */ public static final Option BALANCING_CONNECTIONS = Option.simple(Options.class, "BALANCING_CONNECTIONS", Integer.class); /** * The poll interval for poll based file system watchers. Defaults to 5000ms. Ignored on Java 7 and later. */ public static final Option WATCHER_POLL_INTERVAL = Option.simple(Options.class, "WATCHER_POLL_INTERVAL", Integer.class); } xnio-3.3.2.Final/api/src/main/java/org/xnio/PollingFileSystemWatcher.java000066400000000000000000000134721257016060700263020ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio; import java.io.File; import java.io.IOException; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; import java.util.Deque; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.concurrent.atomic.AtomicInteger; import org.xnio._private.Messages; /** * Polling based file system watcher service, for use on JDK6 * * @author Stuart Douglas */ class PollingFileSystemWatcher implements FileSystemWatcher, Runnable { private static final AtomicInteger threadIdCounter = new AtomicInteger(0); public static final String THREAD_NAME = "xnio-polling-file-watcher"; private final Map files = Collections.synchronizedMap(new HashMap()); private final Thread watchThread; private final int pollInterval; private volatile boolean stopped = false; PollingFileSystemWatcher(final String name, int pollInterval, final boolean daemon) { watchThread = new Thread(this, THREAD_NAME + "[" + name + "]-" + threadIdCounter); watchThread.setDaemon(daemon); watchThread.start(); this.pollInterval = pollInterval; } @Override public void run() { while (!stopped) { try { doNotify(); Thread.sleep(pollInterval); } catch (InterruptedException e) { //ignore } } } private void doNotify() { for (Map.Entry entry : files.entrySet()) { Map result = doScan(entry.getKey()); List currentDiff = doDiff(result, entry.getValue().currentFileState); if (!currentDiff.isEmpty()) { entry.getValue().currentFileState = result; for(FileChangeCallback callback : entry.getValue().callbacks) { invokeCallback(callback, currentDiff); } } } } private List doDiff(Map newFileState, Map currentFileState) { final List results = new ArrayList(); final Map currentCopy = new HashMap(currentFileState); for (Map.Entry newEntry : newFileState.entrySet()) { Long old = currentCopy.remove(newEntry.getKey()); if (old == null) { results.add(new FileChangeEvent(newEntry.getKey(), FileChangeEvent.Type.ADDED)); } else { if (!old.equals(newEntry.getValue()) && !newEntry.getKey().isDirectory()) { //we don't add modified events for directories //as we will be generating modified events for the files in the dir anyway results.add(new FileChangeEvent(newEntry.getKey(), FileChangeEvent.Type.MODIFIED)); } } } for (Map.Entry old : currentCopy.entrySet()) { results.add(new FileChangeEvent(old.getKey(), FileChangeEvent.Type.REMOVED)); } return results; } @Override public synchronized void watchPath(File file, FileChangeCallback callback) { PollHolder holder = files.get(file); if(holder == null) { files.put(file, holder = new PollHolder(doScan(file))); } holder.callbacks.add(callback); } @Override public synchronized void unwatchPath(File file, final FileChangeCallback callback) { PollHolder holder = files.get(file); if(holder != null) { holder.callbacks.remove(callback); if(holder.callbacks.isEmpty()) { files.remove(file); } } files.remove(file); } @Override public void close() throws IOException { this.stopped = true; watchThread.interrupt(); } private class PollHolder { Map currentFileState; final List callbacks = new ArrayList(); private PollHolder(Map currentFileState) { this.currentFileState = currentFileState; } } static Map doScan(File file) { final Map results = new HashMap(); final Deque toScan = new ArrayDeque(); toScan.add(file); while (!toScan.isEmpty()) { File next = toScan.pop(); if (next.isDirectory()) { results.put(next, next.lastModified()); File[] list = next.listFiles(); if (list != null) { for (File f : list) { toScan.push(new File(f.getAbsolutePath())); } } } else { results.put(next, next.lastModified()); } } return results; } static void invokeCallback(FileChangeCallback callback, List results) { try { callback.handleChanges(results); } catch (Exception e) { Messages.msg.failedToInvokeFileWatchCallback(e); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/Pool.java000066400000000000000000000004211257016060700222520ustar00rootroot00000000000000 package org.xnio; /** * A generic pooled resource manager. * * @param the resource type * * @apiviz.landmark */ public interface Pool { /** * Allocate a resource from the pool. * * @return the resource */ Pooled allocate(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/Pooled.java000066400000000000000000000032761257016060700225760ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2010 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; /** * A resource which is pooled. * * @param the pooled resource type * @author David M. Lloyd */ public interface Pooled extends AutoCloseable { /** * Discard this resource. Any backing resources corresponding to this pooled resource will be rendered unavailable * until the pooled resource has been garbage-collected. */ void discard(); /** * Free this resource for immediate re-use. The resource must not be accessed again after * calling this method; if it is possible that an instance is still in use, you must call {@link #discard()} instead. */ void free(); /** * Get the pooled resource. * * @return the pooled resource * @throws IllegalStateException if the resource has been freed or discarded already */ T getResource() throws IllegalStateException; /** * Delegates to {@link #free()}. */ void close(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/Property.java000066400000000000000000000074331257016060700231770ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import java.io.Serializable; import static org.xnio._private.Messages.msg; /** * An immutable property represented by a key and value. * * @author Darran Lofthouse */ public final class Property implements Serializable { private static final long serialVersionUID = -4958518978461712277L; private final String key; private final Object value; private Property(final String key, final Object value) { if (key == null) throw msg.nullParameter("key"); if (value == null) throw msg.nullParameter("value"); this.key = key; this.value = value; } private Property(final String key, final String value) { this(key, (Object) value); } /** * Get the key of this key/value Property. * * @return the key. */ public String getKey() { return key; } /** * Get the value of this key/value Property. * * @return the value. */ public Object getValue() { return value; } /** * Get the value of this key/value Property. * * @return the value. */ public String getValue$$bridger() { // If the value is not a String we want a ClassCastException to indicate the error. return (String) value; } /** * Get the {@link String} representation of this property. * * @return the {@link String} representation of this property. */ @Override public String toString() { return "(" + key + "=>" + value.toString() + ")"; } /** * Get the hash code for this Property. * * @return the hash code. */ @Override public int hashCode() { return key.hashCode() * 7 + value.hashCode(); } /** * Determine if this Property equals another Property. * * @param obj the other Property to compare. * @return true if the two Properties are equal. */ @Override public boolean equals(Object obj) { return obj instanceof Property && equals((Property) obj); } /** * Determine if this Property equals another Property. * * @param other the other Property to compare. * @return true if the two Properties are equal. */ public boolean equals(Property other) { return key.equals(other.key) && value.equals(other.value); } /** * Create a new property for the specified key and value. * * @param key the key for new Property * @param value the value for the new Property * @return the newly created Property */ public static Property of(final String key, final Object value) { return new Property(key, value); } /** * Create a new property for the specified key and value. * * @param key the key for new Property * @param value the value for the new Property * @return the newly created Property */ public static Property of(final String key, final String value) { return new Property(key, value); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/ReadPropertyAction.java000066400000000000000000000027561257016060700251340ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2012 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.security.PrivilegedAction; /** * A simple property-read privileged action. * * @author David M. Lloyd */ public final class ReadPropertyAction implements PrivilegedAction { private final String propertyName; private final String defaultValue; /** * Construct a new instance. * * @param propertyName the property name * @param defaultValue the default value */ public ReadPropertyAction(final String propertyName, final String defaultValue) { this.propertyName = propertyName; this.defaultValue = defaultValue; } /** * Run the action. * * @return the property or default value */ public String run() { return System.getProperty(propertyName, defaultValue); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/Result.java000066400000000000000000000017411257016060700226250ustar00rootroot00000000000000 package org.xnio; import java.io.IOException; /** * A handler for the result of an operation. May be used to populate an {@link IoFuture}. */ public interface Result { /** * Set the result for this operation. Any threads blocking on this instance will be unblocked. * * @param result the result to set * * @return {@code false} if the operation was already completed, {@code true} otherwise */ boolean setResult(T result); /** * Set the exception for this operation. Any threads blocking on this instance will be unblocked. * * @param exception the exception to set * * @return {@code false} if the operation was already completed, {@code true} otherwise */ boolean setException(IOException exception); /** * Acknowledge the cancellation of this operation. * * @return {@code false} if the operation was already completed, {@code true} otherwise */ boolean setCancelled(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/Sequence.java000066400000000000000000000122451257016060700231200ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2009 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.io.Serializable; import java.util.Iterator; import java.util.Arrays; import java.util.Collection; import java.util.AbstractList; import java.util.List; import java.util.RandomAccess; import static org.xnio._private.Messages.msg; /** * An immutable sequence of elements. Though this class implements {@link java.util.List}, it is in fact * immutable. * * @param the element type */ public final class Sequence extends AbstractList implements List, RandomAccess, Serializable { private static final long serialVersionUID = 3042164316147742903L; private final Object[] values; private static final Object[] empty = new Object[0]; private Sequence(final Object[] values) { final Object[] realValues = values.clone(); this.values = realValues; for (int i = 0, length = realValues.length; i < length; i++) { if (realValues[i] == null) { throw msg.nullArrayIndex("option", i); } } } private static final Sequence EMPTY = new Sequence(empty); /** * Return a sequence of the given members. * * @param members the members * @param the element type * @return a sequence */ public static Sequence of(T... members) { if (members.length == 0) { return empty(); } else { return new Sequence(members); } } /** * Return a sequence of the given members. * * @param members the members * @param the element type * @return a sequence */ public static Sequence of(Collection members) { if (members instanceof Sequence) { return (Sequence) members; } final Object[] objects = members.toArray(); if (objects.length == 0) { return empty(); } return new Sequence(objects); } /** * Cast a sequence to a different type if all the contained elements are of the subtype. * * @param newType the class to cast to * @param the new type * @return the typecast sequence * @throws ClassCastException if any elements could not be cast */ @SuppressWarnings("unchecked") public Sequence cast(Class newType) throws ClassCastException { for (Object value : values) { newType.cast(value); } return (Sequence) this; } /** * Return an empty sequence. * * @param the element type * @return the empty sequence */ @SuppressWarnings("unchecked") public static Sequence empty() { return (Sequence) EMPTY; } /** * Get an iterator over the elements of this sequence. * * @return an iterator over the elements of this sequence */ @SuppressWarnings("unchecked") public Iterator iterator() { return Arrays.asList((T[]) values).iterator(); } /** * Return the number of elements in this sequence. * * @return the number of elements */ public int size() { return values.length; } /** * Determine whether this sequence is empty. * * @return {@code true} if the sequence has no elements */ public boolean isEmpty() { return values.length == 0; } /** * Get a copy of the values array. * * @return a copy of the values array */ public Object[] toArray() { return values.clone(); } /** * Get the value at a certain index. * * @param index the index * @return the value */ @SuppressWarnings("unchecked") public T get(final int index) { return (T) values[index]; } /** * Determine whether this sequence is equal to another. * * @param other the other sequence * @return {@code true} if they are equal, {@code false} otherwise */ public boolean equals(Object other) { return other instanceof Sequence && equals((Sequence)other); } /** * Determine whether this sequence is equal to another. * * @param other the other sequence * @return {@code true} if they are equal, {@code false} otherwise */ public boolean equals(Sequence other) { return this == other || other != null && Arrays.equals(values, other.values); } /** * Get the hash code for this sequence. * * @return the hash code */ public int hashCode() { return Arrays.hashCode(values); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/SequenceOption.java000066400000000000000000000045771257016060700243220ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import java.util.ArrayList; import java.util.Collection; import java.util.List; import static org.xnio._private.Messages.msg; /** * @author David M. Lloyd */ final class SequenceOption extends Option> { private static final long serialVersionUID = -4328676629293125136L; private final transient Class elementType; private final transient ValueParser parser; SequenceOption(final Class declClass, final String name, final Class elementType) { super(declClass, name); if (elementType == null) { throw msg.nullParameter("elementType"); } this.elementType = elementType; parser = Option.getParser(elementType); } public Sequence cast(final Object o) { if (o == null) { return null; } else if (o instanceof Sequence) { return ((Sequence)o).cast(elementType); } else if (o instanceof Object[]){ return Sequence.of((Object[])o).cast(elementType); } else if (o instanceof Collection) { return Sequence.of((Collection)o).cast(elementType); } else { throw new ClassCastException("Not a sequence"); } } public Sequence parseValue(final String string, final ClassLoader classLoader) throws IllegalArgumentException { final List list = new ArrayList(); if (string.isEmpty()) { return Sequence.empty(); } for (String value : string.split(",")) { list.add(parser.parseValue(value, classLoader)); } return Sequence.of(list); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/SingleOption.java000066400000000000000000000031141257016060700237550ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.xnio._private.Messages.msg; /** * @author David M. Lloyd */ final class SingleOption extends Option { private static final long serialVersionUID = 2449094406108952764L; private final transient Class type; private final transient ValueParser parser; SingleOption(final Class declClass, final String name, final Class type) { super(declClass, name); if (type == null) { throw msg.nullParameter("type"); } this.type = type; parser = Option.getParser(type); } public T cast(final Object o) { return type.cast(o); } public T parseValue(final String string, final ClassLoader classLoader) throws IllegalArgumentException { return parser.parseValue(string, classLoader); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/SslClientAuthMode.java000066400000000000000000000006171257016060700246770ustar00rootroot00000000000000 package org.xnio; /** * The desired SSL client authentication mode for SSL channels in server mode. */ public enum SslClientAuthMode { /** * SSL client authentication is not requested. */ NOT_REQUESTED, /** * SSL client authentication is requested but not required. */ REQUESTED, /** * SSL client authentication is required. */ REQUIRED, } xnio-3.3.2.Final/api/src/main/java/org/xnio/StreamConnection.java000066400000000000000000000063561257016060700246310ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import org.xnio.channels.CloseListenerSettable; import org.xnio.conduits.ConduitStreamSinkChannel; import org.xnio.conduits.ConduitStreamSourceChannel; import org.xnio.conduits.StreamSinkConduit; import org.xnio.conduits.StreamSourceConduit; import static org.xnio._private.Messages.msg; /** * A connection between peers. * * @author David M. Lloyd */ public abstract class StreamConnection extends Connection implements CloseListenerSettable { private ConduitStreamSourceChannel sourceChannel; private ConduitStreamSinkChannel sinkChannel; private ChannelListener closeListener; /** * Construct a new instance. * * @param thread the I/O thread */ protected StreamConnection(final XnioIoThread thread) { super(thread); } public void setCloseListener(final ChannelListener listener) { this.closeListener = listener; } public ChannelListener getCloseListener() { return closeListener; } public ChannelListener.Setter getCloseSetter() { return new Setter(this); } /** * Set the source conduit for this channel. The source channel will automatically be updated. * * @param conduit the source conduit for this channel */ protected void setSourceConduit(StreamSourceConduit conduit) { this.sourceChannel = conduit == null ? null : new ConduitStreamSourceChannel(this, conduit); } /** * Set the sink conduit for this channel. The sink channel will automatically be updated. * * @param conduit the sink conduit for this channel */ protected void setSinkConduit(StreamSinkConduit conduit) { this.sinkChannel = conduit == null ? null : new ConduitStreamSinkChannel(this, conduit); } void invokeCloseListener() { ChannelListeners.invokeChannelListener(this, closeListener); } private static T notNull(T orig) throws IllegalStateException { if (orig == null) { throw msg.channelNotAvailable(); } return orig; } /** * Get the source channel. * * @return the source channel */ public ConduitStreamSourceChannel getSourceChannel() { return notNull(sourceChannel); } /** * Get the sink channel. * * @return the sink channel */ public ConduitStreamSinkChannel getSinkChannel() { return notNull(sinkChannel); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/TranslatingResult.java000066400000000000000000000030551257016060700250340ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2009 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.io.IOException; /** * Abstract base class for {@code Result}s which translate from one type to another. * * @param the result type to accept * @param the result type to pass to the delegate */ public abstract class TranslatingResult implements Result { private final Result output; protected TranslatingResult(final Result output) { this.output = output; } public boolean setException(final IOException exception) { return output.setException(exception); } public boolean setCancelled() { return output.setCancelled(); } public boolean setResult(final T result) { try { return output.setResult(translate(result)); } catch (IOException e) { return output.setException(e); } } protected abstract O translate(T input) throws IOException; } xnio-3.3.2.Final/api/src/main/java/org/xnio/TypeOption.java000066400000000000000000000032711257016060700234610ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.xnio._private.Messages.msg; /** * @author David M. Lloyd */ final class TypeOption extends Option> { private static final long serialVersionUID = 2449094406108952764L; private final transient Class type; private final transient ValueParser> parser; TypeOption(final Class declClass, final String name, final Class type) { super(declClass, name); if (type == null) { throw msg.nullParameter("type"); } this.type = type; parser = Option.getClassParser(type); } public Class cast(final Object o) { return ((Class) o).asSubclass(type); } public Class parseValue(final String string, final ClassLoader classLoader) throws IllegalArgumentException { return (Class) parser.parseValue(string, classLoader); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/TypeSequenceOption.java000066400000000000000000000054571257016060700251620ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import java.util.ArrayList; import java.util.Collection; import java.util.List; import static org.xnio._private.Messages.msg; /** * @author David M. Lloyd */ final class TypeSequenceOption extends Option>> { private static final long serialVersionUID = -4328676629293125136L; private final transient Class elementDeclType; private final transient ValueParser> parser; TypeSequenceOption(final Class declClass, final String name, final Class elementDeclType) { super(declClass, name); if (elementDeclType == null) { throw msg.nullParameter("elementDeclType"); } this.elementDeclType = elementDeclType; parser = Option.getClassParser(elementDeclType); } public Sequence> cast(final Object o) { if (o == null) { return null; } else if (o instanceof Sequence) { return castSeq((Sequence) o, elementDeclType); } else if (o instanceof Object[]){ return castSeq(Sequence.of((Object[]) o), elementDeclType); } else if (o instanceof Collection) { return castSeq(Sequence.of((Collection) o), elementDeclType); } else { throw new ClassCastException("Not a sequence"); } } @SuppressWarnings("unchecked") static Sequence> castSeq(Sequence seq, Class type) { for (Object o : seq) { ((Class)o).asSubclass(type); } return (Sequence>) seq; } public Sequence> parseValue(final String string, final ClassLoader classLoader) throws IllegalArgumentException { final List> list = new ArrayList>(); if (string.isEmpty()) { return Sequence.empty(); } for (String value : string.split(",")) { list.add(parser.parseValue(value, classLoader)); } return Sequence.of(list); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/Version.java000066400000000000000000000050161257016060700227730ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2014 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Properties; /** * The version class. * * @apiviz.exclude */ public final class Version { private Version() {} /** * Print out the current XNIO version on {@code System.out}. * * @param args ignored */ public static void main(String[] args) { System.out.print(VERSION); } private static final String JAR_NAME; public static final String VERSION; static { Properties versionProps = new Properties(); String jarName = "(unknown)"; String versionString = "(unknown)"; try { final InputStream stream = Version.class.getResourceAsStream("Version.properties"); try { final InputStreamReader reader = new InputStreamReader(stream); try { versionProps.load(reader); jarName = versionProps.getProperty("jarName", jarName); versionString = versionProps.getProperty("version", versionString); } finally { try { reader.close(); } catch (Throwable ignored) { } } } finally { try { stream.close(); } catch (Throwable ignored) { } } } catch (IOException ignored) { } JAR_NAME = jarName; VERSION = versionString; } /** * Get the name of the program JAR. * * @return the name */ public static String getJarName() { return JAR_NAME; } /** * Get the version string. * * @return the version string */ public static String getVersionString() { return VERSION; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/Xnio.java000066400000000000000000000542661257016060700222760ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.io.Closeable; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; import java.lang.management.ManagementFactory; import java.net.InetSocketAddress; import java.nio.channels.FileChannel; import java.nio.file.NoSuchFileException; import java.nio.file.StandardOpenOption; import java.security.AccessController; import java.security.GeneralSecurityException; import java.security.PrivilegedAction; import java.util.EnumMap; import java.util.EnumSet; import java.util.Iterator; import java.util.ServiceLoader; import java.util.concurrent.atomic.AtomicBoolean; import javax.management.InstanceAlreadyExistsException; import javax.management.InstanceNotFoundException; import javax.management.MBeanRegistrationException; import javax.management.MBeanServer; import javax.management.MalformedObjectNameException; import javax.management.NotCompliantMBeanException; import javax.management.ObjectName; import org.xnio.management.XnioProviderMXBean; import org.xnio.management.XnioServerMXBean; import org.xnio.management.XnioWorkerMXBean; import org.xnio.ssl.JsseSslUtils; import org.xnio.ssl.JsseXnioSsl; import org.xnio.ssl.XnioSsl; import javax.net.ssl.KeyManager; import javax.net.ssl.TrustManager; import static java.security.AccessController.doPrivileged; import static org.xnio._private.Messages.msg; /** * The XNIO provider class. * * @apiviz.landmark */ @SuppressWarnings("unused") public abstract class Xnio { static final InetSocketAddress ANY_INET_ADDRESS = new InetSocketAddress(0); static final LocalSocketAddress ANY_LOCAL_ADDRESS = new LocalSocketAddress(""); private static final EnumMap FILE_ACCESS_OPTION_MAPS; private static final RuntimePermission ALLOW_BLOCKING_SETTING = new RuntimePermission("changeThreadBlockingSetting"); private static final MBeanServer MBEAN_SERVER; /** * A flag indicating the presence of NIO.2 (JDK 7). */ public static final boolean NIO2; static { boolean nio2 = false; try { // try to find an NIO.2 interface on the system class path Class.forName("java.nio.channels.MulticastChannel", false, null); nio2 = true; } catch (Throwable t) { } NIO2 = nio2; msg.greeting(Version.VERSION); final EnumMap map = new EnumMap(FileAccess.class); for (FileAccess access : FileAccess.values()) { map.put(access, OptionMap.create(Options.FILE_ACCESS, access)); } FILE_ACCESS_OPTION_MAPS = map; MBEAN_SERVER = doPrivileged(new PrivilegedAction() { public MBeanServer run() { return ManagementFactory.getPlatformMBeanServer(); } }); } /** * The name of this provider instance. */ private final String name; /** * Construct an XNIO provider instance. Used by implementors only. To get an XNIO instance, * use one of the {@link org.xnio.Xnio#getInstance()} methods. * * @param name the provider name */ protected Xnio(String name) { if (name == null) { throw msg.nullParameter("name"); } this.name = name; } private static final ThreadLocal BLOCKING = new ThreadLocal() { protected Boolean initialValue() { return Boolean.TRUE; } }; /** * Allow (or disallow) blocking I/O on the current thread. Requires the {@code changeThreadBlockingSetting} * {@link RuntimePermission}. * * @param newSetting {@code true} to allow blocking I/O, {@code false} to disallow it * @return the previous setting * @throws SecurityException if a security manager is present and disallows changing the {@code changeThreadBlockingSetting} {@code RuntimePermission} */ public static boolean allowBlocking(boolean newSetting) throws SecurityException { final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(ALLOW_BLOCKING_SETTING); } final ThreadLocal threadLocal = BLOCKING; try { return threadLocal.get().booleanValue(); } finally { threadLocal.set(Boolean.valueOf(newSetting)); } } /** * Determine whether blocking I/O is allowed from the current thread. * * @return {@code true} if blocking I/O is allowed, {@code false} otherwise */ public static boolean isBlockingAllowed() { return BLOCKING.get().booleanValue(); } /** * Perform a check for whether blocking is allowed on the current thread. * * @throws IllegalStateException if blocking is not allowed on the current thread */ public static void checkBlockingAllowed() throws IllegalStateException { if (! BLOCKING.get().booleanValue()) { throw msg.blockingNotAllowed(); } } /** * Get an XNIO provider instance. If multiple providers are * available, use the first one encountered. * * @param classLoader the class loader to search in * @return the XNIO provider instance * * @since 3.0 */ public static Xnio getInstance(ClassLoader classLoader) { return doGetInstance(null, ServiceLoader.load(XnioProvider.class, classLoader)); } /** * Get an XNIO provider instance from XNIO's class loader. If multiple providers are * available, use the first one encountered. * * @return the XNIO provider instance * * @since 3.0 */ public static Xnio getInstance() { return doGetInstance(null, ServiceLoader.load(XnioProvider.class, Xnio.class.getClassLoader())); } /** * Get a specific XNIO provider instance. * * @param provider the provider name, or {@code null} for the first available * @param classLoader the class loader to search in * @return the XNIO provider instance * * @since 3.0 */ public static Xnio getInstance(String provider, ClassLoader classLoader) { return doGetInstance(provider, ServiceLoader.load(XnioProvider.class, classLoader)); } /** * Get a specific XNIO provider instance from XNIO's class loader. * * @param provider the provider name, or {@code null} for the first available * @return the XNIO provider instance * * @since 3.0 */ public static Xnio getInstance(String provider) { return doGetInstance(provider, ServiceLoader.load(XnioProvider.class, Xnio.class.getClassLoader())); } private static Xnio doGetInstance(final String provider, final ServiceLoader serviceLoader) { final Iterator iterator = serviceLoader.iterator(); for (;;) { try { if (! iterator.hasNext()) break; final XnioProvider xnioProvider = iterator.next(); try { if (provider == null || provider.equals(xnioProvider.getName())) { return xnioProvider.getInstance(); } } catch (Throwable t) { msg.debugf(t, "Not loading provider %s", xnioProvider.getName()); } } catch (Throwable t) { msg.debugf(t, "Skipping non-loadable provider"); } } throw msg.noProviderFound(); } //================================================== // // SSL methods // //================================================== /** * Get an SSL provider for this XNIO provider. * * @param optionMap the option map to use for configuring SSL * @return the SSL provider * @throws GeneralSecurityException if an exception occurred configuring the SSL provider */ public XnioSsl getSslProvider(final OptionMap optionMap) throws GeneralSecurityException { return new JsseXnioSsl(this, optionMap); } /** * Get an SSL provider for this XNIO provider. * * @param optionMap the option map to use for configuring SSL * @param keyManagers the key managers to use, or {@code null} to configure from the option map * @param trustManagers the trust managers to use, or {@code null} to configure from the option map * @return the SSL provider * @throws GeneralSecurityException if an exception occurred configuring the SSL provider */ public XnioSsl getSslProvider(final KeyManager[] keyManagers, final TrustManager[] trustManagers, final OptionMap optionMap) throws GeneralSecurityException { return new JsseXnioSsl(this, optionMap, JsseSslUtils.createSSLContext(keyManagers, trustManagers, null, optionMap)); } //================================================== // // File system methods // //================================================== private interface Opener { FileChannel openFile(File file, OptionMap options) throws IOException; } private static final Opener OPENER = NIO2 ? new Nio2Opener() : new Nio1Opener(); private static final class Nio1Opener implements Opener { public FileChannel openFile(final File file, final OptionMap options) throws IOException { final FileAccess fileAccess = options.get(Options.FILE_ACCESS, FileAccess.READ_WRITE); final boolean append = options.get(Options.FILE_APPEND, false); final boolean create = options.get(Options.FILE_CREATE, fileAccess != FileAccess.READ_ONLY); if (fileAccess == FileAccess.READ_ONLY) { if (append) { throw msg.readAppendNotSupported(); } if (create) { throw msg.openModeRequires7(); } return new XnioFileChannel(new FileInputStream(file).getChannel()); } else if (fileAccess == FileAccess.READ_WRITE) { if (append) { throw msg.openModeRequires7(); } if (! create) { throw msg.openModeRequires7(); } return new XnioFileChannel(new RandomAccessFile(file, "rw").getChannel()); } else if (fileAccess == FileAccess.WRITE_ONLY) { if (! create) { throw msg.openModeRequires7(); } return new XnioFileChannel(new FileOutputStream(file, append).getChannel()); } else { throw new IllegalStateException(); } } } private static final class Nio2Opener implements Opener { public FileChannel openFile(final File file, final OptionMap options) throws IOException { try { final FileAccess fileAccess = options.get(Options.FILE_ACCESS, FileAccess.READ_WRITE); final boolean append = options.get(Options.FILE_APPEND, false); final boolean create = options.get(Options.FILE_CREATE, fileAccess != FileAccess.READ_ONLY); final EnumSet openOptions = EnumSet.noneOf(StandardOpenOption.class); if (create) { openOptions.add(StandardOpenOption.CREATE); } if (fileAccess.isRead()) { openOptions.add(StandardOpenOption.READ); } if (fileAccess.isWrite()) { openOptions.add(StandardOpenOption.WRITE); } if (append) { openOptions.add(StandardOpenOption.APPEND); } return new XnioFileChannel(FileChannel.open(file.toPath(), openOptions.toArray(new StandardOpenOption[openOptions.size()]))); } catch (NoSuchFileException e) { throw new FileNotFoundException(e.getMessage()); } } } /** * Open a file on the filesystem. * * @param file the file to open * @param options the file-open options * @return the file channel * @throws IOException if an I/O error occurs */ public FileChannel openFile(File file, OptionMap options) throws IOException { if (file == null) { throw msg.nullParameter("file"); } if (options == null) { throw msg.nullParameter("options"); } return OPENER.openFile(file, options); } /** * Open a file on the filesystem. * * @param fileName the file name of the file to open * @param options the file-open options * @return the file channel * @throws IOException if an I/O error occurs */ public FileChannel openFile(String fileName, OptionMap options) throws IOException { if (fileName == null) { throw msg.nullParameter("fileName"); } return openFile(new File(fileName), options); } /** * Open a file on the filesystem. * * @param file the file to open * @param access the file access level to use * @return the file channel * @throws IOException if an I/O error occurs */ public FileChannel openFile(File file, FileAccess access) throws IOException { if (access == null) { throw msg.nullParameter("access"); } return openFile(file, FILE_ACCESS_OPTION_MAPS.get(access)); } /** * Open a file on the filesystem. * * @param fileName the file name of the file to open * @param access the file access level to use * @return the file channel * @throws IOException if an I/O error occurs */ public FileChannel openFile(String fileName, FileAccess access) throws IOException { if (access == null) { throw msg.nullParameter("access"); } if (fileName == null) { throw msg.nullParameter("fileName"); } return openFile(new File(fileName), FILE_ACCESS_OPTION_MAPS.get(access)); } /** * Unwrap an XNIO-wrapped file channel. For use by providers. * * @param src the possibly wrapped file channel * @return the unwrapped file channel */ protected FileChannel unwrapFileChannel(FileChannel src) { if (src instanceof XnioFileChannel) { return ((XnioFileChannel)src).getDelegate(); } else { return src; } } //================================================== // // Worker methods // //================================================== /** * Construct a new XNIO worker. * * @param optionMap the options to use to configure the worker * @return the new worker * @throws IOException if the worker failed to be opened * @throws IllegalArgumentException if an option value is invalid for this worker */ public XnioWorker createWorker(OptionMap optionMap) throws IOException, IllegalArgumentException { return createWorker(null, optionMap); } /** * Construct a new XNIO worker. * * @param threadGroup the thread group for worker threads * @param optionMap the options to use to configure the worker * @return the new worker * @throws IOException if the worker failed to be opened * @throws IllegalArgumentException if an option value is invalid for this worker */ public XnioWorker createWorker(ThreadGroup threadGroup, OptionMap optionMap) throws IOException, IllegalArgumentException { return createWorker(threadGroup, optionMap, null); } /** * Construct a new XNIO worker. * * @param threadGroup the thread group for worker threads * @param optionMap the options to use to configure the worker * @param terminationTask the task to run after the worker has shut down * @return the new worker * @throws IOException if the worker failed to be opened * @throws IllegalArgumentException if an option value is invalid for this worker */ public abstract XnioWorker createWorker(ThreadGroup threadGroup, OptionMap optionMap, Runnable terminationTask) throws IOException, IllegalArgumentException; /** * Creates a file system watcher, that can be used to monitor file system changes. * * @param name The watcher name * @param options The options to use to create the watcher * @return The file system watcher */ public FileSystemWatcher createFileSystemWatcher(final String name, final OptionMap options) { int pollInterval = options.get(Options.WATCHER_POLL_INTERVAL, 5000); boolean daemonThread = options.get(Options.THREAD_DAEMON, true); return new PollingFileSystemWatcher(name, pollInterval, daemonThread); } //================================================== // // General methods // //================================================== /** * Get the name of this XNIO provider. * * @return the name */ public final String getName() { return name; } /** * Get a string representation of this XNIO provider. * * @return the string representation */ public final String toString() { return String.format("XNIO provider \"%s\" <%s@%s>", getName(), getClass().getName(), Integer.toHexString(hashCode())); } /** * Get an XNIO property. The property name must start with {@code "xnio."}. * * @param name the property name * @return the property value, or {@code null} if it wasn't found * @since 1.2 */ protected static String getProperty(final String name) { if (! name.startsWith("xnio.")) { throw msg.propReadForbidden(); } final SecurityManager sm = System.getSecurityManager(); if (sm != null) { return AccessController.doPrivileged(new ReadPropertyAction(name, null)); } else { return System.getProperty(name); } } /** * Get an XNIO property. The property name must start with {@code "xnio."}. * * @param name the property name * @param defaultValue the default value * @return the property value, or {@code defaultValue} if it wasn't found * @since 1.2 */ protected static String getProperty(final String name, final String defaultValue) { if (! name.startsWith("xnio.")) { throw msg.propReadForbidden(); } final SecurityManager sm = System.getSecurityManager(); if (sm != null) { return AccessController.doPrivileged(new ReadPropertyAction(name, defaultValue)); } else { return System.getProperty(name, defaultValue); } } /** * Register an MBean. If the MBean cannot be registered, this method will simply return. * * @param providerMXBean the provider MBean to register * @return a handle which may be used to remove the registration */ protected static Closeable register(XnioProviderMXBean providerMXBean) { try { final ObjectName objectName = new ObjectName("org.xnio", ObjectProperties.properties(ObjectProperties.property("type", "Xnio"), ObjectProperties.property("provider", ObjectName.quote(providerMXBean.getName())))); MBEAN_SERVER.registerMBean(providerMXBean, objectName); return new MBeanCloseable(objectName); } catch (Exception ignored) { return IoUtils.nullCloseable(); } } /** * Register an MBean. If the MBean cannot be registered, this method will simply return. * * @param workerMXBean the worker MBean to register * @return a handle which may be used to remove the registration */ protected static Closeable register(XnioWorkerMXBean workerMXBean) { try { final ObjectName objectName = new ObjectName("org.xnio", ObjectProperties.properties(ObjectProperties.property("type", "Xnio"), ObjectProperties.property("provider", ObjectName.quote(workerMXBean.getProviderName())), ObjectProperties.property("worker", ObjectName.quote(workerMXBean.getName())))); MBEAN_SERVER.registerMBean(workerMXBean, objectName); return new MBeanCloseable(objectName); } catch (Exception ignored) { return IoUtils.nullCloseable(); } } /** * Register an MBean. If the MBean cannot be registered, this method will simply return. * * @param serverMXBean the server MBean to register * @return a handle which may be used to remove the registration */ protected static Closeable register(XnioServerMXBean serverMXBean) { try { final ObjectName objectName = new ObjectName("org.xnio", ObjectProperties.properties(ObjectProperties.property("type", "Xnio"), ObjectProperties.property("provider", ObjectName.quote(serverMXBean.getProviderName())), ObjectProperties.property("worker", ObjectName.quote(serverMXBean.getWorkerName())), ObjectProperties.property("address", ObjectName.quote(serverMXBean.getBindAddress())))); MBEAN_SERVER.registerMBean(serverMXBean, objectName); return new MBeanCloseable(objectName); } catch (Exception ignored) { return IoUtils.nullCloseable(); } } static class MBeanCloseable extends AtomicBoolean implements Closeable { private final ObjectName objectName; MBeanCloseable(final ObjectName objectName) { this.objectName = objectName; } public void close() { if (! getAndSet(true)) try { MBEAN_SERVER.unregisterMBean(objectName); } catch (Exception ignored) { } } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/XnioExecutor.java000066400000000000000000000060001257016060700237740ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; /** * An executor with the capability to run timed, cancellable tasks. * * @author David M. Lloyd */ @SuppressWarnings("unused") public interface XnioExecutor extends Executor { /** * Execute a task in this executor. * * @param command the command to run */ void execute(Runnable command); /** * Execute a command after a period of time. At least the amount of time given in {@code time} will * have elapsed when the task is run. The returned key may be used to cancel the task before it runs. * * @param command the command to execute * @param time the amount of time to delay, or {@code 0} to run immediately * @param unit the time unit to apply to {@code time} * @return a key which may be used to cancel this task before it executes */ Key executeAfter(Runnable command, long time, TimeUnit unit); /** * Execute a command repeatedly at a time interval until it is cancelled. At least the amount of time given in * {@code time} will have elapsed when the task is first run, and again for each subsequent run. The returned key * may be used to cancel the task before it runs. * * @param command the command to execute * @param time the amount of time to delay, or {@code 0} to run immediately * @param unit the time unit to apply to {@code time} * @return a key which may be used to cancel this task before it executes */ Key executeAtInterval(Runnable command, long time, TimeUnit unit); /** * A task key for a timeout task. */ interface Key { /** * Remove a previously-submitted task. * * @return {@code true} if the task was cancelled; {@code false} if it already ran */ boolean remove(); /** * An immediate key. When the time delay is <= 0, this may be returned and the task immediately run. */ XnioExecutor.Key IMMEDIATE = new XnioExecutor.Key() { public boolean remove() { return false; } public String toString() { return "Immediate key"; } }; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/XnioFileChannel.java000066400000000000000000000076361257016060700243660ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; final class XnioFileChannel extends FileChannel { private final FileChannel delegate; XnioFileChannel(final FileChannel delegate) { this.delegate = delegate; } public int read(final ByteBuffer dst) throws IOException { return delegate.read(dst); } public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { return delegate.read(dsts, offset, length); } public int write(final ByteBuffer src) throws IOException { return delegate.write(src); } public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException { return delegate.write(srcs, offset, length); } public long position() throws IOException { return delegate.position(); } public FileChannel position(final long newPosition) throws IOException { return delegate.position(newPosition); } public long size() throws IOException { return delegate.size(); } public FileChannel truncate(final long size) throws IOException { return delegate.truncate(size); } public void force(final boolean metaData) throws IOException { delegate.force(metaData); } public long transferTo(final long position, final long count, final WritableByteChannel target) throws IOException { if (target instanceof StreamSinkChannel) { return ((StreamSinkChannel) target).transferFrom(delegate, position, count); } else { return delegate.transferTo(position, count, target); } } public long transferFrom(final ReadableByteChannel src, final long position, final long count) throws IOException { if (src instanceof StreamSourceChannel) { return ((StreamSourceChannel) src).transferTo(position, count, delegate); } else { return delegate.transferFrom(src, position, count); } } public int read(final ByteBuffer dst, final long position) throws IOException { return delegate.read(dst, position); } public int write(final ByteBuffer src, final long position) throws IOException { return delegate.write(src, position); } public MappedByteBuffer map(final MapMode mode, final long position, final long size) throws IOException { return delegate.map(mode, position, size); } public FileLock lock(final long position, final long size, final boolean shared) throws IOException { return delegate.lock(position, size, shared); } public FileLock tryLock(final long position, final long size, final boolean shared) throws IOException { return delegate.tryLock(position, size, shared); } public void implCloseChannel() throws IOException { delegate.close(); } FileChannel getDelegate() { return delegate; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/XnioIoFactory.java000066400000000000000000000155701257016060700241110ustar00rootroot00000000000000package org.xnio; import java.io.IOException; import java.net.SocketAddress; import org.xnio.channels.BoundChannel; import org.xnio.channels.StreamChannel; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; /** * An XNIO I/O factory which can be used to create channels. * * @author David M. Lloyd */ public interface XnioIoFactory { /** * Connect to a remote stream server. The protocol family is determined by the type of the socket address given. * If an open listener is used, the channel should not be accessed via the returned * {@code IoFuture}, and vice-versa. * * @param destination the destination address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param optionMap the option map * @return the future result of this operation */ IoFuture openStreamConnection(SocketAddress destination, ChannelListener openListener, OptionMap optionMap); /** * Connect to a remote stream server. The protocol family is determined by the type of the socket address given. * If an open listener is used, the channel should not be accessed via the returned * {@code IoFuture}, and vice-versa. * * @param destination the destination address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param bindListener the listener which will be notified when the channel is bound, or {@code null} for none * @param optionMap the option map * @return the future result of this operation */ IoFuture openStreamConnection(SocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap); /** * Connect to a remote stream server. The protocol family is determined by the type of the socket addresses given * (which must match). If an open listener is used, the channel should not be accessed via the returned * {@code IoFuture}, and vice-versa. * * @param bindAddress the local address to bind to * @param destination the destination address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param bindListener the listener which will be notified when the channel is bound, or {@code null} for none * @param optionMap the option map * @return the future result of this operation */ IoFuture openStreamConnection(SocketAddress bindAddress, SocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap); /** * Accept a stream connection at a destination address. If a wildcard address is specified, then a destination address * is chosen in a manner specific to the OS and/or channel type. * * @param destination the destination (bind) address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param bindListener the listener which will be notified when the acceptor is bound, or {@code null} for none * @param optionMap the option map * @return the future connection */ IoFuture acceptStreamConnection(SocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap); /** * Connect to a remote message server. The protocol family is determined by the type of the socket address given. * If an open listener is used, the channel should not be accessed via the returned * {@code IoFuture}, and vice-versa. * * @param destination the destination address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param optionMap the option map * @return the future result of this operation */ IoFuture openMessageConnection(SocketAddress destination, ChannelListener openListener, OptionMap optionMap); /** * Accept a message connection at a destination address. If a wildcard address is specified, then a destination address * is chosen in a manner specific to the OS and/or channel type. If an open listener is used, the channel should * not be accessed via the returned {@code IoFuture}, and vice-versa. * * @param destination the destination (bind) address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param bindListener the listener which will be notified when the acceptor is bound, or {@code null} for none * @param optionMap the option map * @return the future connection */ IoFuture acceptMessageConnection(SocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap); /** * Create a two-way stream pipe. * * @return the created pipe * @throws java.io.IOException if the pipe could not be created */ ChannelPipe createFullDuplexPipe() throws IOException; /** * Create a two-way stream pipe. * * @return the created pipe * @throws java.io.IOException if the pipe could not be created */ ChannelPipe createFullDuplexPipeConnection() throws IOException; /** * Create a one-way stream pipe. * * @return the created pipe * @throws java.io.IOException if the pipe could not be created */ ChannelPipe createHalfDuplexPipe() throws IOException; /** * Create a two-way stream pipe. The left side will be associated with this factory, and the right * side will be associated with the given peer. * * @param peer the peer to use for controlling the remote (right) side * @return the created pipe * @throws java.io.IOException if the pipe could not be created */ ChannelPipe createFullDuplexPipeConnection(XnioIoFactory peer) throws IOException; /** * Create a one-way stream pipe. The left (source) side will be associated with this factory, and the right * (sink) side will be associated with the given peer. * * @param peer the peer to use for the sink (right) side * @return the created pipe * @throws java.io.IOException if the pipe could not be created */ ChannelPipe createHalfDuplexPipe(XnioIoFactory peer) throws IOException; } xnio-3.3.2.Final/api/src/main/java/org/xnio/XnioIoThread.java000066400000000000000000000353051257016060700237070ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import org.xnio.channels.AssembledStreamChannel; import org.xnio.channels.BoundChannel; import org.xnio.channels.StreamChannel; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; import static org.xnio._private.Messages.msg; /** * An XNIO thread. * * @author David M. Lloyd */ @SuppressWarnings("unused") public abstract class XnioIoThread extends Thread implements XnioExecutor, XnioIoFactory { private final XnioWorker worker; private final int number; /** * Construct a new instance. * * @param worker the XNIO worker to associate with * @param number the thread number */ protected XnioIoThread(final XnioWorker worker, final int number) { this.number = number; this.worker = worker; } /** * Construct a new instance. * * @param worker the XNIO worker to associate with * @param number the thread number * @param name the thread name */ protected XnioIoThread(final XnioWorker worker, final int number, final String name) { super(name); this.number = number; this.worker = worker; } /** * Construct a new instance. * * @param worker the XNIO worker to associate with * @param number the thread number * @param group the thread group * @param name the thread name */ protected XnioIoThread(final XnioWorker worker, final int number, final ThreadGroup group, final String name) { super(group, name); this.number = number; this.worker = worker; } /** * Construct a new instance. * * @param worker the XNIO worker to associate with * @param number the thread number * @param group the thread group * @param name the thread name * @param stackSize the thread stack size */ protected XnioIoThread(final XnioWorker worker, final int number, final ThreadGroup group, final String name, final long stackSize) { super(group, null, name, stackSize); this.number = number; this.worker = worker; } /** * Get the current XNIO thread. If the current thread is not an XNIO thread, {@code null} is returned. * * @return the current XNIO thread */ public static XnioIoThread currentThread() { final Thread thread = Thread.currentThread(); if (thread instanceof XnioIoThread) { return (XnioIoThread) thread; } else { return null; } } /** * Get the current XNIO thread. If the current thread is not an XNIO thread, an {@link IllegalStateException} is * thrown. * * @return the current XNIO thread * @throws IllegalStateException if the current thread is not an XNIO thread */ public static XnioIoThread requireCurrentThread() throws IllegalStateException { final XnioIoThread thread = currentThread(); if (thread == null) { throw msg.xnioThreadRequired(); } return thread; } /** * Get the number of this thread. In each XNIO worker, every IO thread is given a unique, sequential number. * * @return the number of this thread */ public int getNumber() { return number; } /** * Get the XNIO worker associated with this thread. * * @return the XNIO worker */ public XnioWorker getWorker() { return worker; } public IoFuture acceptStreamConnection(SocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { if (destination == null) { throw msg.nullParameter("destination"); } if (destination instanceof InetSocketAddress) { return acceptTcpStreamConnection((InetSocketAddress) destination, openListener, bindListener, optionMap); } else if (destination instanceof LocalSocketAddress) { return acceptLocalStreamConnection((LocalSocketAddress) destination, openListener, bindListener, optionMap); } else { throw msg.badSockType(destination.getClass()); } } /** * Implementation helper method to accept a local (UNIX domain) stream connection. * * @param destination the destination (bind) address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param bindListener the listener which will be notified when the acceptor is bound, or {@code null} for none * @param optionMap the option map * * @return the future connection */ protected IoFuture acceptLocalStreamConnection(LocalSocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { throw msg.unsupported("acceptLocalStreamConnection"); } /** * Implementation helper method to accept a TCP connection. * * @param destination the destination (bind) address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param bindListener the listener which will be notified when the acceptor is bound, or {@code null} for none * @param optionMap the option map * * @return the future connection */ protected IoFuture acceptTcpStreamConnection(InetSocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { throw msg.unsupported("acceptTcpStreamConnection"); } public IoFuture openMessageConnection(final SocketAddress destination, final ChannelListener openListener, final OptionMap optionMap) { if (destination == null) { throw msg.nullParameter("destination"); } if (destination instanceof LocalSocketAddress) { return openLocalMessageConnection(Xnio.ANY_LOCAL_ADDRESS, (LocalSocketAddress) destination, openListener, optionMap); } else { throw msg.badSockType(destination.getClass()); } } public IoFuture acceptMessageConnection(final SocketAddress destination, final ChannelListener openListener, final ChannelListener bindListener, final OptionMap optionMap) { if (destination == null) { throw msg.nullParameter("destination"); } if (destination instanceof LocalSocketAddress) { return acceptLocalMessageConnection((LocalSocketAddress) destination, openListener, bindListener, optionMap); } else { throw msg.badSockType(destination.getClass()); } } /** * Implementation helper method to accept a local (UNIX domain) datagram connection. * * @param destination the destination (bind) address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param bindListener the listener which will be notified when the acceptor is bound, or {@code null} for none * @param optionMap the option map * * @return the future connection */ protected IoFuture acceptLocalMessageConnection(LocalSocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { throw msg.unsupported("acceptLocalMessageConnection"); } public IoFuture openStreamConnection(SocketAddress destination, ChannelListener openListener, OptionMap optionMap) { if (destination == null) { throw msg.nullParameter("destination"); } if (destination instanceof InetSocketAddress) { return openTcpStreamConnection(Xnio.ANY_INET_ADDRESS, (InetSocketAddress) destination, openListener, null, optionMap); } else if (destination instanceof LocalSocketAddress) { return openLocalStreamConnection(Xnio.ANY_LOCAL_ADDRESS, (LocalSocketAddress) destination, openListener, null, optionMap); } else { throw msg.badSockType(destination.getClass()); } } public IoFuture openStreamConnection(SocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { if (destination == null) { throw msg.nullParameter("destination"); } if (destination instanceof InetSocketAddress) { return openTcpStreamConnection(Xnio.ANY_INET_ADDRESS, (InetSocketAddress) destination, openListener, bindListener, optionMap); } else if (destination instanceof LocalSocketAddress) { return openLocalStreamConnection(Xnio.ANY_LOCAL_ADDRESS, (LocalSocketAddress) destination, openListener, bindListener, optionMap); } else { throw msg.badSockType(destination.getClass()); } } public IoFuture openStreamConnection(SocketAddress bindAddress, SocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { if (bindAddress == null) { throw msg.nullParameter("bindAddress"); } if (destination == null) { throw msg.nullParameter("destination"); } if (bindAddress.getClass() != destination.getClass()) { throw msg.mismatchSockType(bindAddress.getClass(), destination.getClass()); } if (destination instanceof InetSocketAddress) { return openTcpStreamConnection((InetSocketAddress) bindAddress, (InetSocketAddress) destination, openListener, bindListener, optionMap); } else if (destination instanceof LocalSocketAddress) { return openLocalStreamConnection((LocalSocketAddress) bindAddress, (LocalSocketAddress) destination, openListener, bindListener, optionMap); } else { throw msg.badSockType(destination.getClass()); } } /** * Implementation helper method to connect to a TCP server. * * @param bindAddress the bind address * @param destinationAddress the destination address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param bindListener the listener which will be notified when the channel is bound, or {@code null} for none * @param optionMap the option map @return the future result of this operation * @return the future result of this operation */ protected IoFuture openTcpStreamConnection(InetSocketAddress bindAddress, InetSocketAddress destinationAddress, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { throw msg.unsupported("openTcpStreamConnection"); } /** * Implementation helper method to connect to a local (UNIX domain) server. * * @param bindAddress the bind address * @param destinationAddress the destination address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param bindListener the listener which will be notified when the channel is bound, or {@code null} for none * @param optionMap the option map * @return the future result of this operation */ protected IoFuture openLocalStreamConnection(LocalSocketAddress bindAddress, LocalSocketAddress destinationAddress, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { throw msg.unsupported("openLocalStreamConnection"); } /** * Implementation helper method to connect to a local (UNIX domain) server. * * @param bindAddress the bind address * @param destinationAddress the destination address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param optionMap the option map * @return the future result of this operation */ protected IoFuture openLocalMessageConnection(LocalSocketAddress bindAddress, LocalSocketAddress destinationAddress, ChannelListener openListener, OptionMap optionMap) { throw msg.unsupported("openLocalMessageConnection"); } public ChannelPipe createFullDuplexPipe() throws IOException { final ChannelPipe connection = createFullDuplexPipeConnection(); final StreamChannel left = new AssembledStreamChannel(connection.getLeftSide(), connection.getLeftSide().getSourceChannel(), connection.getLeftSide().getSinkChannel()); final StreamChannel right = new AssembledStreamChannel(connection.getRightSide(), connection.getRightSide().getSourceChannel(), connection.getRightSide().getSinkChannel()); return new ChannelPipe(left, right); } public ChannelPipe createFullDuplexPipeConnection() throws IOException { return createFullDuplexPipeConnection(this); } public ChannelPipe createHalfDuplexPipe() throws IOException { return createHalfDuplexPipe(this); } public ChannelPipe createFullDuplexPipeConnection(final XnioIoFactory peer) throws IOException { throw msg.unsupported("createFullDuplexPipeConnection"); } public ChannelPipe createHalfDuplexPipe(final XnioIoFactory peer) throws IOException { throw msg.unsupported("createHalfDuplexPipe"); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/XnioProvider.java000066400000000000000000000006611257016060700237770ustar00rootroot00000000000000 package org.xnio; /** * An XNIO provider, used by the service loader discovery mechanism. * * @author David M. Lloyd */ public interface XnioProvider { /** * Get the XNIO instance for this provider. * * @return the XNIO instance */ Xnio getInstance(); /** * Get the provider name. * * @return the name */ String getName(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/XnioWorker.java000066400000000000000000001257301257016060700234630ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.security.PrivilegedAction; import java.util.List; import java.util.Set; import java.util.concurrent.AbstractExecutorService; import java.util.concurrent.BlockingQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.LinkedBlockingQueue; import java.util.concurrent.RejectedExecutionHandler; import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.zip.Deflater; import java.util.zip.Inflater; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.AssembledConnectedMessageChannel; import org.xnio.channels.AssembledConnectedStreamChannel; import org.xnio.channels.BoundChannel; import org.xnio.channels.Configurable; import org.xnio.channels.ConnectedMessageChannel; import org.xnio.channels.ConnectedStreamChannel; import org.xnio.channels.MulticastMessageChannel; import org.xnio.channels.StreamChannel; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; import org.xnio.conduits.ConduitStreamSinkChannel; import org.xnio.conduits.ConduitStreamSourceChannel; import org.xnio.conduits.DeflatingStreamSinkConduit; import org.xnio.conduits.InflatingStreamSourceConduit; import org.xnio.conduits.StreamSinkChannelWrappingConduit; import org.xnio.conduits.StreamSourceChannelWrappingConduit; import static java.security.AccessController.doPrivileged; import static org.xnio.IoUtils.safeClose; import static org.xnio._private.Messages.msg; /** * A worker for I/O channel notification. * * @author David M. Lloyd * * @since 3.0 */ @SuppressWarnings("unused") public abstract class XnioWorker extends AbstractExecutorService implements Configurable, ExecutorService, XnioIoFactory { private final Xnio xnio; private final TaskPool taskPool; private final String name; private final Runnable terminationTask; private volatile int taskSeq; private volatile int coreSize; private static final AtomicIntegerFieldUpdater taskSeqUpdater = AtomicIntegerFieldUpdater.newUpdater(XnioWorker.class, "taskSeq"); private static final AtomicIntegerFieldUpdater coreSizeUpdater = AtomicIntegerFieldUpdater.newUpdater(XnioWorker.class, "coreSize"); private static final AtomicInteger seq = new AtomicInteger(1); private static final RuntimePermission CREATE_WORKER_PERMISSION = new RuntimePermission("createXnioWorker"); private final BlockingQueue taskQueue; private int getNextSeq() { return taskSeqUpdater.incrementAndGet(this); } /** * Construct a new instance. Intended to be called only from implementations. To construct an XNIO worker, * use the {@link Xnio#createWorker(OptionMap)} method. * * @param xnio the XNIO provider which produced this worker instance * @param threadGroup the thread group for worker threads * @param optionMap the option map to use to configure this worker * @param terminationTask an optional runnable task to run when the worker shutdown completes */ protected XnioWorker(final Xnio xnio, final ThreadGroup threadGroup, final OptionMap optionMap, final Runnable terminationTask) { this.xnio = xnio; this.terminationTask = terminationTask; final SecurityManager sm = System.getSecurityManager(); if (sm != null) { sm.checkPermission(CREATE_WORKER_PERMISSION); } String workerName = optionMap.get(Options.WORKER_NAME); if (workerName == null) { workerName = "XNIO-" + seq.getAndIncrement(); } name = workerName; taskQueue = new LinkedBlockingQueue(); this.coreSize = optionMap.get(Options.WORKER_TASK_CORE_THREADS, 4); final boolean markThreadAsDaemon = optionMap.get(Options.THREAD_DAEMON, false); final int threadCount = optionMap.get(Options.WORKER_TASK_MAX_THREADS, 16); taskPool = new TaskPool( threadCount, // ignore core threads setting, always fill to max threadCount, optionMap.get(Options.WORKER_TASK_KEEPALIVE, 60000), TimeUnit.MILLISECONDS, taskQueue, new WorkerThreadFactory(threadGroup, optionMap, markThreadAsDaemon), new ThreadPoolExecutor.AbortPolicy()); } //================================================== // // Stream methods // //================================================== // Servers /** * Create a stream server, for TCP or UNIX domain servers. The type of server is determined by the bind address. * * @param bindAddress the address to bind to * @param acceptListener the initial accept listener * @param optionMap the initial configuration for the server * @return the acceptor * @throws IOException if the server could not be created */ @Deprecated public AcceptingChannel createStreamServer(SocketAddress bindAddress, ChannelListener> acceptListener, OptionMap optionMap) throws IOException { final AcceptingChannel server = createStreamConnectionServer(bindAddress, null, optionMap); final AcceptingChannel acceptingChannel = new AcceptingChannel() { public ConnectedStreamChannel accept() throws IOException { final StreamConnection connection = server.accept(); return connection == null ? null : new AssembledConnectedStreamChannel(connection, connection.getSourceChannel(), connection.getSinkChannel()); } public ChannelListener.Setter> getAcceptSetter() { return ChannelListeners.getDelegatingSetter(server.getAcceptSetter(), this); } public ChannelListener.Setter> getCloseSetter() { return ChannelListeners.getDelegatingSetter(server.getCloseSetter(), this); } public SocketAddress getLocalAddress() { return server.getLocalAddress(); } public A getLocalAddress(final Class type) { return server.getLocalAddress(type); } public void suspendAccepts() { server.suspendAccepts(); } public void resumeAccepts() { server.resumeAccepts(); } public boolean isAcceptResumed() { return server.isAcceptResumed(); } public void wakeupAccepts() { server.wakeupAccepts(); } public void awaitAcceptable() throws IOException { server.awaitAcceptable(); } public void awaitAcceptable(final long time, final TimeUnit timeUnit) throws IOException { server.awaitAcceptable(time, timeUnit); } public XnioWorker getWorker() { return server.getWorker(); } @Deprecated public XnioExecutor getAcceptThread() { return server.getAcceptThread(); } public XnioIoThread getIoThread() { return chooseThread(); } public void close() throws IOException { server.close(); } public boolean isOpen() { return server.isOpen(); } public boolean supportsOption(final Option option) { return server.supportsOption(option); } public T getOption(final Option option) throws IOException { return server.getOption(option); } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return server.setOption(option, value); } }; acceptingChannel.getAcceptSetter().set(acceptListener); return acceptingChannel; } /** * Create a stream server, for TCP or UNIX domain servers. The type of server is determined by the bind address. * * @param bindAddress the address to bind to * @param acceptListener the initial accept listener * @param optionMap the initial configuration for the server * @return the acceptor * @throws IOException if the server could not be created */ public AcceptingChannel createStreamConnectionServer(SocketAddress bindAddress, ChannelListener> acceptListener, OptionMap optionMap) throws IOException { if (bindAddress == null) { throw msg.nullParameter("bindAddress"); } if (bindAddress instanceof InetSocketAddress) { return createTcpConnectionServer((InetSocketAddress) bindAddress, acceptListener, optionMap); } else if (bindAddress instanceof LocalSocketAddress) { return createLocalStreamConnectionServer((LocalSocketAddress) bindAddress, acceptListener, optionMap); } else { throw msg.badSockType(bindAddress.getClass()); } } /** * Implementation helper method to create a TCP stream server. * * @param bindAddress the address to bind to * @param acceptListener the initial accept listener * @param optionMap the initial configuration for the server * @return the acceptor * @throws IOException if the server could not be created */ protected AcceptingChannel createTcpConnectionServer(InetSocketAddress bindAddress, ChannelListener> acceptListener, OptionMap optionMap) throws IOException { throw msg.unsupported("createTcpConnectionServer"); } /** * Implementation helper method to create a UNIX domain stream server. * * @param bindAddress the address to bind to * @param acceptListener the initial accept listener * @param optionMap the initial configuration for the server * @return the acceptor * @throws IOException if the server could not be created */ protected AcceptingChannel createLocalStreamConnectionServer(LocalSocketAddress bindAddress, ChannelListener> acceptListener, OptionMap optionMap) throws IOException { throw msg.unsupported("createLocalStreamConnectionServer"); } // Connectors /** * Connect to a remote stream server. The protocol family is determined by the type of the socket address given. * * @param destination the destination address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param optionMap the option map * @return the future result of this operation */ @Deprecated public IoFuture connectStream(SocketAddress destination, ChannelListener openListener, OptionMap optionMap) { final FutureResult futureResult = new FutureResult(); final ChannelListener nestedOpenListener = new StreamConnectionWrapListener(futureResult, openListener); final IoFuture future = openStreamConnection(destination, nestedOpenListener, optionMap); future.addNotifier(STREAM_WRAPPING_HANDLER, futureResult); futureResult.addCancelHandler(future); return futureResult.getIoFuture(); } /** * Connect to a remote stream server. The protocol family is determined by the type of the socket address given. * * @param destination the destination address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param bindListener the listener which will be notified when the channel is bound, or {@code null} for none * @param optionMap the option map * @return the future result of this operation */ @Deprecated public IoFuture connectStream(SocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { final FutureResult futureResult = new FutureResult(); final ChannelListener nestedOpenListener = new StreamConnectionWrapListener(futureResult, openListener); final IoFuture future = openStreamConnection(destination, nestedOpenListener, bindListener, optionMap); future.addNotifier(STREAM_WRAPPING_HANDLER, futureResult); futureResult.addCancelHandler(future); return futureResult.getIoFuture(); } /** * Connect to a remote stream server. The protocol family is determined by the type of the socket addresses given * (which must match). * * @param bindAddress the local address to bind to * @param destination the destination address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param bindListener the listener which will be notified when the channel is bound, or {@code null} for none * @param optionMap the option map * @return the future result of this operation */ @Deprecated public IoFuture connectStream(SocketAddress bindAddress, SocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { final FutureResult futureResult = new FutureResult(); final ChannelListener nestedOpenListener = new StreamConnectionWrapListener(futureResult, openListener); final IoFuture future = openStreamConnection(bindAddress, destination, nestedOpenListener, bindListener, optionMap); future.addNotifier(STREAM_WRAPPING_HANDLER, futureResult); futureResult.addCancelHandler(future); return futureResult.getIoFuture(); } public IoFuture openStreamConnection(SocketAddress destination, ChannelListener openListener, OptionMap optionMap) { return chooseThread().openStreamConnection(destination, openListener, optionMap); } public IoFuture openStreamConnection(SocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { return chooseThread().openStreamConnection(destination, openListener, bindListener, optionMap); } public IoFuture openStreamConnection(SocketAddress bindAddress, SocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { return chooseThread().openStreamConnection(bindAddress, destination, openListener, bindListener, optionMap); } // Acceptors /** * Accept a stream connection at a destination address. If a wildcard address is specified, then a destination address * is chosen in a manner specific to the OS and/or channel type. * * @param destination the destination (bind) address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param bindListener the listener which will be notified when the acceptor is bound, or {@code null} for none * @param optionMap the option map * @return the future connection */ @Deprecated public IoFuture acceptStream(SocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { final FutureResult futureResult = new FutureResult(); final ChannelListener nestedOpenListener = new StreamConnectionWrapListener(futureResult, openListener); final IoFuture future = acceptStreamConnection(destination, nestedOpenListener, bindListener, optionMap); future.addNotifier(STREAM_WRAPPING_HANDLER, futureResult); futureResult.addCancelHandler(future); return futureResult.getIoFuture(); } public IoFuture acceptStreamConnection(SocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { return chooseThread().acceptStreamConnection(destination, openListener, bindListener, optionMap); } //================================================== // // Message (datagram) channel methods // //================================================== /** * Connect to a remote datagram server. The protocol family is determined by the type of the socket address given. * * @param destination the destination address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param bindListener the listener which will be notified when the channel is bound, or {@code null} for none * @param optionMap the option map * @return the future result of this operation */ @Deprecated // FIXME XNIO-192 invoke bind listener public IoFuture connectDatagram(SocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { final FutureResult futureResult = new FutureResult(); final ChannelListener nestedOpenListener = new MessageConnectionWrapListener(futureResult, openListener); final IoFuture future = openMessageConnection(destination, nestedOpenListener, optionMap); future.addNotifier(MESSAGE_WRAPPING_HANDLER, futureResult); futureResult.addCancelHandler(future); return futureResult.getIoFuture(); } /** * Connect to a remote datagram server. The protocol family is determined by the type of the socket addresses given * (which must match). * * @param bindAddress the local address to bind to * @param destination the destination address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param bindListener the listener which will be notified when the channel is bound, or {@code null} for none * @param optionMap the option map * @return the future result of this operation */ @Deprecated // FIXME bindAddress is now ignored public IoFuture connectDatagram(SocketAddress bindAddress, SocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { final FutureResult futureResult = new FutureResult(); final ChannelListener nestedOpenListener = new MessageConnectionWrapListener(futureResult, openListener); final IoFuture future = openMessageConnection(destination, nestedOpenListener, optionMap); future.addNotifier(MESSAGE_WRAPPING_HANDLER, futureResult); futureResult.addCancelHandler(future); return futureResult.getIoFuture(); } public IoFuture openMessageConnection(final SocketAddress destination, final ChannelListener openListener, final OptionMap optionMap) { return chooseThread().openMessageConnection(destination, openListener, optionMap); } // Acceptors /** * Accept a message connection at a destination address. If a wildcard address is specified, then a destination address * is chosen in a manner specific to the OS and/or channel type. * * @param destination the destination (bind) address * @param openListener the listener which will be notified when the channel is open, or {@code null} for none * @param bindListener the listener which will be notified when the acceptor is bound, or {@code null} for none * @param optionMap the option map * @return the future connection */ @Deprecated public IoFuture acceptDatagram(SocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { final FutureResult futureResult = new FutureResult(); final ChannelListener nestedOpenListener = new MessageConnectionWrapListener(futureResult, openListener); final IoFuture future = acceptMessageConnection(destination, nestedOpenListener, bindListener, optionMap); future.addNotifier(MESSAGE_WRAPPING_HANDLER, futureResult); futureResult.addCancelHandler(future); return futureResult.getIoFuture(); } public IoFuture acceptMessageConnection(final SocketAddress destination, final ChannelListener openListener, final ChannelListener bindListener, final OptionMap optionMap) { return chooseThread().acceptMessageConnection(destination, openListener, bindListener, optionMap); } //================================================== // // UDP methods // //================================================== /** * Create a UDP server. The UDP server can be configured to be multicast-capable; this should only be * done if multicast is needed, since some providers have a performance penalty associated with multicast. * The provider's default executor will be used to execute listener methods. * * @param bindAddress the bind address * @param bindListener the initial open-connection listener * @param optionMap the initial configuration for the server * @return the UDP server channel * @throws java.io.IOException if the server could not be created * * @since 3.0 */ public MulticastMessageChannel createUdpServer(InetSocketAddress bindAddress, ChannelListener bindListener, OptionMap optionMap) throws IOException { throw msg.unsupported("createUdpServer"); } /** * Create a UDP server. The UDP server can be configured to be multicast-capable; this should only be * done if multicast is needed, since some providers have a performance penalty associated with multicast. * The provider's default executor will be used to execute listener methods. * * @param bindAddress the bind address * @param optionMap the initial configuration for the server * @return the UDP server channel * @throws java.io.IOException if the server could not be created * * @since 3.0 */ public MulticastMessageChannel createUdpServer(InetSocketAddress bindAddress, OptionMap optionMap) throws IOException { return createUdpServer(bindAddress, ChannelListeners.nullChannelListener(), optionMap); } //================================================== // // Stream pipe methods // //================================================== /** * Open a bidirectional stream pipe. * * @param leftOpenListener the left-hand open listener * @param rightOpenListener the right-hand open listener * @param optionMap the pipe channel configuration * @throws java.io.IOException if the pipe could not be created * @deprecated Users should prefer the simpler {@link #createFullDuplexPipe()} instead. */ @Deprecated public void createPipe(ChannelListener leftOpenListener, ChannelListener rightOpenListener, final OptionMap optionMap) throws IOException { final ChannelPipe pipe = createFullDuplexPipe(); final boolean establishWriting = optionMap.get(Options.WORKER_ESTABLISH_WRITING, false); final StreamChannel left = pipe.getLeftSide(); XnioExecutor leftExec = establishWriting ? left.getWriteThread() : left.getReadThread(); final StreamChannel right = pipe.getRightSide(); XnioExecutor rightExec = establishWriting ? right.getWriteThread() : right.getReadThread(); // not unsafe - http://youtrack.jetbrains.net/issue/IDEA-59290 //noinspection unchecked leftExec.execute(ChannelListeners.getChannelListenerTask(left, leftOpenListener)); // not unsafe - http://youtrack.jetbrains.net/issue/IDEA-59290 //noinspection unchecked rightExec.execute(ChannelListeners.getChannelListenerTask(right, rightOpenListener)); } /** * Open a unidirectional stream pipe. * * @param sourceListener the source open listener * @param sinkListener the sink open listener * @param optionMap the pipe channel configuration * @throws java.io.IOException if the pipe could not be created * @deprecated Users should prefer the simpler {@link #createHalfDuplexPipe()} instead. */ @Deprecated public void createOneWayPipe(ChannelListener sourceListener, ChannelListener sinkListener, final OptionMap optionMap) throws IOException { final ChannelPipe pipe = createHalfDuplexPipe(); final StreamSourceChannel left = pipe.getLeftSide(); XnioExecutor leftExec = left.getReadThread(); final StreamSinkChannel right = pipe.getRightSide(); XnioExecutor rightExec = right.getWriteThread(); // not unsafe - http://youtrack.jetbrains.net/issue/IDEA-59290 //noinspection unchecked leftExec.execute(ChannelListeners.getChannelListenerTask(left, sourceListener)); // not unsafe - http://youtrack.jetbrains.net/issue/IDEA-59290 //noinspection unchecked rightExec.execute(ChannelListeners.getChannelListenerTask(right, sinkListener)); } //================================================== // // Compression methods // //================================================== /** * Create a stream channel that decompresses the source data according to the configuration in the given option map. * * @param delegate the compressed channel * @param options the configuration options for the channel * @return a decompressed channel * @throws IOException if the channel could not be constructed */ public StreamSourceChannel getInflatingChannel(final StreamSourceChannel delegate, OptionMap options) throws IOException { final boolean nowrap; switch (options.get(Options.COMPRESSION_TYPE, CompressionType.DEFLATE)) { case DEFLATE: nowrap = false; break; case GZIP: nowrap = true; break; default: throw msg.badCompressionFormat(); } return getInflatingChannel(delegate, new Inflater(nowrap)); } /** * Create a stream channel that decompresses the source data according to the configuration in the given inflater. * * @param delegate the compressed channel * @param inflater the inflater to use * @return a decompressed channel * @throws IOException if the channel could not be constructed */ protected StreamSourceChannel getInflatingChannel(final StreamSourceChannel delegate, final Inflater inflater) throws IOException { return new ConduitStreamSourceChannel(Configurable.EMPTY, new InflatingStreamSourceConduit(new StreamSourceChannelWrappingConduit(delegate), inflater)); } /** * Create a stream channel that compresses to the destination according to the configuration in the given option map. * * @param delegate the channel to compress to * @param options the configuration options for the channel * @return a compressed channel * @throws IOException if the channel could not be constructed */ public StreamSinkChannel getDeflatingChannel(final StreamSinkChannel delegate, final OptionMap options) throws IOException { final int level = options.get(Options.COMPRESSION_LEVEL, -1); final boolean nowrap; switch (options.get(Options.COMPRESSION_TYPE, CompressionType.DEFLATE)) { case DEFLATE: nowrap = false; break; case GZIP: nowrap = true; break; default: throw msg.badCompressionFormat(); } return getDeflatingChannel(delegate, new Deflater(level, nowrap)); } /** * Create a stream channel that compresses to the destination according to the configuration in the given inflater. * * @param delegate the channel to compress to * @param deflater the deflater to use * @return a compressed channel * @throws IOException if the channel could not be constructed */ protected StreamSinkChannel getDeflatingChannel(final StreamSinkChannel delegate, final Deflater deflater) throws IOException { return new ConduitStreamSinkChannel(Configurable.EMPTY, new DeflatingStreamSinkConduit(new StreamSinkChannelWrappingConduit(delegate), deflater)); } public ChannelPipe createFullDuplexPipe() throws IOException { return chooseThread().createFullDuplexPipe(); } public ChannelPipe createFullDuplexPipeConnection() throws IOException { return chooseThread().createFullDuplexPipeConnection(); } public ChannelPipe createHalfDuplexPipe() throws IOException { return chooseThread().createHalfDuplexPipe(); } public ChannelPipe createFullDuplexPipeConnection(final XnioIoFactory peer) throws IOException { return chooseThread().createFullDuplexPipeConnection(peer); } public ChannelPipe createHalfDuplexPipe(final XnioIoFactory peer) throws IOException { return chooseThread().createHalfDuplexPipe(peer); } //================================================== // // State methods // //================================================== /** * Shut down this worker. This method returns immediately. Upon return worker shutdown will have * commenced but not necessarily completed. When worker shutdown is complete, the termination task (if one was * defined) will be executed. */ public abstract void shutdown(); /** * Immediately terminate the worker. Any outstanding tasks are collected and returned in a list. Upon return * worker shutdown will have commenced but not necessarily completed; however the worker will only complete its * current tasks instead of completing all tasks. * * @return the list of outstanding tasks */ public abstract List shutdownNow(); /** * Determine whether the worker has been shut down. Will return {@code true} once either shutdown method has * been called. * * @return {@code true} the worker has been shut down */ public abstract boolean isShutdown(); /** * Determine whether the worker has terminated. Will return {@code true} once all worker threads are exited * (with the possible exception of the thread running the termination task, if any). * * @return {@code true} if the worker is terminated */ public abstract boolean isTerminated(); /** * Wait for termination. * * @param timeout the amount of time to wait * @param unit the unit of time * @return {@code true} if termination completed before the timeout expired * @throws InterruptedException if the operation was interrupted */ public abstract boolean awaitTermination(final long timeout, final TimeUnit unit) throws InterruptedException; /** * Wait for termination. * * @throws InterruptedException if the operation was interrupted */ public abstract void awaitTermination() throws InterruptedException; //================================================== // // Thread pool methods // //================================================== /** * Get an I/O thread from this worker. The thread may be chosen based on arbitrary rules. * * @return the I/O thread */ public final XnioIoThread getIoThread() { return chooseThread(); } /** * Get the user task to run once termination is complete. * * @return the termination task */ protected Runnable getTerminationTask() { return terminationTask; } /** * Callback to indicate that the task thread pool has terminated. */ protected void taskPoolTerminated() {} /** * Initiate shutdown of the task thread pool. When all the tasks and threads have completed, * the {@link #taskPoolTerminated()} method is called. */ protected void shutDownTaskPool() { taskPool.shutdown(); } /** * Shut down the task thread pool immediately and return its pending tasks. * * @return the pending task list */ protected List shutDownTaskPoolNow() { return taskPool.shutdownNow(); } /** * Execute a command in the task pool. * * @param command the command to run */ public void execute(final Runnable command) { taskPool.execute(command); } /** * Get the number of I/O threads configured on this worker. * * @return the number of I/O threads configured on this worker */ public abstract int getIoThreadCount(); //================================================== // // Configuration methods // //================================================== private static Set> OPTIONS = Option.setBuilder() .add(Options.WORKER_TASK_CORE_THREADS) .add(Options.WORKER_TASK_MAX_THREADS) .add(Options.WORKER_TASK_KEEPALIVE) .create(); public boolean supportsOption(final Option option) { return OPTIONS.contains(option); } public T getOption(final Option option) throws IOException { if (option.equals(Options.WORKER_TASK_CORE_THREADS)) { return option.cast(Integer.valueOf(coreSize)); } else if (option.equals(Options.WORKER_TASK_MAX_THREADS)) { return option.cast(Integer.valueOf(taskPool.getMaximumPoolSize())); } else if (option.equals(Options.WORKER_TASK_KEEPALIVE)) { return option.cast(Integer.valueOf((int) Math.min((long) Integer.MAX_VALUE, taskPool.getKeepAliveTime(TimeUnit.MILLISECONDS)))); } else { return null; } } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { if (option.equals(Options.WORKER_TASK_CORE_THREADS)) { return option.cast(Integer.valueOf(coreSizeUpdater.getAndSet(this, Options.WORKER_TASK_CORE_THREADS.cast(value).intValue()))); } else if (option.equals(Options.WORKER_TASK_MAX_THREADS)) { final int old = taskPool.getMaximumPoolSize(); taskPool.setCorePoolSize(Options.WORKER_TASK_MAX_THREADS.cast(value).intValue()); taskPool.setMaximumPoolSize(Options.WORKER_TASK_MAX_THREADS.cast(value).intValue()); return option.cast(Integer.valueOf(old)); } else if (option.equals(Options.WORKER_TASK_KEEPALIVE)) { final long old = taskPool.getKeepAliveTime(TimeUnit.MILLISECONDS); taskPool.setKeepAliveTime(Options.WORKER_TASK_KEEPALIVE.cast(value).intValue(), TimeUnit.MILLISECONDS); return option.cast(Integer.valueOf((int) Math.min((long) Integer.MAX_VALUE, old))); } else { return null; } } //================================================== // // Accessor methods // //================================================== /** * Get the XNIO provider which produced this worker. * * @return the XNIO provider */ public Xnio getXnio() { return xnio; } /** * Get the name of this worker. * * @return the name of the worker */ public String getName() { return name; } //================================================== // // SPI methods // //================================================== /** * Choose a thread randomly from this worker. * * @return the thread */ protected abstract XnioIoThread chooseThread(); /** * Get the core worker pool size. * * @return the core worker pool size */ protected final int getCoreWorkerPoolSize() { return coreSize; } /** * Get the maximum worker pool size. * * @return the maximum worker pool size */ protected final int getMaxWorkerPoolSize() { return taskPool.getMaximumPoolSize(); } /** * Get an estimate of the number of tasks in the worker queue. * * @return the estimated number of tasks */ protected final int getWorkerQueueSize() { return taskQueue.size(); } final class TaskPool extends ThreadPoolExecutor { TaskPool(final int corePoolSize, final int maximumPoolSize, final long keepAliveTime, final TimeUnit unit, final BlockingQueue workQueue, final ThreadFactory threadFactory, final RejectedExecutionHandler handler) { super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler); } protected void terminated() { taskPoolTerminated(); } } static class StreamConnectionWrapListener implements ChannelListener { private final FutureResult futureResult; private final ChannelListener openListener; public StreamConnectionWrapListener(final FutureResult futureResult, final ChannelListener openListener) { this.futureResult = futureResult; this.openListener = openListener; } public void handleEvent(final StreamConnection channel) { final AssembledConnectedStreamChannel assembledChannel = new AssembledConnectedStreamChannel(channel, channel.getSourceChannel(), channel.getSinkChannel()); if (!futureResult.setResult(assembledChannel)) { safeClose(assembledChannel); } else { ChannelListeners.invokeChannelListener(assembledChannel, openListener); } } } static class MessageConnectionWrapListener implements ChannelListener { private final FutureResult futureResult; private final ChannelListener openListener; public MessageConnectionWrapListener(final FutureResult futureResult, final ChannelListener openListener) { this.futureResult = futureResult; this.openListener = openListener; } public void handleEvent(final MessageConnection channel) { final AssembledConnectedMessageChannel assembledChannel = new AssembledConnectedMessageChannel(channel, channel.getSourceChannel(), channel.getSinkChannel()); if (!futureResult.setResult(assembledChannel)) { safeClose(assembledChannel); } else { ChannelListeners.invokeChannelListener(assembledChannel, openListener); } } } private static final IoFuture.HandlingNotifier> STREAM_WRAPPING_HANDLER = new IoFuture.HandlingNotifier>() { public void handleCancelled(final FutureResult attachment) { attachment.setCancelled(); } public void handleFailed(final IOException exception, final FutureResult attachment) { attachment.setException(exception); } }; private static final IoFuture.HandlingNotifier> MESSAGE_WRAPPING_HANDLER = new IoFuture.HandlingNotifier>() { public void handleCancelled(final FutureResult attachment) { attachment.setCancelled(); } public void handleFailed(final IOException exception, final FutureResult attachment) { attachment.setException(exception); } }; class WorkerThreadFactory implements ThreadFactory { private final ThreadGroup threadGroup; private final OptionMap optionMap; private final boolean markThreadAsDaemon; WorkerThreadFactory(final ThreadGroup threadGroup, final OptionMap optionMap, final boolean markThreadAsDaemon) { this.threadGroup = threadGroup; this.optionMap = optionMap; this.markThreadAsDaemon = markThreadAsDaemon; } public Thread newThread(final Runnable r) { return doPrivileged(new PrivilegedAction() { public Thread run() { final Thread taskThread = new Thread(threadGroup, r, name + " task-" + getNextSeq(), optionMap.get(Options.STACK_SIZE, 0L)); // Mark the thread as daemon if the Options.THREAD_DAEMON has been set if (markThreadAsDaemon) { taskThread.setDaemon(true); } return taskThread; } }); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/_private/000077500000000000000000000000001257016060700223125ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/java/org/xnio/_private/Messages.java000066400000000000000000000326171257016060700247350ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2012 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio._private; import java.io.CharConversionException; import java.io.EOFException; import java.io.IOException; import java.io.InterruptedIOException; import java.net.SocketAddress; import java.nio.BufferOverflowException; import java.nio.BufferUnderflowException; import java.nio.ReadOnlyBufferException; import java.nio.channels.Channel; import java.util.concurrent.CancellationException; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeoutException; import javax.net.ssl.SSLEngineResult; import javax.security.sasl.SaslException; import org.jboss.logging.BasicLogger; import org.jboss.logging.Logger; import org.jboss.logging.annotations.Cause; import org.jboss.logging.annotations.Field; import org.jboss.logging.annotations.LogMessage; import org.jboss.logging.annotations.Message; import org.jboss.logging.annotations.MessageLogger; import org.xnio.IoFuture; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.ConcurrentStreamChannelAccessException; import org.xnio.channels.ConnectedChannel; import org.xnio.channels.FixedLengthOverflowException; import org.xnio.channels.FixedLengthUnderflowException; import org.xnio.channels.ReadTimeoutException; import org.xnio.channels.WriteTimeoutException; import static org.jboss.logging.Logger.Level.*; @MessageLogger(projectCode = "XNIO") public interface Messages extends BasicLogger { Messages msg = Logger.getMessageLogger(Messages.class, "org.xnio"); Messages futureMsg = Logger.getMessageLogger(Messages.class, "org.xnio.future"); Messages optionParseMsg = Logger.getMessageLogger(Messages.class, "org.xnio.option.parse"); Messages closeMsg = Logger.getMessageLogger(Messages.class, "org.xnio.safe-close"); Messages listenerMsg = Logger.getMessageLogger(Messages.class, "org.xnio.listener"); // Greeting @Message(value = "XNIO version %s") @LogMessage(level = INFO) void greeting(String version); // Validation messages - cross-check with xnio-nio @Message(id = 0, value = "Method parameter '%s' cannot be null") IllegalArgumentException nullParameter(String name); @Message(id = 1, value = "Method parameter '%s' must be greater than %d") IllegalArgumentException minRange(String paramName, int minimumValue); @Message(id = 2, value = "Unsupported socket address %s") IllegalArgumentException badSockType(Class type); @Message(id = 3, value = "Method parameter '%s' contains disallowed null value at index %d") IllegalArgumentException nullArrayIndex(String paramName, int index); @Message(id = 4, value = "Bind address %s is not the same type as destination address %s") IllegalArgumentException mismatchSockType(Class bindType, Class destType); @Message(id = 5, value = "No such field named \"%s\" in %s") IllegalArgumentException noField(String fieldName, Class clazz); @Message(id = 6, value = "Class \"%s\" not found in %s") IllegalArgumentException optionClassNotFound(String className, ClassLoader classLoader); @Message(id = 7, value = "Field named \"%s\" is not accessible (public) in %s") IllegalArgumentException fieldNotAccessible(String fieldName, Class clazz); @Message(id = 8, value = "Field named \"%s\" is not static in %s") IllegalArgumentException fieldNotStatic(String fieldName, Class clazz); @Message(id = 9, value = "Copy with negative count is not supported") UnsupportedOperationException copyNegative(); @Message(id = 10, value = "Invalid option '%s' in property '%s': %s") @LogMessage(level = WARN) void invalidOptionInProperty(String optionName, String name, /* ! @Cause */ Throwable problem); // id = 11 - task failed to execute @Message(id = 12, value = "Attempt to write to a read-only buffer") ReadOnlyBufferException readOnlyBuffer(); @Message(id = 13, value = "Buffer underflow") BufferUnderflowException bufferUnderflow(); @Message(id = 14, value = "Buffer overflow") BufferOverflowException bufferOverflow(); // all param range checks should have ID 15 @Message(id = 15, value = "Parameter '%s' is out of range") IllegalArgumentException parameterOutOfRange(String name); // end range checks @Message(id = 16, value = "Mixed direct and heap buffers not allowed") IllegalArgumentException mixedDirectAndHeap(); @Message(id = 17, value = "Buffer was already freed") IllegalStateException bufferFreed(); @Message(id = 18, value = "Access a thread-local random from the wrong thread") IllegalStateException randomWrongThread(); @Message(id = 19, value = "Channel not available from connection") IllegalStateException channelNotAvailable(); @Message(id = 20, value = "No parser for this option value type") IllegalArgumentException noOptionParser(); @Message(id = 21, value = "Invalid format for property value '%s'") IllegalArgumentException invalidOptionPropertyFormat(String value); @Message(id = 22, value = "Class %s not found") IllegalArgumentException classNotFound(String name, @Cause ClassNotFoundException cause); @Message(id = 23, value = "Class %s is not an instance of %s") IllegalArgumentException classNotInstance(String name, Class expectedType); @Message(id = 24, value = "Invalid option name '%s'") IllegalArgumentException invalidOptionName(String name); @Message(id = 25, value = "Invalid null option '%s'") IllegalArgumentException invalidNullOption(String name); @Message(id = 26, value = "Read with append is not supported") IOException readAppendNotSupported(); @Message(id = 27, value = "Requested file open mode requires Java 7 or higher") IOException openModeRequires7(); @Message(id = 28, value = "Current thread is not an XNIO I/O thread") IllegalStateException xnioThreadRequired(); @Message(id = 29, value = "Compression format not supported") IllegalArgumentException badCompressionFormat(); @Message(id = 30, value = "Both channels must come from the same worker") IllegalArgumentException differentWorkers(); @Message(id = 31, value = "At least one channel must have a connection") IllegalArgumentException oneChannelMustBeConnection(); @Message(id = 32, value = "At least one channel must be an SSL channel") IllegalArgumentException oneChannelMustBeSSL(); @Message(id = 33, value = "'%s' is not a valid QOP value") IllegalArgumentException invalidQop(String name); @Message(id = 34, value = "Failed to instantiate %s") IllegalArgumentException cantInstantiate(Class clazz, @Cause Throwable cause); @Message(id = 35, value = "Stream channel was accessed concurrently") ConcurrentStreamChannelAccessException concurrentAccess(); @Message(id = 36, value = "Malformed input") CharConversionException malformedInput(); @Message(id = 37, value = "Unmappable character") CharConversionException unmappableCharacter(); @Message(id = 38, value = "Character decoding problem") CharConversionException characterDecodingProblem(); // id = 39 - Option value range // HTTP upgrade @Message(id = 100, value = "'https' URL scheme chosen but no SSL provider given") IllegalArgumentException missingSslProvider(); @Message(id = 101, value = "Unknown URL scheme '%s' given; must be one of 'http' or 'https'") IllegalArgumentException invalidURLScheme(String scheme); // SASL/authentication @Message(id = 200, value = "Unexpected extra SASL challenge data received") SaslException extraChallenge(); @Message(id = 201, value = "Unexpected extra SASL response data received") SaslException extraResponse(); // SSL @Message(id = 300, value = "Socket buffer is too small") IllegalArgumentException socketBufferTooSmall(); @Message(id = 301, value = "Application buffer is too small") IllegalArgumentException appBufferTooSmall(); @Message(id = 302, value = "SSLEngine required a bigger send buffer but our buffer was already big enough") IOException wrongBufferExpansion(); @Message(id = 303, value = "Unexpected wrap result status: %s") IOException unexpectedWrapResult(SSLEngineResult.Status status); @Message(id = 304, value = "Unexpected handshake status: %s") IOException unexpectedHandshakeStatus(SSLEngineResult.HandshakeStatus status); @Message(id = 305, value = "Unexpected unwrap result status: %s") IOException unexpectedUnwrapResult(SSLEngineResult.Status status); @Message(id = 306, value = "SSL connection is not from this provider") IllegalArgumentException notFromThisProvider(); // I/O errors @Message(id = 800, value = "Read timed out") ReadTimeoutException readTimeout(); @Message(id = 801, value = "Write timed out") WriteTimeoutException writeTimeout(); @Message(id = 802, value = "Write past the end of a fixed-length channel") FixedLengthOverflowException fixedOverflow(); @Message(id = 803, value = "Close before all bytes were written to a fixed-length channel (%d bytes remaining)") FixedLengthUnderflowException fixedUnderflow(long remaining); @Message(id = 804, value = "Received an invalid message length of %d") IOException recvInvalidMsgLength(int length); @Message(id = 805, value = "Writes have been shut down") EOFException writeShutDown(); @Message(id = 806, value = "Transmitted message is too large") IOException txMsgTooLarge(); @Message(id = 807, value = "Unflushed data truncated") IOException unflushedData(); @Message(id = 808, value = "I/O operation was interrupted") InterruptedIOException interruptedIO(); InterruptedIOException interruptedIO(@Field int bytesTransferred); @Message(id = 809, value = "Cannot flush due to insufficient buffer space") IOException flushSmallBuffer(); @Message(id = 810, value = "Deflater doesn't need input, but won't produce output") IOException deflaterState(); @Message(id = 811, value = "Inflater needs dictionary") IOException inflaterNeedsDictionary(); @Message(id = 812, value = "Connection closed unexpectedly") EOFException connectionClosedEarly(); @Message(id = 813, value = "The stream is closed") IOException streamClosed(); @Message(id = 814, value = "Mark not set") IOException markNotSet(); // 815 - worker shut down @Message(id = 816, value = "Redirect encountered establishing connection") String redirect(); // Unsupported implementation operations - cross-check with xnio-nio @Message(id = 900, value = "Method '%s' is not supported on this implementation") UnsupportedOperationException unsupported(String methodName); // General impl run-time messages - cross-check with xnio-nio @Message(id = 1000, value = "Blocking I/O is not allowed on the current thread") IllegalStateException blockingNotAllowed(); @Message(id = 1001, value = "No XNIO provider found") IllegalArgumentException noProviderFound(); @Message(id = 1002, value = "Operation was cancelled") CancellationException opCancelled(); @Message(id = 1003, value = "Running IoFuture notifier %s failed") @LogMessage(level = WARN) void notifierFailed(@Cause Throwable cause, IoFuture.Notifier notifier); @Message(id = 1004, value = "Operation timed out") TimeoutException opTimedOut(); @Message(id = 1005, value = "Not allowed to read non-XNIO properties") SecurityException propReadForbidden(); @Message(id = 1006, value = "Failed to invoke file watch callback") @LogMessage(level = ERROR) void failedToInvokeFileWatchCallback(@Cause Throwable cause); @Message(id = 1007, value = "A channel event listener threw an exception") @LogMessage(level = ERROR) void listenerException(@Cause Throwable cause); @Message(id = 1008, value = "A channel exception handler threw an exception") @LogMessage(level = ERROR) void exceptionHandlerException(@Cause Throwable cause); @Message(id = 1009, value = "Failed to accept a connection on %s: %s") @LogMessage(level = ERROR) void acceptFailed(AcceptingChannel channel, IOException reason); @Message(id = 1010, value = "Failed to submit task to executor: %s (closing %s)") @LogMessage(level = ERROR) void executorSubmitFailed(RejectedExecutionException cause, Channel channel); // Trace @Message(value = "Closing resource %s") @LogMessage(level = TRACE) void closingResource(Object resource); @Message(value = "Closing resource %s failed") @LogMessage(level = TRACE) void resourceCloseFailed(@Cause Throwable cause, Object resource); @Message(value = "Shutting down reads on %s failed") @LogMessage(level = TRACE) void resourceReadShutdownFailed(@Cause Throwable cause, Object resource); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/000077500000000000000000000000001257016060700222745ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/AcceptListenerSettable.java000066400000000000000000000036701257016060700275360ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.nio.channels.Channel; import org.xnio.ChannelListener; /** * An object which supports directly setting the accept listener may implement this interface. * * @author David M. Lloyd */ public interface AcceptListenerSettable { /** * Get the accept listener. * * @return the accept listener */ ChannelListener getAcceptListener(); /** * Set the accept listener. * * @param listener the accept listener */ void setAcceptListener(ChannelListener listener); /** * A channel listener setter implementation which delegates to the appropriate setter method. * * @param the channel type */ class Setter implements ChannelListener.Setter { private final AcceptListenerSettable settable; /** * Construct a new instance. * * @param settable the settable to delegate to */ public Setter(final AcceptListenerSettable settable) { this.settable = settable; } public void set(final ChannelListener listener) { settable.setAcceptListener(listener); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/AcceptingChannel.java000066400000000000000000000012201257016060700263200ustar00rootroot00000000000000 package org.xnio.channels; import java.io.IOException; import org.xnio.ChannelListener; /** * A channel which can accept inbound connections from remote endpoints. * * @author David M. Lloyd * @param the channel type */ public interface AcceptingChannel extends BoundChannel, SimpleAcceptingChannel { /** {@inheritDoc} */ C accept() throws IOException; /** {@inheritDoc} */ ChannelListener.Setter> getAcceptSetter(); /** {@inheritDoc} */ ChannelListener.Setter> getCloseSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/AssembledChannel.java000066400000000000000000000110101257016060700263200ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import java.io.IOException; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.IoUtils; import org.xnio.Option; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import static org.xnio._private.Messages.msg; /** * A closeable view over a read and write side of a suspendable channel. * * @author David M. Lloyd */ public class AssembledChannel implements CloseableChannel { private final SuspendableReadChannel readChannel; private final SuspendableWriteChannel writeChannel; // Actual type is SimpleSetter private final ChannelListener.SimpleSetter closeSetter = new ChannelListener.SimpleSetter(); private final ChannelListener listener = new ChannelListener() { public void handleEvent(final CloseableChannel channel) { int newState, oldState; final AssembledChannel obj = AssembledChannel.this; do { oldState = stateUpdater.get(obj); if (oldState == 3) { return; } newState = oldState; if (channel == readChannel) { newState |= 1; } if (channel == writeChannel) { newState |= 2; } } while (! stateUpdater.compareAndSet(obj, oldState, newState)); if (newState == 3) { ChannelListeners.invokeChannelListener(obj, closeSetter.get()); } } }; @SuppressWarnings("unused") private volatile int state = 0; private static final AtomicIntegerFieldUpdater stateUpdater = AtomicIntegerFieldUpdater.newUpdater(AssembledChannel.class, "state"); /** * Construct a new instance. * * @param readChannel the read side * @param writeChannel the write side */ public AssembledChannel(final SuspendableReadChannel readChannel, final SuspendableWriteChannel writeChannel) { this.readChannel = readChannel; this.writeChannel = writeChannel; if (readChannel.getWorker() != writeChannel.getWorker()) { throw msg.differentWorkers(); } } public ChannelListener.Setter getCloseSetter() { readChannel.getCloseSetter().set(listener); writeChannel.getCloseSetter().set(listener); return closeSetter; } public XnioWorker getWorker() { // both should be the same return readChannel.getWorker(); } public XnioIoThread getIoThread() { // both should be the same return readChannel.getIoThread(); } public void close() throws IOException { try { readChannel.close(); writeChannel.close(); } finally { IoUtils.safeClose(readChannel); IoUtils.safeClose(writeChannel); } } public boolean isOpen() { return readChannel.isOpen() && writeChannel.isOpen(); } public boolean supportsOption(final Option option) { return readChannel.supportsOption(option) || writeChannel.supportsOption(option); } private static T nonNullOrFirst(T one, T two) { return one != null ? one : two; } public T getOption(final Option option) throws IOException { return nonNullOrFirst(readChannel.getOption(option), writeChannel.getOption(option)); } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return nonNullOrFirst(readChannel.setOption(option, value), writeChannel.setOption(option, value)); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/AssembledConnectedChannel.java000066400000000000000000000050021257016060700301470ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import static org.xnio._private.Messages.msg; import java.net.SocketAddress; import org.xnio.ChannelListener; /** * A closeable, connected view over a read and write side of a suspendable channel, at least one of which is connected. * * @author David M. Lloyd */ public class AssembledConnectedChannel extends AssembledChannel implements ConnectedChannel { private final ConnectedChannel connection; /** * Construct a new instance. At least one of the channels must be an instance of {@link ConnectedChannel}. * * @param readChannel the read channel * @param writeChannel the write channel */ public AssembledConnectedChannel(final SuspendableReadChannel readChannel, final SuspendableWriteChannel writeChannel) { super(readChannel, writeChannel); ConnectedChannel ch = Channels.unwrap(ConnectedChannel.class, readChannel); if (ch == null) ch = Channels.unwrap(ConnectedChannel.class, writeChannel); if (ch == null) throw msg.oneChannelMustBeConnection(); connection = ch; } @SuppressWarnings("unchecked") public ChannelListener.Setter getCloseSetter() { return (ChannelListener.Setter) super.getCloseSetter(); } public SocketAddress getPeerAddress() { return connection.getPeerAddress(); } public A getPeerAddress(final Class type) { return connection.getPeerAddress(type); } public SocketAddress getLocalAddress() { return connection.getLocalAddress(); } public A getLocalAddress(final Class type) { return connection.getLocalAddress(type); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/AssembledConnectedMessageChannel.java000066400000000000000000000061731257016060700314660ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import java.net.SocketAddress; import org.xnio.ChannelListener; /** * A connected bidirectional message channel assembled from a readable and writable message channel. * * @author David M. Lloyd */ public class AssembledConnectedMessageChannel extends AssembledMessageChannel implements ConnectedMessageChannel { private final ConnectedChannel connection; /** * Construct a new instance. * * @param connection the connected channel * @param readable the read channel * @param writable the write channel */ public AssembledConnectedMessageChannel(final ConnectedChannel connection, final ReadableMessageChannel readable, final WritableMessageChannel writable) { super(connection, readable, writable); this.connection = connection; } /** * Construct a new instance. At least one side must be connected. * * @param readable the read channel * @param writable the write channel */ public AssembledConnectedMessageChannel(final ReadableMessageChannel readable, final WritableMessageChannel writable) { this(new AssembledConnectedChannel(readable, writable), readable, writable); } @SuppressWarnings("unchecked") public ChannelListener.Setter getCloseSetter() { return (ChannelListener.Setter) super.getCloseSetter(); } @SuppressWarnings("unchecked") public ChannelListener.Setter getReadSetter() { return (ChannelListener.Setter) super.getReadSetter(); } @SuppressWarnings("unchecked") public ChannelListener.Setter getWriteSetter() { return (ChannelListener.Setter) super.getWriteSetter(); } public SocketAddress getPeerAddress() { return connection.getPeerAddress(); } public A getPeerAddress(final Class type) { return connection.getPeerAddress(type); } public SocketAddress getLocalAddress() { return connection.getLocalAddress(); } public A getLocalAddress(final Class type) { return connection.getLocalAddress(type); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/AssembledConnectedSslStreamChannel.java000066400000000000000000000062371257016060700320200ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import java.io.IOException; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import javax.net.ssl.SSLSession; /** * A connected SSL stream channel assembled from a stream source and stream sink. * * @author David M. Lloyd */ public class AssembledConnectedSslStreamChannel extends AssembledConnectedStreamChannel implements ConnectedSslStreamChannel { private final SslChannel sslChannel; private final ChannelListener.Setter handshakeSetter; /** * Construct a new instance. * * @param sslChannel the SSL channel * @param source the source * @param sink the sink */ public AssembledConnectedSslStreamChannel(final SslChannel sslChannel, final StreamSourceChannel source, final StreamSinkChannel sink) { super(sslChannel, source, sink); this.sslChannel = sslChannel; handshakeSetter = ChannelListeners.getDelegatingSetter(sslChannel.getHandshakeSetter(), this); } /** * Construct a new instance. At least one side must be an SSL channel. * * @param source the source * @param sink the sink */ public AssembledConnectedSslStreamChannel(final StreamSourceChannel source, final StreamSinkChannel sink) { this(new AssembledSslChannel(source, sink), source, sink); } public void startHandshake() throws IOException { sslChannel.startHandshake(); } public SSLSession getSslSession() { return sslChannel.getSslSession(); } public ChannelListener.Setter getHandshakeSetter() { return handshakeSetter; } @SuppressWarnings("unchecked") public ChannelListener.Setter getCloseSetter() { return (ChannelListener.Setter) super.getCloseSetter(); } @SuppressWarnings("unchecked") public ChannelListener.Setter getReadSetter() { return (ChannelListener.Setter) super.getReadSetter(); } @SuppressWarnings("unchecked") public ChannelListener.Setter getWriteSetter() { return (ChannelListener.Setter) super.getWriteSetter(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/AssembledConnectedStreamChannel.java000066400000000000000000000060011257016060700313230ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import java.net.SocketAddress; import org.xnio.ChannelListener; /** * A connected stream channel assembled from a stream source and stream sink. * * @author David M. Lloyd */ public class AssembledConnectedStreamChannel extends AssembledStreamChannel implements ConnectedStreamChannel { private final ConnectedChannel connection; /** * Construct a new instance. * * @param connection the connected channel * @param source the source * @param sink the sink */ public AssembledConnectedStreamChannel(final ConnectedChannel connection, final StreamSourceChannel source, final StreamSinkChannel sink) { super(connection, source, sink); this.connection = connection; } /** * Construct a new instance. At least one side must be connected. * * @param source the source * @param sink the sink */ public AssembledConnectedStreamChannel(final StreamSourceChannel source, final StreamSinkChannel sink) { this(new AssembledConnectedChannel(source, sink), source, sink); } @SuppressWarnings("unchecked") public ChannelListener.Setter getCloseSetter() { return (ChannelListener.Setter) super.getCloseSetter(); } @SuppressWarnings("unchecked") public ChannelListener.Setter getReadSetter() { return (ChannelListener.Setter) super.getReadSetter(); } @SuppressWarnings("unchecked") public ChannelListener.Setter getWriteSetter() { return (ChannelListener.Setter) super.getWriteSetter(); } public SocketAddress getPeerAddress() { return connection.getPeerAddress(); } public A getPeerAddress(final Class type) { return connection.getPeerAddress(type); } public SocketAddress getLocalAddress() { return connection.getLocalAddress(); } public A getLocalAddress(final Class type) { return connection.getLocalAddress(type); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/AssembledMessageChannel.java000066400000000000000000000154401257016060700276400ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import static org.xnio._private.Messages.msg; import java.io.IOException; import java.nio.ByteBuffer; import java.util.concurrent.TimeUnit; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.Option; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; /** * A bidirectional message channel assembled from a readable and writable message channel. * * @author David M. Lloyd */ public class AssembledMessageChannel implements MessageChannel { private final CloseableChannel closeable; private final ReadableMessageChannel readable; private final WritableMessageChannel writable; private final ChannelListener.Setter readSetter; private final ChannelListener.Setter writeSetter; private final ChannelListener.Setter closeSetter; /** * Construct a new instance. * * @param closeable the single central closeable channel * @param readable the read channel * @param writable the write channel */ public AssembledMessageChannel(final CloseableChannel closeable, final ReadableMessageChannel readable, final WritableMessageChannel writable) { if (readable.getWorker() != writable.getWorker() || readable.getWorker() != closeable.getWorker()) { throw msg.differentWorkers(); } this.closeable = closeable; this.readable = readable; this.writable = writable; readSetter = ChannelListeners.getDelegatingSetter(readable.getReadSetter(), this); writeSetter = ChannelListeners.getDelegatingSetter(writable.getWriteSetter(), this); closeSetter = ChannelListeners.getDelegatingSetter(closeable.getCloseSetter(), this); } /** * Construct a new instance. * * @param readable the read channel * @param writable the write channel */ public AssembledMessageChannel(final ReadableMessageChannel readable, final WritableMessageChannel writable) { this(new AssembledChannel(readable, writable), readable, writable); } public XnioIoThread getIoThread() { // both should be the same return readable.getIoThread(); } // Read side public ChannelListener.Setter getReadSetter() { return readSetter; } public void suspendReads() { readable.suspendReads(); } public void resumeReads() { readable.resumeReads(); } public boolean isReadResumed() { return readable.isReadResumed(); } public void wakeupReads() { readable.wakeupReads(); } public void shutdownReads() throws IOException { readable.shutdownReads(); } public void awaitReadable() throws IOException { readable.awaitReadable(); } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { readable.awaitReadable(time, timeUnit); } @Deprecated public XnioExecutor getReadThread() { return readable.getReadThread(); } public int receive(final ByteBuffer buffer) throws IOException { return readable.receive(buffer); } public long receive(final ByteBuffer[] buffers) throws IOException { return readable.receive(buffers); } public long receive(final ByteBuffer[] buffers, final int offs, final int len) throws IOException { return readable.receive(buffers, offs, len); } // Write side public ChannelListener.Setter getWriteSetter() { return writeSetter; } public void suspendWrites() { writable.suspendWrites(); } public void resumeWrites() { writable.resumeWrites(); } public boolean isWriteResumed() { return writable.isWriteResumed(); } public void wakeupWrites() { writable.wakeupWrites(); } public void shutdownWrites() throws IOException { writable.shutdownWrites(); } public void awaitWritable() throws IOException { writable.awaitWritable(); } public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException { writable.awaitWritable(time, timeUnit); } @Deprecated public XnioExecutor getWriteThread() { return writable.getWriteThread(); } public boolean send(final ByteBuffer buffer) throws IOException { return writable.send(buffer); } public boolean send(final ByteBuffer[] buffers) throws IOException { return writable.send(buffers); } public boolean send(final ByteBuffer[] buffers, final int offs, final int len) throws IOException { return writable.send(buffers, offs, len); } @Override public boolean sendFinal(ByteBuffer buffer) throws IOException { return writable.sendFinal(buffer); } @Override public boolean sendFinal(ByteBuffer[] buffers) throws IOException { return writable.sendFinal(buffers); } @Override public boolean sendFinal(ByteBuffer[] buffers, int offs, int len) throws IOException { return writable.sendFinal(buffers, offs, len); } public boolean flush() throws IOException { return writable.flush(); } // Single side public ChannelListener.Setter getCloseSetter() { return closeSetter; } public XnioWorker getWorker() { return closeable.getWorker(); } public void close() throws IOException { closeable.close(); } public boolean isOpen() { return closeable.isOpen(); } public boolean supportsOption(final Option option) { return closeable.supportsOption(option); } public T getOption(final Option option) throws IOException { return closeable.getOption(option); } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return closeable.setOption(option, value); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/AssembledSslChannel.java000066400000000000000000000047521257016060700270210ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import static org.xnio._private.Messages.msg; import java.io.IOException; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import javax.net.ssl.SSLSession; /** * An assembled SSL channel. * * @author David M. Lloyd */ public class AssembledSslChannel extends AssembledConnectedChannel implements SslChannel { private final SslChannel sslChannel; private final ChannelListener.Setter handshakeSetter; /** * Construct a new instance. At least one side must be an SSL channel. * * @param readChannel the read channel * @param writeChannel the write channel */ public AssembledSslChannel(final SuspendableReadChannel readChannel, final SuspendableWriteChannel writeChannel) { super(readChannel, writeChannel); if (readChannel instanceof SslChannel) { sslChannel = (SslChannel) readChannel; } else if (writeChannel instanceof SslChannel) { sslChannel = (SslChannel) writeChannel; } else { throw msg.oneChannelMustBeSSL(); } handshakeSetter = ChannelListeners.getDelegatingSetter(sslChannel.getHandshakeSetter(), this); } public void startHandshake() throws IOException { sslChannel.startHandshake(); } public SSLSession getSslSession() { return sslChannel.getSslSession(); } public ChannelListener.Setter getHandshakeSetter() { return handshakeSetter; } @SuppressWarnings("unchecked") public ChannelListener.Setter getCloseSetter() { return (ChannelListener.Setter) super.getCloseSetter(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/AssembledStreamChannel.java000066400000000000000000000164661257016060700275200ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import static org.xnio._private.Messages.msg; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.Option; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; /** * A stream channel assembled from a stream source and stream sink. * * @author David M. Lloyd */ public class AssembledStreamChannel implements StreamChannel { private final CloseableChannel closeable; private final StreamSourceChannel source; private final StreamSinkChannel sink; private final ChannelListener.Setter readSetter; private final ChannelListener.Setter writeSetter; private final ChannelListener.Setter closeSetter; /** * Construct a new instance. * * @param closeable the single central closeable channel * @param source the stream source channel * @param sink the stream sink channel */ public AssembledStreamChannel(final CloseableChannel closeable, final StreamSourceChannel source, final StreamSinkChannel sink) { if (source.getWorker() != sink.getWorker() || source.getWorker() != closeable.getWorker()) { throw msg.differentWorkers(); } this.closeable = closeable; this.source = source; this.sink = sink; readSetter = ChannelListeners.getDelegatingSetter(source.getReadSetter(), this); writeSetter = ChannelListeners.getDelegatingSetter(sink.getWriteSetter(), this); closeSetter = ChannelListeners.getDelegatingSetter(closeable.getCloseSetter(), this); } /** * Construct a new instance. * * @param source the stream source channel * @param sink the stream sink channel */ public AssembledStreamChannel(final StreamSourceChannel source, final StreamSinkChannel sink) { this(new AssembledChannel(source, sink), source, sink); } // Read side public ChannelListener.Setter getReadSetter() { return readSetter; } public void suspendReads() { source.suspendReads(); } public void resumeReads() { source.resumeReads(); } public boolean isReadResumed() { return source.isReadResumed(); } public void wakeupReads() { source.wakeupReads(); } public void shutdownReads() throws IOException { source.shutdownReads(); } public void awaitReadable() throws IOException { source.awaitReadable(); } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { source.awaitReadable(time, timeUnit); } @Deprecated public XnioExecutor getReadThread() { return source.getReadThread(); } public XnioIoThread getIoThread() { return source.getIoThread(); } public int read(final ByteBuffer dst) throws IOException { return source.read(dst); } public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { return source.read(dsts, offset, length); } public long read(final ByteBuffer[] dsts) throws IOException { return source.read(dsts); } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { return source.transferTo(position, count, target); } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { return source.transferTo(count, throughBuffer, target); } // Write side public long transferFrom(final FileChannel src, final long position, final long count) throws IOException { return sink.transferFrom(src, position, count); } public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { return sink.transferFrom(source, count, throughBuffer); } public ChannelListener.Setter getWriteSetter() { return writeSetter; } public int write(final ByteBuffer src) throws IOException { return sink.write(src); } public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException { return sink.write(srcs, offset, length); } public long write(final ByteBuffer[] srcs) throws IOException { return sink.write(srcs); } public void suspendWrites() { sink.suspendWrites(); } public void resumeWrites() { sink.resumeWrites(); } public boolean isWriteResumed() { return sink.isWriteResumed(); } public void wakeupWrites() { sink.wakeupWrites(); } public void shutdownWrites() throws IOException { sink.shutdownWrites(); } public void awaitWritable() throws IOException { sink.awaitWritable(); } public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException { sink.awaitWritable(time, timeUnit); } @Deprecated public XnioExecutor getWriteThread() { return sink.getWriteThread(); } public boolean flush() throws IOException { return sink.flush(); } // Single side public ChannelListener.Setter getCloseSetter() { return closeSetter; } @Override public int writeFinal(ByteBuffer src) throws IOException { return sink.writeFinal(src); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { return sink.writeFinal(srcs, offset, length); } @Override public long writeFinal(ByteBuffer[] srcs) throws IOException { return sink.writeFinal(srcs); } public XnioWorker getWorker() { return closeable.getWorker(); } public void close() throws IOException { closeable.close(); } public boolean isOpen() { return closeable.isOpen(); } public boolean supportsOption(final Option option) { return closeable.supportsOption(option); } public T getOption(final Option option) throws IOException { return closeable.getOption(option); } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return closeable.setOption(option, value); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/BlockingByteChannel.java000066400000000000000000000257321257016060700270150ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2009 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import static org.xnio._private.Messages.msg; import java.nio.channels.ScatteringByteChannel; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ByteChannel; import java.nio.ByteBuffer; import java.io.IOException; import java.io.Flushable; import java.util.concurrent.TimeUnit; import org.xnio.Buffers; /** * A blocking wrapper for a {@code StreamChannel}. Read and write operations will block until some data may be transferred. * Once any amount of data is read or written, the operation will return. If a read timeout is specified, then the read methods * will throw a {@link ReadTimeoutException} if the timeout expires without reading any data. If a write timeout is specified, then the write methods * will throw a {@link WriteTimeoutException} if the timeout expires without writing any data. */ public class BlockingByteChannel implements ScatteringByteChannel, GatheringByteChannel, ByteChannel, Flushable { private final StreamChannel delegate; private volatile long readTimeout; private volatile long writeTimeout; /** * Construct a new instance. * * @param delegate the channel to forward I/O operations to */ public BlockingByteChannel(final StreamChannel delegate) { this.delegate = delegate; } /** * Construct a new instance. * * @param delegate the channel to forward I/O operations to * @param timeout the read/write timeout * @param timeoutUnit the read/write timeout unit */ public BlockingByteChannel(final StreamChannel delegate, final long timeout, final TimeUnit timeoutUnit) { this(delegate, timeout, timeoutUnit, timeout, timeoutUnit); } /** * Construct a new instance. * * @param delegate the channel to forward I/O operations to * @param readTimeout the read timeout * @param readTimeoutUnit the read timeout unit * @param writeTimeout the write timeout * @param writeTimeoutUnit the write timeout unit */ public BlockingByteChannel(final StreamChannel delegate, final long readTimeout, final TimeUnit readTimeoutUnit, final long writeTimeout, final TimeUnit writeTimeoutUnit) { if (readTimeout < 0L) { throw msg.parameterOutOfRange("readTimeout"); } if (writeTimeout < 0L) { throw msg.parameterOutOfRange("writeTimeout"); } final long calcReadTimeout = readTimeoutUnit.toNanos(readTimeout); this.readTimeout = readTimeout == 0L ? 0L : calcReadTimeout < 1L ? 1L : calcReadTimeout; final long calcWriteTimeout = writeTimeoutUnit.toNanos(writeTimeout); this.writeTimeout = writeTimeout == 0L ? 0L : calcWriteTimeout < 1L ? 1L : calcWriteTimeout; this.delegate = delegate; } /** * Set the read timeout. * * @param readTimeout the read timeout * @param readTimeoutUnit the read timeout unit */ public void setReadTimeout(long readTimeout, TimeUnit readTimeoutUnit) { if (readTimeout < 0L) { throw msg.parameterOutOfRange("readTimeout"); } final long calcTimeout = readTimeoutUnit.toNanos(readTimeout); this.readTimeout = readTimeout == 0L ? 0L : calcTimeout < 1L ? 1L : calcTimeout; } /** * Set the write timeout. * * @param writeTimeout the write timeout * @param writeTimeoutUnit the write timeout unit */ public void setWriteTimeout(long writeTimeout, TimeUnit writeTimeoutUnit) { if (writeTimeout < 0L) { throw msg.parameterOutOfRange("writeTimeout"); } final long calcTimeout = writeTimeoutUnit.toNanos(writeTimeout); this.writeTimeout = writeTimeout == 0L ? 0L : calcTimeout < 1L ? 1L : calcTimeout; } /** * Perform a blocking, scattering read operation. * * @param dsts the destination buffers * @param offset the offset into the destination buffer array * @param length the number of buffers to read into * @return the number of bytes actually read (will be greater than zero) * @throws IOException if an I/O error occurs */ public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { if (! Buffers.hasRemaining(dsts, offset, length)) { return 0L; } final StreamSourceChannel delegate = this.delegate; long res; if ((res = delegate.read(dsts, offset, length)) == 0L) { long start = System.nanoTime(); long elapsed = 0L, readTimeout; do { readTimeout = this.readTimeout; if (readTimeout == 0L || readTimeout == Long.MAX_VALUE) { delegate.awaitReadable(); } else if (readTimeout <= elapsed) { throw msg.readTimeout(); } else { delegate.awaitReadable(readTimeout - elapsed, TimeUnit.NANOSECONDS); } elapsed = System.nanoTime() - start; } while ((res = delegate.read(dsts, offset, length)) == 0L); } return res; } /** * Perform a blocking, scattering read operation. * * @param dsts the destination buffers * @return the number of bytes actually read (will be greater than zero) * @throws IOException if an I/O error occurs */ public long read(final ByteBuffer[] dsts) throws IOException { return read(dsts, 0, dsts.length); } /** * Perform a blocking read operation. * * @param dst the destination buffer * @return the number of bytes actually read (will be greater than zero) * @throws IOException if an I/O error occurs */ public int read(final ByteBuffer dst) throws IOException { if (! dst.hasRemaining()) { return 0; } final StreamSourceChannel delegate = this.delegate; int res; if ((res = delegate.read(dst)) == 0) { long start = System.nanoTime(); long elapsed = 0L, readTimeout; do { readTimeout = this.readTimeout; if (readTimeout == 0L || readTimeout == Long.MAX_VALUE) { delegate.awaitReadable(); } else if (readTimeout <= elapsed) { throw msg.readTimeout(); } else { delegate.awaitReadable(readTimeout - elapsed, TimeUnit.NANOSECONDS); } elapsed = System.nanoTime() - start; } while ((res = delegate.read(dst)) == 0); } return res; } /** * Perform a blocking, gathering write operation. * * @param srcs the source buffers * @param offset the offset into the destination buffer array * @param length the number of buffers to write from * @return the number of bytes actually written (will be greater than zero) * @throws IOException if an I/O error occurs */ public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException { if (! Buffers.hasRemaining(srcs, offset, length)) { return 0L; } final StreamSinkChannel delegate = this.delegate; long res; if ((res = delegate.write(srcs, offset, length)) == 0L) { long start = System.nanoTime(); long elapsed = 0L, writeTimeout; do { writeTimeout = this.writeTimeout; if (writeTimeout == 0L || writeTimeout == Long.MAX_VALUE) { delegate.awaitWritable(); } else if (writeTimeout <= elapsed) { throw msg.writeTimeout(); } else { delegate.awaitWritable(writeTimeout - elapsed, TimeUnit.NANOSECONDS); } elapsed = System.nanoTime() - start; } while ((res = delegate.write(srcs, offset, length)) == 0L); } return res; } /** * Perform a blocking, gathering write operation. * * @param srcs the source buffers * @return the number of bytes actually written (will be greater than zero) * @throws IOException if an I/O error occurs */ public long write(final ByteBuffer[] srcs) throws IOException { return write(srcs, 0, srcs.length); } /** * Perform a blocking write operation. * * @param src the source buffer * @return the number of bytes actually written (will be greater than zero) * @throws IOException if an I/O error occurs */ public int write(final ByteBuffer src) throws IOException { if (! src.hasRemaining()) { return 0; } final StreamSinkChannel delegate = this.delegate; int res; if ((res = delegate.write(src)) == 0L) { long start = System.nanoTime(); long elapsed = 0L, writeTimeout; do { writeTimeout = this.writeTimeout; if (writeTimeout == 0L || writeTimeout == Long.MAX_VALUE) { delegate.awaitWritable(); } else if (writeTimeout <= elapsed) { throw msg.writeTimeout(); } else { delegate.awaitWritable(writeTimeout - elapsed, TimeUnit.NANOSECONDS); } elapsed = System.nanoTime() - start; } while ((res = delegate.write(src)) == 0L); } return res; } /** {@inheritDoc} */ public boolean isOpen() { return delegate.isOpen(); } /** {@inheritDoc} */ public void flush() throws IOException { final StreamSinkChannel delegate = this.delegate; if (! delegate.flush()) { long start = System.nanoTime(); long elapsed = 0L, writeTimeout; do { writeTimeout = this.writeTimeout; if (writeTimeout == 0L || writeTimeout == Long.MAX_VALUE) { delegate.awaitWritable(); } else if (writeTimeout <= elapsed) { throw msg.writeTimeout(); } else { delegate.awaitWritable(writeTimeout - elapsed, TimeUnit.NANOSECONDS); } elapsed = System.nanoTime() - start; } while (! delegate.flush()); } } /** {@inheritDoc} */ public void close() throws IOException { delegate.close(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/BlockingReadableByteChannel.java000066400000000000000000000133521257016060700304300ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2009 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import static org.xnio._private.Messages.msg; import java.nio.channels.ScatteringByteChannel; import java.nio.ByteBuffer; import java.io.IOException; import java.util.concurrent.TimeUnit; import org.xnio.Buffers; /** * A blocking wrapper for a {@code StreamSourceChannel}. Read operations will block until some data may be transferred. * Once any amount of data is read, the operation will return. If a read timeout is specified, then the read methods * will throw a {@link ReadTimeoutException} if the timeout expires without reading any data. */ public class BlockingReadableByteChannel implements ScatteringByteChannel { private final StreamSourceChannel delegate; private volatile long readTimeout; /** * Construct a new instance. * * @param delegate the channel to forward I/O operations to */ public BlockingReadableByteChannel(final StreamSourceChannel delegate) { this.delegate = delegate; } /** * Construct a new instance. * * @param delegate the channel to forward I/O operations to * @param readTimeout the read timeout * @param readTimeoutUnit the read timeout unit */ public BlockingReadableByteChannel(final StreamSourceChannel delegate, final long readTimeout, final TimeUnit readTimeoutUnit) { if (readTimeout < 0L) { throw msg.parameterOutOfRange("readTimeout"); } this.delegate = delegate; final long calcTimeout = readTimeoutUnit.toNanos(readTimeout); this.readTimeout = readTimeout == 0L ? 0L : calcTimeout < 1L ? 1L : calcTimeout; } /** * Set the read timeout. * * @param readTimeout the read timeout * @param readTimeoutUnit the read timeout unit */ public void setReadTimeout(long readTimeout, TimeUnit readTimeoutUnit) { if (readTimeout < 0L) { throw msg.parameterOutOfRange("readTimeout"); } final long calcTimeout = readTimeoutUnit.toNanos(readTimeout); this.readTimeout = readTimeout == 0L ? 0L : calcTimeout < 1L ? 1L : calcTimeout; } /** * Perform a blocking, scattering read operation. * * @param dsts the destination buffers * @param offset the offset into the destination buffer array * @param length the number of buffers to read into * @return the number of bytes actually read (will be greater than zero) * @throws IOException if an I/O error occurs */ public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { if (!Buffers.hasRemaining(dsts, offset, length)) { return 0L; } final StreamSourceChannel delegate = this.delegate; long res; if ((res = delegate.read(dsts, offset, length)) == 0L) { long start = System.nanoTime(); long elapsed = 0L, readTimeout; do { readTimeout = this.readTimeout; if (readTimeout == 0L || readTimeout == Long.MAX_VALUE) { delegate.awaitReadable(); } else if (readTimeout <= elapsed) { throw msg.readTimeout(); } else { delegate.awaitReadable(readTimeout - elapsed, TimeUnit.NANOSECONDS); } elapsed = System.nanoTime() - start; } while ((res = delegate.read(dsts, offset, length)) == 0L); } return res; } /** * Perform a blocking, scattering read operation. * * @param dsts the destination buffers * @return the number of bytes actually read (will be greater than zero) * @throws IOException if an I/O error occurs */ public long read(final ByteBuffer[] dsts) throws IOException { return read(dsts, 0, dsts.length); } /** * Perform a blocking read operation. * * @param dst the destination buffer * @return the number of bytes actually read (will be greater than zero) * @throws IOException if an I/O error occurs */ public int read(final ByteBuffer dst) throws IOException { if (! dst.hasRemaining()) { return 0; } final StreamSourceChannel delegate = this.delegate; int res; if ((res = delegate.read(dst)) == 0) { long start = System.nanoTime(); long elapsed = 0L, readTimeout; do { readTimeout = this.readTimeout; if (readTimeout == 0L || readTimeout == Long.MAX_VALUE) { delegate.awaitReadable(); } else if (readTimeout <= elapsed) { throw msg.readTimeout(); } else { delegate.awaitReadable(readTimeout - elapsed, TimeUnit.NANOSECONDS); } elapsed = System.nanoTime() - start; } while ((res = delegate.read(dst)) == 0); } return res; } /** {@inheritDoc} */ public boolean isOpen() { return delegate.isOpen(); } /** {@inheritDoc} */ public void close() throws IOException { delegate.close(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/BlockingWritableByteChannel.java000066400000000000000000000151061257016060700305010ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2009 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import static org.xnio._private.Messages.msg; import java.nio.channels.GatheringByteChannel; import java.nio.ByteBuffer; import java.io.IOException; import java.io.Flushable; import java.util.concurrent.TimeUnit; import org.xnio.Buffers; /** * A blocking wrapper for a {@code StreamChannel}. Write operations will block until some data may be transferred. * Once any amount of data is written, the operation will return. If a write timeout is specified, then the write methods * will throw a {@link WriteTimeoutException} if the timeout expires without writing any data. */ public class BlockingWritableByteChannel implements GatheringByteChannel, Flushable { private final StreamSinkChannel delegate; private volatile long writeTimeout; /** * Construct a new instance. * * @param delegate the channel to forward I/O operations to */ public BlockingWritableByteChannel(final StreamSinkChannel delegate) { this.delegate = delegate; } /** * Construct a new instance. * * @param delegate the channel to forward I/O operations to * @param writeTimeout the write timeout * @param writeTimeoutUnit the write timeout unit */ public BlockingWritableByteChannel(final StreamSinkChannel delegate, final long writeTimeout, final TimeUnit writeTimeoutUnit) { if (writeTimeout < 0L) { throw msg.parameterOutOfRange("writeTimeout"); } this.delegate = delegate; final long calcTimeout = writeTimeoutUnit.toNanos(writeTimeout); this.writeTimeout = writeTimeout == 0L ? 0L : calcTimeout < 1L ? 1L : calcTimeout; } /** * Set the write timeout. * * @param writeTimeout the write timeout * @param writeTimeoutUnit the write timeout unit */ public void setWriteTimeout(long writeTimeout, TimeUnit writeTimeoutUnit) { if (writeTimeout < 0L) { throw msg.parameterOutOfRange("writeTimeout"); } final long calcTimeout = writeTimeoutUnit.toNanos(writeTimeout); this.writeTimeout = writeTimeout == 0L ? 0L : calcTimeout < 1L ? 1L : calcTimeout; } /** * Perform a blocking, gathering write operation. * * @param srcs the source buffers * @param offset the offset into the destination buffer array * @param length the number of buffers to write from * @return the number of bytes actually written (will be greater than zero) * @throws IOException if an I/O error occurs */ public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException { if (!Buffers.hasRemaining(srcs, offset, length)) { return 0L; } final StreamSinkChannel delegate = this.delegate; long res; if ((res = delegate.write(srcs, offset, length)) == 0L) { long start = System.nanoTime(); long elapsed = 0L, writeTimeout; do { writeTimeout = this.writeTimeout; if (writeTimeout == 0L || writeTimeout == Long.MAX_VALUE) { delegate.awaitWritable(); } else if (writeTimeout <= elapsed) { throw msg.writeTimeout(); } else { delegate.awaitWritable(writeTimeout - elapsed, TimeUnit.NANOSECONDS); } elapsed = System.nanoTime() - start; } while ((res = delegate.write(srcs, offset, length)) == 0L); } return res; } /** * Perform a blocking, gathering write operation. * * @param srcs the source buffers * @return the number of bytes actually written (will be greater than zero) * @throws IOException if an I/O error occurs */ public long write(final ByteBuffer[] srcs) throws IOException { return write(srcs, 0, srcs.length); } /** * Perform a blocking write operation. * * @param src the source buffer * @return the number of bytes actually written (will be greater than zero) * @throws IOException if an I/O error occurs */ public int write(final ByteBuffer src) throws IOException { if (! src.hasRemaining()) { return 0; } final StreamSinkChannel delegate = this.delegate; int res; if ((res = delegate.write(src)) == 0L) { long start = System.nanoTime(); long elapsed = 0L, writeTimeout; do { writeTimeout = this.writeTimeout; if (writeTimeout == 0L || writeTimeout == Long.MAX_VALUE) { delegate.awaitWritable(); } else if (writeTimeout <= elapsed) { throw msg.writeTimeout(); } else { delegate.awaitWritable(writeTimeout - elapsed, TimeUnit.NANOSECONDS); } elapsed = System.nanoTime() - start; } while ((res = delegate.write(src)) == 0L); } return res; } /** {@inheritDoc} */ public boolean isOpen() { return delegate.isOpen(); } /** {@inheritDoc} */ public void flush() throws IOException { final StreamSinkChannel delegate = this.delegate; if (! delegate.flush()) { long start = System.nanoTime(); long elapsed = 0L, writeTimeout; do { writeTimeout = this.writeTimeout; if (writeTimeout == 0L || writeTimeout == Long.MAX_VALUE) { delegate.awaitWritable(); } else if (writeTimeout <= elapsed) { throw msg.writeTimeout(); } else { delegate.awaitWritable(writeTimeout - elapsed, TimeUnit.NANOSECONDS); } elapsed = System.nanoTime() - start; } while (! delegate.flush()); } } /** {@inheritDoc} */ public void close() throws IOException { delegate.close(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/BoundChannel.java000066400000000000000000000014231257016060700254770ustar00rootroot00000000000000 package org.xnio.channels; import java.net.SocketAddress; import org.xnio.ChannelListener; /** * A channel that is bound to a local address. */ public interface BoundChannel extends CloseableChannel { /** * Get the local address that this channel is bound to. * * @return the local address */ SocketAddress getLocalAddress(); /** * Get the local address of a given type, or {@code null} if the address is not of that * type. * * @param type the address type class * @param the address type * @return the local address, or {@code null} if unknown */ A getLocalAddress(Class type); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/BoundMultipointMessageChannel.java000066400000000000000000000011401257016060700310650ustar00rootroot00000000000000 package org.xnio.channels; import org.xnio.ChannelListener; /** * A multipoint datagram channel. A multipoint datagram channel is a bound multipoint message channel. */ public interface BoundMultipointMessageChannel extends MultipointMessageChannel, BoundChannel { /** {@inheritDoc} */ ChannelListener.Setter getReadSetter(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); /** {@inheritDoc} */ ChannelListener.Setter getWriteSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/ByteChannel.java000066400000000000000000000006621257016060700253370ustar00rootroot00000000000000 package org.xnio.channels; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ScatteringByteChannel; /** * An extension of a simple NIO {@link java.nio.channels.ByteChannel} which includes scatter/gather operations. * * @author David M. Lloyd */ public interface ByteChannel extends java.nio.channels.ByteChannel, GatheringByteChannel, ScatteringByteChannel { } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/ChannelFactory.java000066400000000000000000000017711257016060700260450ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2012 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.nio.channels.Channel; /** * A generalized channel factory type. * * @author David M. Lloyd */ public interface ChannelFactory { /** * Create the channel instance. * * @return the channel instance */ C create(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/Channels.java000066400000000000000000001143141257016060700246760ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOError; import java.io.InterruptedIOException; import java.nio.channels.Channel; import java.nio.channels.FileChannel; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Locale; import org.xnio.Buffers; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; import java.nio.channels.GatheringByteChannel; import java.nio.channels.ReadableByteChannel; import java.nio.channels.ScatteringByteChannel; import java.util.concurrent.TimeUnit; import org.xnio.ChannelListener; import org.xnio.Option; import org.xnio.XnioIoThread; /** * A utility class containing static methods to support channel usage. * * @apiviz.exclude */ public final class Channels { private Channels() { } /** * Simple utility method to execute a blocking flush on a writable channel. The method blocks until there are no * remaining bytes in the send queue. * * @param channel the writable channel * @throws IOException if an I/O exception occurs * * @since 2.0 */ public static void flushBlocking(SuspendableWriteChannel channel) throws IOException { while (! channel.flush()) { channel.awaitWritable(); } } /** * Simple utility method to execute a blocking write shutdown on a writable channel. The method blocks until the * channel's output side is fully shut down. * * @param channel the writable channel * @throws IOException if an I/O exception occurs * * @since 2.0 */ public static void shutdownWritesBlocking(SuspendableWriteChannel channel) throws IOException { channel.shutdownWrites(); flushBlocking(channel); } /** * Simple utility method to execute a blocking write on a byte channel. The method blocks until the bytes in the * buffer have been fully written. To ensure that the data is sent, the {@link #flushBlocking(SuspendableWriteChannel)} * method should be called after all writes are complete. * * @param channel the channel to write on * @param buffer the data to write * @param the channel type * @return the number of bytes written * @throws IOException if an I/O exception occurs * @since 1.2 */ public static int writeBlocking(C channel, ByteBuffer buffer) throws IOException { int t = 0; while (buffer.hasRemaining()) { final int res = channel.write(buffer); if (res == 0) { channel.awaitWritable(); } else { t += res; } } return t; } /** * Simple utility method to execute a blocking write on a byte channel with a timeout. The method blocks until * either the bytes in the buffer have been fully written, or the timeout expires, whichever comes first. * * @param channel the channel to write on * @param buffer the data to write * @param time the amount of time to wait * @param unit the unit of time to wait * @param the channel type * @return the number of bytes written * @throws IOException if an I/O exception occurs * @since 1.2 */ public static int writeBlocking(C channel, ByteBuffer buffer, long time, TimeUnit unit) throws IOException { long remaining = unit.toNanos(time); long now = System.nanoTime(); int t = 0; while (buffer.hasRemaining() && remaining > 0L) { int res = channel.write(buffer); if (res == 0) { channel.awaitWritable(remaining, TimeUnit.NANOSECONDS); remaining -= Math.max(-now + (now = System.nanoTime()), 0L); } else { t += res; } } return t; } /** * Simple utility method to execute a blocking write on a gathering byte channel. The method blocks until the * bytes in the buffer have been fully written. * * @param channel the channel to write on * @param buffers the data to write * @param offs the index of the first buffer to write * @param len the number of buffers to write * @param the channel type * @return the number of bytes written * @throws IOException if an I/O exception occurs * @since 1.2 */ public static long writeBlocking(C channel, ByteBuffer[] buffers, int offs, int len) throws IOException { long t = 0; while (Buffers.hasRemaining(buffers, offs, len)) { final long res = channel.write(buffers, offs, len); if (res == 0) { channel.awaitWritable(); } else { t += res; } } return t; } /** * Simple utility method to execute a blocking write on a gathering byte channel with a timeout. The method blocks until all * the bytes are written, or until the timeout occurs. * * @param channel the channel to write on * @param buffers the data to write * @param offs the index of the first buffer to write * @param len the number of buffers to write * @param time the amount of time to wait * @param unit the unit of time to wait * @param the channel type * @return the number of bytes written * @throws IOException if an I/O exception occurs * @since 1.2 */ public static long writeBlocking(C channel, ByteBuffer[] buffers, int offs, int len, long time, TimeUnit unit) throws IOException { long remaining = unit.toNanos(time); long now = System.nanoTime(); long t = 0; while (Buffers.hasRemaining(buffers, offs, len) && remaining > 0L) { long res = channel.write(buffers, offs, len); if (res == 0) { channel.awaitWritable(remaining, TimeUnit.NANOSECONDS); remaining -= Math.max(-now + (now = System.nanoTime()), 0L); } else { t += res; } } return t; } /** * Simple utility method to execute a blocking send on a message channel. The method blocks until the message is written. * * @param channel the channel to write on * @param buffer the data to write * @param the channel type * @throws IOException if an I/O exception occurs * @since 1.2 */ public static void sendBlocking(C channel, ByteBuffer buffer) throws IOException { while (! channel.send(buffer)) { channel.awaitWritable(); } } /** * Simple utility method to execute a blocking send on a message channel with a timeout. The method blocks until the channel * is writable, and then the message is written. * * @param channel the channel to write on * @param buffer the data to write * @param time the amount of time to wait * @param unit the unit of time to wait * @param the channel type * @return the write result * @throws IOException if an I/O exception occurs * @since 1.2 */ public static boolean sendBlocking(C channel, ByteBuffer buffer, long time, TimeUnit unit) throws IOException { long remaining = unit.toNanos(time); long now = System.nanoTime(); while (remaining > 0L) { if (!channel.send(buffer)) { channel.awaitWritable(remaining, TimeUnit.NANOSECONDS); remaining -= Math.max(-now + (now = System.nanoTime()), 0L); } else { return true; } } return false; } /** * Simple utility method to execute a blocking gathering send on a message channel. The method blocks until the message is written. * * @param channel the channel to write on * @param buffers the data to write * @param offs the index of the first buffer to write * @param len the number of buffers to write * @param the channel type * @throws IOException if an I/O exception occurs * @since 1.2 */ public static void sendBlocking(C channel, ByteBuffer[] buffers, int offs, int len) throws IOException { while (! channel.send(buffers, offs, len)) { channel.awaitWritable(); } } /** * Simple utility method to execute a blocking gathering send on a message channel with a timeout. The method blocks until either * the message is written or the timeout expires. * * @param channel the channel to write on * @param buffers the data to write * @param offs the index of the first buffer to write * @param len the number of buffers to write * @param time the amount of time to wait * @param unit the unit of time to wait * @param the channel type * @return {@code true} if the message was written before the timeout * @throws IOException if an I/O exception occurs * @since 1.2 */ public static boolean sendBlocking(C channel, ByteBuffer[] buffers, int offs, int len, long time, TimeUnit unit) throws IOException { long remaining = unit.toNanos(time); long now = System.nanoTime(); while (remaining > 0L) { if (!channel.send(buffers, offs, len)) { channel.awaitWritable(remaining, TimeUnit.NANOSECONDS); remaining -= Math.max(-now + (now = System.nanoTime()), 0L); } else { return true; } } return false; } /** * Simple utility method to execute a blocking read on a readable byte channel. This method blocks until the * channel is readable, and then the message is read. * * @param channel the channel to read from * @param buffer the buffer into which bytes are to be transferred * @param the channel type * @return the number of bytes read * @throws IOException if an I/O exception occurs * @since 1.2 */ public static int readBlocking(C channel, ByteBuffer buffer) throws IOException { int res; while ((res = channel.read(buffer)) == 0 && buffer.hasRemaining()) { channel.awaitReadable(); } return res; } /** * Simple utility method to execute a blocking read on a readable byte channel with a timeout. This method blocks until the * channel is readable, and then the message is read. * * @param channel the channel to read from * @param buffer the buffer into which bytes are to be transferred * @param time the amount of time to wait * @param unit the unit of time to wait * @param the channel type * @return the number of bytes read * @throws IOException if an I/O exception occurs * @since 1.2 */ public static int readBlocking(C channel, ByteBuffer buffer, long time, TimeUnit unit) throws IOException { int res = channel.read(buffer); if (res == 0 && buffer.hasRemaining()) { channel.awaitReadable(time, unit); return channel.read(buffer); } else { return res; } } /** * Simple utility method to execute a blocking read on a scattering byte channel. This method blocks until the * channel is readable, and then the message is read. * * @param channel the channel to read from * @param buffers the buffers into which bytes are to be transferred * @param offs the first buffer to use * @param len the number of buffers to use * @param the channel type * @return the number of bytes read * @throws IOException if an I/O exception occurs * @since 1.2 */ public static long readBlocking(C channel, ByteBuffer[] buffers, int offs, int len) throws IOException { long res; while ((res = channel.read(buffers, offs, len)) == 0) { channel.awaitReadable(); } return res; } /** * Simple utility method to execute a blocking read on a scattering byte channel with a timeout. This method blocks until the * channel is readable, and then the message is read. * * @param channel the channel to read from * @param buffers the buffers into which bytes are to be transferred * @param offs the first buffer to use * @param len the number of buffers to use * @param time the amount of time to wait * @param unit the unit of time to wait * @param the channel type * @return the number of bytes read * @throws IOException if an I/O exception occurs * @since 1.2 */ public static long readBlocking(C channel, ByteBuffer[] buffers, int offs, int len, long time, TimeUnit unit) throws IOException { long res = channel.read(buffers, offs, len); if (res == 0L && Buffers.hasRemaining(buffers, offs, len)) { channel.awaitReadable(time, unit); return channel.read(buffers, offs, len); } else { return res; } } /** * Simple utility method to execute a blocking receive on a readable message channel. This method blocks until the * channel is readable, and then the message is received. * * @param channel the channel to read from * @param buffer the buffer into which bytes are to be transferred * @param the channel type * @return the number of bytes read * @throws IOException if an I/O exception occurs * @since 1.2 */ public static int receiveBlocking(C channel, ByteBuffer buffer) throws IOException { int res; while ((res = channel.receive(buffer)) == 0) { channel.awaitReadable(); } return res; } /** * Simple utility method to execute a blocking receive on a readable message channel with a timeout. This method blocks until the * channel is readable, and then the message is received. * * @param channel the channel to read from * @param buffer the buffer into which bytes are to be transferred * @param time the amount of time to wait * @param unit the unit of time to wait * @param the channel type * @return the number of bytes read * @throws IOException if an I/O exception occurs * @since 1.2 */ public static int receiveBlocking(C channel, ByteBuffer buffer, long time, TimeUnit unit) throws IOException { int res = channel.receive(buffer); if ((res) == 0) { channel.awaitReadable(time, unit); return channel.receive(buffer); } else { return res; } } /** * Simple utility method to execute a blocking receive on a readable message channel. This method blocks until the * channel is readable, and then the message is received. * * @param channel the channel to read from * @param buffers the buffers into which bytes are to be transferred * @param offs the first buffer to use * @param len the number of buffers to use * @param the channel type * @return the number of bytes read * @throws IOException if an I/O exception occurs * @since 1.2 */ public static long receiveBlocking(C channel, ByteBuffer[] buffers, int offs, int len) throws IOException { long res; while ((res = channel.receive(buffers, offs, len)) == 0) { channel.awaitReadable(); } return res; } /** * Simple utility method to execute a blocking receive on a readable message channel with a timeout. This method blocks until the * channel is readable, and then the message is received. * * @param channel the channel to read from * @param buffers the buffers into which bytes are to be transferred * @param offs the first buffer to use * @param len the number of buffers to use * @param time the amount of time to wait * @param unit the unit of time to wait * @param the channel type * @return the number of bytes read * @throws IOException if an I/O exception occurs * @since 1.2 */ public static long receiveBlocking(C channel, ByteBuffer[] buffers, int offs, int len, long time, TimeUnit unit) throws IOException { long res = channel.receive(buffers, offs, len); if ((res) == 0) { channel.awaitReadable(time, unit); return channel.receive(buffers, offs, len); } else { return res; } } /** * Simple utility method to execute a blocking accept on an accepting channel. This method blocks until * an accept is possible, and then returns the accepted connection. * * @param channel the accepting channel * @param the connection channel type * @param the accepting channel type * @return the accepted channel * @throws IOException if an I/O error occurs * @since 3.0 */ public static > C acceptBlocking(A channel) throws IOException { C accepted; while ((accepted = channel.accept()) == null) { channel.awaitAcceptable(); } return accepted; } /** * Simple utility method to execute a blocking accept on an accepting channel, with a timeout. This method blocks until * an accept is possible, and then returns the accepted connection. * * @param channel the accepting channel * @param time the amount of time to wait * @param unit the unit of time to wait * @param the connection channel type * @param the accepting channel type * @return the accepted channel, or {@code null} if the timeout occurred before a connection was accepted * @throws IOException if an I/O error occurs * @since 3.0 */ public static > C acceptBlocking(A channel, long time, TimeUnit unit) throws IOException { final C accepted = channel.accept(); if (accepted == null) { channel.awaitAcceptable(time, unit); return channel.accept(); } else { return accepted; } } /** * Transfer bytes between two channels efficiently, blocking if necessary. * * @param destination the destination channel * @param source the source file channel * @param startPosition the start position in the source file * @param count the number of bytes to transfer * @throws IOException if an I/O error occurs */ public static void transferBlocking(StreamSinkChannel destination, FileChannel source, long startPosition, final long count) throws IOException { long remaining = count; long res; while (remaining > 0L) { while ((res = destination.transferFrom(source, startPosition, remaining)) == 0L) { try { destination.awaitWritable(); } catch (InterruptedIOException e) { final long bytes = count - remaining; if (bytes > (long) Integer.MAX_VALUE) { e.bytesTransferred = -1; } else { e.bytesTransferred = (int) bytes; } } } remaining -= res; startPosition += res; } } /** * Transfer bytes between two channels efficiently, blocking if necessary. * * @param destination the destination file channel * @param source the source channel * @param startPosition the start position in the destination file * @param count the number of bytes to transfer * @throws IOException if an I/O error occurs */ public static void transferBlocking(FileChannel destination, StreamSourceChannel source, long startPosition, final long count) throws IOException { long remaining = count; long res; while (remaining > 0L) { while ((res = source.transferTo(startPosition, remaining, destination)) == 0L) { try { source.awaitReadable(); } catch (InterruptedIOException e) { final long bytes = count - remaining; if (bytes > (long) Integer.MAX_VALUE) { e.bytesTransferred = -1; } else { e.bytesTransferred = (int) bytes; } } } remaining -= res; startPosition += res; } } /** * Transfer bytes between two channels efficiently, blocking if necessary. * * @param destination the destination channel * @param source the source channel * @param throughBuffer the buffer to transfer through, * @param count the number of bytes to transfer * @return the number of bytes actually transferred (will be fewer than {@code count} if EOF was reached) * @throws IOException if the transfer fails */ public static long transferBlocking(StreamSinkChannel destination, StreamSourceChannel source, ByteBuffer throughBuffer, long count) throws IOException { long t = 0L; long res; while (t < count) { try { while ((res = source.transferTo(count, throughBuffer, destination)) == 0L) { if (throughBuffer.hasRemaining()) { writeBlocking(destination, throughBuffer); } else { source.awaitReadable(); } } t += res; } catch (InterruptedIOException e) { int transferred = e.bytesTransferred; t += transferred; if (transferred < 0 || t > (long) Integer.MAX_VALUE) { e.bytesTransferred = -1; } else { e.bytesTransferred = (int) t; } throw e; } if (res == -1L) { return t == 0L ? -1L : t; } } return t; } /** * Set the close listener for a channel (type-safe). * * @param channel the channel * @param listener the listener to set * @param the channel type */ public static void setCloseListener(T channel, ChannelListener listener) { @SuppressWarnings("unchecked") ChannelListener.Setter setter = (ChannelListener.Setter) channel.getCloseSetter(); setter.set(listener); } /** * Set the accept listener for a channel (type-safe). * * @param channel the channel * @param listener the listener to set * @param the channel type */ public static > void setAcceptListener(T channel, ChannelListener listener) { @SuppressWarnings("unchecked") ChannelListener.Setter setter = (ChannelListener.Setter) channel.getAcceptSetter(); setter.set(listener); } /** * Set the read listener for a channel (type-safe). * * @param channel the channel * @param listener the listener to set * @param the channel type */ public static void setReadListener(T channel, ChannelListener listener) { @SuppressWarnings("unchecked") ChannelListener.Setter setter = (ChannelListener.Setter) channel.getReadSetter(); setter.set(listener); } /** * Set the write listener for a channel (type-safe). * * @param channel the channel * @param listener the listener to set * @param the channel type */ public static void setWriteListener(T channel, ChannelListener listener) { @SuppressWarnings("unchecked") ChannelListener.Setter setter = (ChannelListener.Setter) channel.getWriteSetter(); setter.set(listener); } /** * Create a wrapper for a byte channel which does not expose other methods. * * @param original the original * @return the wrapped channel */ public static ByteChannel wrapByteChannel(final ByteChannel original) { return new ByteChannel() { public int read(final ByteBuffer dst) throws IOException { return original.read(dst); } public boolean isOpen() { return original.isOpen(); } public void close() throws IOException { original.close(); } public int write(final ByteBuffer src) throws IOException { return original.write(src); } public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException { return original.write(srcs, offset, length); } public long write(final ByteBuffer[] srcs) throws IOException { return original.write(srcs); } public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { return original.read(dsts, offset, length); } public long read(final ByteBuffer[] dsts) throws IOException { return original.read(dsts); } }; } /** * Get an option value from a configurable target. If the method throws an exception then the default value * is returned. * * @param configurable the configurable target * @param option the option * @param defaultValue the default value * @param the option value type * @return the value */ public static T getOption(Configurable configurable, Option option, T defaultValue) { try { final T value = configurable.getOption(option); return value == null ? defaultValue : value; } catch (IOException e) { return defaultValue; } } /** * Get an option value from a configurable target. If the method throws an exception then the default value * is returned. * * @param configurable the configurable target * @param option the option * @param defaultValue the default value * @return the value */ public static boolean getOption(Configurable configurable, Option option, boolean defaultValue) { try { final Boolean value = configurable.getOption(option); return value == null ? defaultValue : value.booleanValue(); } catch (IOException e) { return defaultValue; } } /** * Get an option value from a configurable target. If the method throws an exception then the default value * is returned. * * @param configurable the configurable target * @param option the option * @param defaultValue the default value * @return the value */ public static int getOption(Configurable configurable, Option option, int defaultValue) { try { final Integer value = configurable.getOption(option); return value == null ? defaultValue : value.intValue(); } catch (IOException e) { return defaultValue; } } /** * Get an option value from a configurable target. If the method throws an exception then the default value * is returned. * * @param configurable the configurable target * @param option the option * @param defaultValue the default value * @return the value */ public static long getOption(Configurable configurable, Option option, long defaultValue) { try { final Long value = configurable.getOption(option); return value == null ? defaultValue : value.longValue(); } catch (IOException e) { return defaultValue; } } /** * Unwrap a nested channel type. If the channel does not wrap the target type, {@code null} is returned. * * @param targetType the class to unwrap * @param channel the channel * @param the type to unwrap * @return the unwrapped type, or {@code null} if the given type is not wrapped * @see WrappedChannel */ public static T unwrap(Class targetType, Channel channel) { for (;;) { if (channel == null) { return null; } else if (targetType.isInstance(channel)) { return targetType.cast(channel); } else if (channel instanceof WrappedChannel) { channel = ((WrappedChannel)channel).getChannel(); } else { return null; } } } private static final FileChannel NULL_FILE_CHANNEL; private static final ByteBuffer DRAIN_BUFFER = ByteBuffer.allocateDirect(16384); /** * Attempt to drain the given number of bytes from the stream source channel. * * @param channel the channel to drain * @param count the number of bytes * @return the number of bytes drained, 0 if reading the channel would block, or -1 if the EOF was reached * @throws IOException if an error occurs */ public static long drain(StreamSourceChannel channel, long count) throws IOException { long total = 0L, lres; int ires; ByteBuffer buffer = null; for (;;) { if (count == 0L) return total; if (NULL_FILE_CHANNEL != null) { while (count > 0) { if ((lres = channel.transferTo(0, count, NULL_FILE_CHANNEL)) == 0L) { break; } total += lres; count -= lres; } // jump out quick if we drained the fast way if (total > 0L) return total; } if (buffer == null) buffer = DRAIN_BUFFER.duplicate(); if ((long) buffer.limit() > count) buffer.limit((int) count); ires = channel.read(buffer); buffer.clear(); switch (ires) { case -1: return total == 0L ? -1L : total; case 0: return total; default: total += (long) ires; count -= (long) ires; } } } /** * Attempt to drain the given number of bytes from the readable byte channel. * * @param channel the channel to drain * @param count the number of bytes * @return the number of bytes drained, 0 if reading the channel would block, or -1 if the EOF was reached * @throws IOException if an error occurs */ public static long drain(ReadableByteChannel channel, long count) throws IOException { if (channel instanceof StreamSourceChannel) { return drain((StreamSourceChannel) channel, count); } else { long total = 0L, lres; int ires; ByteBuffer buffer = null; for (;;) { if (count == 0L) return total; if (NULL_FILE_CHANNEL != null) { while (count > 0) { if ((lres = NULL_FILE_CHANNEL.transferFrom(channel, 0, count)) == 0L) { break; } total += lres; count -= lres; } // jump out quick if we drained the fast way if (total > 0L) return total; } if (buffer == null) buffer = DRAIN_BUFFER.duplicate(); if ((long) buffer.limit() > count) buffer.limit((int) count); ires = channel.read(buffer); buffer.clear(); switch (ires) { case -1: return total == 0L ? -1L : total; case 0: return total; default: total += (long) ires; count -= (long) ires; } } } } /** * Attempt to drain the given number of bytes from the file channel. This does nothing more than force a * read of bytes in the file. * * @param channel the channel to drain * @param position the position to drain from * @param count the number of bytes * @return the number of bytes drained, 0 if reading the channel would block, or -1 if the EOF was reached * @throws IOException if an error occurs */ public static long drain(FileChannel channel, long position, long count) throws IOException { if (channel instanceof StreamSourceChannel) { return drain((StreamSourceChannel) channel, count); } else { long total = 0L, lres; int ires; ByteBuffer buffer = null; for (;;) { if (count == 0L) return total; if (NULL_FILE_CHANNEL != null) { while (count > 0) { if ((lres = channel.transferTo(position, count, NULL_FILE_CHANNEL)) == 0L) { break; } total += lres; count -= lres; } // jump out quick if we drained the fast way if (total > 0L) return total; } if (buffer == null) buffer = DRAIN_BUFFER.duplicate(); if ((long) buffer.limit() > count) buffer.limit((int) count); ires = channel.read(buffer); buffer.clear(); switch (ires) { case -1: return total == 0L ? -1L : total; case 0: return total; default: total += (long) ires; } } } } /** * Resume reads asynchronously. Queues a task on the channel's I/O thread to resume. Note that if a channel * has multiple threads associated with it, the results may not be desirable. * * @param channel the channel to resume */ public static void resumeReadsAsync(final SuspendableReadChannel channel) { final XnioIoThread ioThread = channel.getIoThread(); if (ioThread == Thread.currentThread()) { channel.resumeReads(); } else { ioThread.execute(new Runnable() { public void run() { channel.resumeReads(); } }); } } /** * Resume writes asynchronously. Queues a task on the channel's I/O thread to resume. Note that if a channel * has multiple threads associated with it, the results may not be desirable. * * @param channel the channel to resume */ public static void resumeWritesAsync(final SuspendableWriteChannel channel) { final XnioIoThread ioThread = channel.getIoThread(); if (ioThread == Thread.currentThread()) { channel.resumeWrites(); } else { ioThread.execute(new Runnable() { public void run() { channel.resumeWrites(); } }); } } /** * Writes out the data in the buffer to the channel. If all the data is written out * then the channel will have its writes shutdown. * * @param channel The channel * @param src The buffer * @return The number of bytes written * @throws IOException */ public static int writeFinalBasic(StreamSinkChannel channel, ByteBuffer src) throws IOException { int res = channel.write(src); if(!src.hasRemaining()) { channel.shutdownWrites(); } return res; } /** * Writes out the data in the buffer to the channel. If all the data is written out * then the channel will have its writes shutdown. * * @param channel The channel * @param srcs The buffers * @param offset The offset into the srcs array * @param length The number buffers to write * @return The number of bytes written * @throws IOException */ public static long writeFinalBasic(StreamSinkChannel channel, ByteBuffer[] srcs, int offset, int length) throws IOException { final long res = channel.write(srcs, offset, length); if (!Buffers.hasRemaining(srcs, offset, length)) { channel.shutdownWrites(); } return res; } static { NULL_FILE_CHANNEL = AccessController.doPrivileged(new PrivilegedAction() { public FileChannel run() { final String osName = System.getProperty("os.name", "unknown").toLowerCase(Locale.US); try { if (osName.contains("windows")) { return new FileOutputStream("NUL:").getChannel(); } else { return new FileOutputStream("/dev/null").getChannel(); } } catch (FileNotFoundException e) { throw new IOError(e); } } }); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/CloseListenerSettable.java000066400000000000000000000036551257016060700274070ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.nio.channels.Channel; import org.xnio.ChannelListener; /** * An object which supports directly setting the close listener may implement this interface. * * @author David M. Lloyd */ public interface CloseListenerSettable { /** * Set the close listener. * * @param listener the close listener */ void setCloseListener(ChannelListener listener); /** * Get the close listener. * * @return the close listener */ ChannelListener getCloseListener(); /** * A channel listener setter implementation which delegates to the appropriate setter method. * * @param the channel type */ class Setter implements ChannelListener.Setter { private final CloseListenerSettable settable; /** * Construct a new instance. * * @param settable the settable to delegate to */ public Setter(final CloseListenerSettable settable) { this.settable = settable; } public void set(final ChannelListener listener) { settable.setCloseListener(listener); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/CloseableChannel.java000066400000000000000000000036011257016060700263210ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2009 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.io.IOException; import java.nio.channels.InterruptibleChannel; import org.xnio.ChannelListener; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; /** * A channel which is closeable. A listener may be registered which is triggered (only once) on channel close. * * @since 2.0 */ public interface CloseableChannel extends InterruptibleChannel, Configurable { /** * Get the setter which can be used to change the close listener for this channel. If the channel is already * closed, then the listener will not be called. * * @return the setter */ ChannelListener.Setter getCloseSetter(); /** * Get the worker for this channel. * * @return the worker */ XnioWorker getWorker(); /** * Get the I/O thread associated with this channel. * * @return the I/O thread associated with this channel */ XnioIoThread getIoThread(); /** * Close this channel. When a channel is closed, its close listener is invoked. Invoking this method * more than once has no additional effect. * * @throws IOException if the close failed */ void close() throws IOException; } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/ConcurrentStreamChannelAccessException.java000066400000000000000000000053251257016060700327340ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; /** * An exception which is thrown when more than one thread tries to access a stream channel at once. While it is * permissible for different threads to read and write stream channels, only one thread may read at a time, and only * one thread may write at a time. * * @author David M. Lloyd */ public class ConcurrentStreamChannelAccessException extends IllegalStateException { /** * Constructs a {@code ConcurrentStreamChannelAccessException} with no detail message. The cause is not initialized, * and may subsequently be initialized by a call to {@link #initCause(Throwable) initCause}. */ public ConcurrentStreamChannelAccessException() { } /** * Constructs a {@code ConcurrentStreamChannelAccessException} with the specified detail message. The cause is not * initialized, and may subsequently be initialized by a call to {@link #initCause(Throwable) initCause}. * * @param msg the detail message */ public ConcurrentStreamChannelAccessException(final String msg) { super(msg); } /** * Constructs a {@code ConcurrentStreamChannelAccessException} with the specified cause. The detail message is set * to: *

(cause == null ? null : cause.toString())
* (which typically contains the class and detail message of {@code cause}). * * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) */ public ConcurrentStreamChannelAccessException(final Throwable cause) { super(cause); } /** * Constructs a {@code ConcurrentStreamChannelAccessException} with the specified detail message and cause. * * @param msg the detail message * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) */ public ConcurrentStreamChannelAccessException(final String msg, final Throwable cause) { super(msg, cause); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/Configurable.java000066400000000000000000000046631257016060700255500ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.io.IOException; import org.xnio.Option; /** * A channel that has parameters that may be configured while the channel is open. * * @apiviz.exclude */ public interface Configurable { /** * Determine whether an option is supported on this channel. * * @param option the option * @return {@code true} if it is supported */ boolean supportsOption(Option option); /** * Get the value of a channel option. * * @param the type of the option value * @param option the option to get * @return the value of the option, or {@code null} if it is not set * @throws IOException if an I/O error occurred when reading the option */ T getOption(Option option) throws IOException; /** * Set an option for this channel. Unsupported options are ignored. * * @param the type of the option value * @param option the option to set * @param value the value of the option to set * @return the previous option value, if any * @throws IllegalArgumentException if the value is not acceptable for this option * @throws IOException if an I/O error occurred when modifying the option */ T setOption(Option option, T value) throws IllegalArgumentException, IOException; /** * An empty configurable instance. */ Configurable EMPTY = new Configurable() { public boolean supportsOption(final Option option) { return false; } public T getOption(final Option option) throws IOException { return null; } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return null; } }; } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/ConnectedChannel.java000066400000000000000000000013521257016060700263330ustar00rootroot00000000000000 package org.xnio.channels; import java.net.SocketAddress; import org.xnio.ChannelListener; /** * A channel that has a local and peer endpoint address. */ public interface ConnectedChannel extends BoundChannel { /** * Get the peer address of this channel. * * @return the peer address */ SocketAddress getPeerAddress(); /** * Get the peer address of a given type, or {@code null} if the address is not of that * type. * * @param type the address type class * @return the peer address, or {@code null} if unknown */ A getPeerAddress(Class type); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/ConnectedMessageChannel.java000066400000000000000000000010351257016060700276360ustar00rootroot00000000000000 package org.xnio.channels; import org.xnio.ChannelListener; /** * A channel that sends and receives messages to a connected peer. */ public interface ConnectedMessageChannel extends MessageChannel, ConnectedChannel { /** {@inheritDoc} */ ChannelListener.Setter getReadSetter(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); /** {@inheritDoc} */ ChannelListener.Setter getWriteSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/ConnectedSslStreamChannel.java000066400000000000000000000010241257016060700301650ustar00rootroot00000000000000 package org.xnio.channels; import org.xnio.ChannelListener; /** * A TLS-encapsulated connected stream channel. */ public interface ConnectedSslStreamChannel extends ConnectedStreamChannel, SslChannel { /** {@inheritDoc} */ ChannelListener.Setter getReadSetter(); /** {@inheritDoc} */ ChannelListener.Setter getWriteSetter(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/ConnectedStreamChannel.java000066400000000000000000000010431257016060700275040ustar00rootroot00000000000000 package org.xnio.channels; import org.xnio.ChannelListener; /** * A stream channel that is a connection between a local and remote endpoint. */ public interface ConnectedStreamChannel extends StreamChannel, ConnectedChannel { /** {@inheritDoc} */ ChannelListener.Setter getReadSetter(); /** {@inheritDoc} */ ChannelListener.Setter getWriteSetter(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/EmptyStreamSourceChannel.java000066400000000000000000000162541257016060700300730ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.Option; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import static org.xnio.Bits.allAreClear; import static org.xnio.Bits.allAreSet; import static org.xnio.Bits.anyAreSet; /** * A stream source channel which is always empty. * * @author David M. Lloyd */ public class EmptyStreamSourceChannel implements StreamSourceChannel, ReadListenerSettable, CloseListenerSettable { private final XnioIoThread thread; private final Runnable readRunnable = new Runnable() { public void run() { ChannelListener listener = readListener; if (listener == null) { suspendReads(); return; } ChannelListeners.invokeChannelListener(EmptyStreamSourceChannel.this, listener); final int oldVal = state; if (allAreSet(oldVal, RESUMED) && allAreClear(oldVal, EMPTIED | CLOSED)) { thread.execute(this); } } }; @SuppressWarnings("unused") private volatile int state; private ChannelListener readListener; private ChannelListener closeListener; private static final int CLOSED = 1 << 0; private static final int EMPTIED = 1 << 1; private static final int RESUMED = 1 << 2; private static final AtomicIntegerFieldUpdater stateUpdater = AtomicIntegerFieldUpdater.newUpdater(EmptyStreamSourceChannel.class, "state"); /** * Construct a new instance. * * @param thread the XNIO read thread to use */ public EmptyStreamSourceChannel(final XnioIoThread thread) { this.thread = thread; } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { return 0; } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { throughBuffer.limit(0); emptied(); return -1; } public void setReadListener(final ChannelListener readListener) { this.readListener = readListener; } public ChannelListener getReadListener() { return readListener; } public void setCloseListener(final ChannelListener closeListener) { this.closeListener = closeListener; } public ChannelListener getCloseListener() { return closeListener; } public ChannelListener.Setter getReadSetter() { return new ReadListenerSettable.Setter(this); } public ChannelListener.Setter getCloseSetter() { return new CloseListenerSettable.Setter(this); } private void emptied() { int oldVal, newVal; do { oldVal = state; if (allAreSet(oldVal, EMPTIED)) { return; } newVal = oldVal | EMPTIED; } while (! stateUpdater.compareAndSet(this, oldVal, newVal)); } public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { emptied(); return -1; } public long read(final ByteBuffer[] dsts) throws IOException { emptied(); return -1; } public int read(final ByteBuffer dst) throws IOException { emptied(); return -1; } public void suspendReads() { int oldVal, newVal; do { oldVal = state; if (allAreClear(oldVal, RESUMED)) { return; } newVal = oldVal & ~RESUMED; } while (! stateUpdater.compareAndSet(this, oldVal, newVal)); } public void resumeReads() { int oldVal, newVal; do { oldVal = state; if (anyAreSet(oldVal, RESUMED | CLOSED)) { return; } newVal = RESUMED; } while (! stateUpdater.compareAndSet(this, oldVal, newVal)); if (allAreClear(oldVal, EMPTIED)) { thread.execute(readRunnable); } } public boolean isReadResumed() { return allAreSet(state, RESUMED); } public void wakeupReads() { int oldVal, newVal; do { oldVal = state; if (anyAreSet(oldVal, CLOSED)) { return; } newVal = RESUMED; } while (! stateUpdater.compareAndSet(this, oldVal, newVal)); thread.execute(readRunnable); } public void shutdownReads() throws IOException { final int oldVal = stateUpdater.getAndSet(this, EMPTIED | CLOSED); if (allAreClear(oldVal, CLOSED)) { thread.execute(ChannelListeners.getChannelListenerTask(this, closeListener)); } } public void awaitReadable() throws IOException { // return immediately } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { // return immediately } @Deprecated public XnioExecutor getReadThread() { return thread; } public XnioIoThread getIoThread() { return thread; } public XnioWorker getWorker() { return thread.getWorker(); } public boolean isOpen() { return allAreClear(state, CLOSED); } public void close() throws IOException { final int oldVal = stateUpdater.getAndSet(this, EMPTIED | CLOSED); if (allAreClear(oldVal, CLOSED)) { thread.execute(ChannelListeners.getChannelListenerTask(this, closeListener)); } } public boolean supportsOption(final Option option) { return false; } public T getOption(final Option option) throws IOException { return null; } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return null; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/FixedLengthOverflowException.java000066400000000000000000000050051257016060700307430ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.channels; import java.io.IOException; /** * Exception thrown when a fixed-length write channel is written beyond its full length. * * @author David M. Lloyd */ public class FixedLengthOverflowException extends IOException { private static final long serialVersionUID = 475540863890698430L; /** * Constructs a {@code FixedLengthOverflowException} with no detail message. The cause is not initialized, and may * subsequently be initialized by a call to {@link #initCause(Throwable) initCause}. */ public FixedLengthOverflowException() { } /** * Constructs a {@code FixedLengthOverflowException} with the specified detail message. The cause is not * initialized, and may subsequently be initialized by a call to {@link #initCause(Throwable) initCause}. * * @param msg the detail message */ public FixedLengthOverflowException(final String msg) { super(msg); } /** * Constructs a {@code FixedLengthOverflowException} with the specified cause. The detail message is set to: *
(cause == null ? null : cause.toString())
* (which typically contains the class and detail message of {@code cause}). * * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) */ public FixedLengthOverflowException(final Throwable cause) { super(cause); } /** * Constructs a {@code FixedLengthOverflowException} with the specified detail message and cause. * * @param msg the detail message * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) */ public FixedLengthOverflowException(final String msg, final Throwable cause) { super(msg, cause); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/FixedLengthStreamSinkChannel.java000066400000000000000000000330541257016060700306370ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.channels; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.Option; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import static java.lang.Math.min; import static org.xnio.Bits.*; import static org.xnio.IoUtils.safeClose; import static org.xnio._private.Messages.msg; /** * A channel which writes a fixed amount of data. A listener is called once the data has been written. * * @author David M. Lloyd */ public final class FixedLengthStreamSinkChannel implements StreamSinkChannel, ProtectedWrappedChannel, WriteListenerSettable, CloseListenerSettable { private final StreamSinkChannel delegate; private final Object guard; private final ChannelListener finishListener; private ChannelListener writeListener; private ChannelListener closeListener; private int state; private long count; private static final int FLAG_CLOSE_REQUESTED = 1 << 0; private static final int FLAG_CLOSE_COMPLETE = 1 << 1; private static final int FLAG_CONFIGURABLE = 1 << 2; private static final int FLAG_PASS_CLOSE = 1 << 3; /** * Construct a new instance. * * @param delegate the delegate channel * @param contentLength the content length * @param configurable {@code true} if this instance should pass configuration to the delegate * @param propagateClose {@code true} if this instance should pass close to the delegate * @param finishListener the listener to call when the channel is closed or the length is reached * @param guard the guard object to use */ public FixedLengthStreamSinkChannel(final StreamSinkChannel delegate, final long contentLength, final boolean configurable, final boolean propagateClose, final ChannelListener finishListener, final Object guard) { if (contentLength < 0L) { throw msg.parameterOutOfRange("contentLength"); } if (delegate == null) { throw msg.nullParameter("delegate"); } this.guard = guard; this.delegate = delegate; this.finishListener = finishListener; state = (configurable ? FLAG_CONFIGURABLE : 0) | (propagateClose ? FLAG_PASS_CLOSE : 0); count = contentLength; delegate.getWriteSetter().set(new ChannelListener() { public void handleEvent(final StreamSinkChannel channel) { ChannelListeners.invokeChannelListener(FixedLengthStreamSinkChannel.this, writeListener); } }); } public void setWriteListener(final ChannelListener listener) { this.writeListener = listener; } public ChannelListener getWriteListener() { return writeListener; } public void setCloseListener(final ChannelListener listener) { this.closeListener = listener; } public ChannelListener getCloseListener() { return closeListener; } public ChannelListener.Setter getWriteSetter() { return new WriteListenerSettable.Setter(this); } public ChannelListener.Setter getCloseSetter() { return new CloseListenerSettable.Setter(this); } @Override public int writeFinal(ByteBuffer src) throws IOException { return write(src, true); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { return write(srcs, offset, length, true); } @Override public long writeFinal(ByteBuffer[] srcs) throws IOException { return write(srcs, 0, srcs.length, true); } public StreamSinkChannel getChannel(final Object guard) { final Object ourGuard = this.guard; if (ourGuard == null || guard == ourGuard) { return delegate; } else { return null; } } @Deprecated public XnioExecutor getWriteThread() { return delegate.getWriteThread(); } public XnioIoThread getIoThread() { return delegate.getIoThread(); } public XnioWorker getWorker() { return delegate.getWorker(); } @Override public int write(final ByteBuffer src) throws IOException { return write(src, false); } private int write(final ByteBuffer src, final boolean finalWrite) throws IOException { if (allAreSet(state, FLAG_CLOSE_REQUESTED)) { throw new ClosedChannelException(); } if (! src.hasRemaining()) { return 0; } int res = 0; final long remaining = count; if (remaining == 0L) { throw msg.fixedOverflow(); } try { final int lim = src.limit(); final int pos = src.position(); if (lim - pos > remaining) { src.limit((int) (remaining - (long) pos)); try { return res = doWrite(src, finalWrite); } finally { src.limit(lim); } } else { return res = doWrite(src, finalWrite); } } finally { count = remaining - res; } } public long write(final ByteBuffer[] srcs) throws IOException { return write(srcs, 0, srcs.length); } public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException { return write(srcs, offset, length, false); } private long write(final ByteBuffer[] srcs, final int offset, final int length, boolean writeFinal) throws IOException { if (allAreSet(state, FLAG_CLOSE_REQUESTED)) { throw new ClosedChannelException(); } if (length == 0) { return 0L; } else if (length == 1) { return write(srcs[offset]); } final long remaining = count; if (remaining == 0L) { throw msg.fixedOverflow(); } long res = 0L; try { int lim; // The total amount of buffer space discovered so far. long t = 0L; for (int i = 0; i < length; i ++) { final ByteBuffer buffer = srcs[i + offset]; // Grow the discovered buffer space by the remaining size of the current buffer. // We want to capture the limit so we calculate "remaining" ourselves. t += (lim = buffer.limit()) - buffer.position(); if (t > remaining) { // only read up to this point, and trim the last buffer by the number of extra bytes buffer.limit(lim - (int) (t - (remaining))); try { return res = doWrite(srcs, offset, i + 1, writeFinal); } finally { // restore the original limit buffer.limit(lim); } } } if (t == 0L) { return 0L; } // the total buffer space is less than the remaining count. return res = doWrite(srcs, offset, length, writeFinal); } finally { count = remaining - res; } } private long doWrite(ByteBuffer[] srcs, int offset, int length, final boolean writeFinal) throws IOException { if(writeFinal) { return delegate.writeFinal(srcs, offset, length); } return delegate.write(srcs, offset, length); } private int doWrite(ByteBuffer src, boolean finalWrite) throws IOException { if(finalWrite) { return delegate.writeFinal(src); } return delegate.write(src); } public long transferFrom(final FileChannel src, final long position, final long count) throws IOException { if (allAreSet(state, FLAG_CLOSE_REQUESTED)) { throw new ClosedChannelException(); } if (count == 0L) return 0L; final long remaining = this.count; if (remaining == 0L) { throw msg.fixedOverflow(); } long res = 0L; try { return res = delegate.transferFrom(src, position, min(count, remaining)); } finally { this.count = remaining - res; } } public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { if (allAreSet(state, FLAG_CLOSE_REQUESTED)) { throw new ClosedChannelException(); } if (count == 0L) return 0L; final long remaining = this.count; if (remaining == 0L) { throw msg.fixedOverflow(); } long res = 0L; try { return res = delegate.transferFrom(source, min(count, remaining), throughBuffer); } finally { this.count = remaining - res; } } public boolean flush() throws IOException { int state = this.state; if (anyAreSet(state, FLAG_CLOSE_COMPLETE)) { return true; } boolean flushed = false; try { return flushed = delegate.flush(); } finally { if (flushed && allAreSet(state, FLAG_CLOSE_REQUESTED)) { this.state = state | FLAG_CLOSE_COMPLETE; callFinish(); callClosed(); if (count != 0) { throw msg.fixedUnderflow(count); } } } } public void suspendWrites() { if (allAreClear(state, FLAG_CLOSE_COMPLETE)) { delegate.suspendWrites(); } } public void resumeWrites() { if (allAreClear(state, FLAG_CLOSE_COMPLETE)) { delegate.resumeWrites(); } } public boolean isWriteResumed() { return allAreClear(state, FLAG_CLOSE_COMPLETE) && delegate.isWriteResumed(); } public void wakeupWrites() { if (allAreClear(state, FLAG_CLOSE_COMPLETE)) { delegate.wakeupWrites(); } } public void shutdownWrites() throws IOException { final int state = this.state; if (allAreSet(state, FLAG_CLOSE_REQUESTED)) { return; // idempotent } this.state = state | FLAG_CLOSE_REQUESTED; if (allAreSet(state, FLAG_PASS_CLOSE)) { delegate.shutdownWrites(); } } public void awaitWritable() throws IOException { delegate.awaitWritable(); } public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException { delegate.awaitWritable(time, timeUnit); } public boolean isOpen() { return allAreClear(state, FLAG_CLOSE_REQUESTED); } public void close() throws IOException { final int state = this.state; if (allAreSet(state, FLAG_CLOSE_COMPLETE)) { return; // idempotent } this.state = state | FLAG_CLOSE_REQUESTED | FLAG_CLOSE_COMPLETE; try { final long count = this.count; if (count != 0) { if (allAreSet(state, FLAG_PASS_CLOSE)) { safeClose(delegate); } throw msg.fixedUnderflow(count); } if (allAreSet(state, FLAG_PASS_CLOSE)) { delegate.close(); } } finally { callClosed(); callFinish(); } } public boolean supportsOption(final Option option) { return allAreSet(state, FLAG_CONFIGURABLE) && delegate.supportsOption(option); } public T getOption(final Option option) throws IOException { return allAreSet(state, FLAG_CONFIGURABLE) ? delegate.getOption(option) : null; } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return allAreSet(state, FLAG_CONFIGURABLE) ? delegate.setOption(option, value) : null; } /** * Get the number of remaining bytes in this fixed length channel. * * @return the number of remaining bytes */ public long getRemaining() { return count; } private void callFinish() { ChannelListeners.invokeChannelListener(this, finishListener); } private void callClosed() { ChannelListeners.invokeChannelListener(this, closeListener); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/FixedLengthStreamSourceChannel.java000066400000000000000000000355251257016060700312000ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.Option; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import static java.lang.Math.min; import static org.xnio.Bits.*; import static org.xnio._private.Messages.msg; /** * A channel which reads data of a fixed length and calls a finish listener. When the finish listener is called, * it should examine the result of {@link #getRemaining()} to see if more bytes were pending when the channel was * closed. * * @author David M. Lloyd */ public final class FixedLengthStreamSourceChannel implements StreamSourceChannel, ProtectedWrappedChannel, ReadListenerSettable, CloseListenerSettable { private final StreamSourceChannel delegate; private final Object guard; private final ChannelListener finishListener; private ChannelListener readListener; private ChannelListener closeListener; private int state; private long remaining; private static final int FLAG_CLOSED = 1 << 0; private static final int FLAG_FINISHED = 1 << 1; private static final int FLAG_CONFIGURABLE = 1 << 2; private static final int FLAG_PASS_CLOSE = 1 << 3; /** * Construct a new instance. The given listener is called once all the bytes are read from the stream * or the stream is closed. This listener should cause the remaining data to be drained from the * underlying stream via the {@link #drain()} method if the underlying stream is to be reused. *

* Calling this constructor will replace the read listener of the underlying channel. The listener should be * restored from the {@code finishListener} object. The underlying stream should not be closed while this wrapper * stream is active. * * @param delegate the stream source channel to read from * @param contentLength the amount of content to read * @param finishListener the listener to call once the stream is exhausted or closed * @param guard the guard object to use */ public FixedLengthStreamSourceChannel(final StreamSourceChannel delegate, final long contentLength, final ChannelListener finishListener, final Object guard) { this(delegate, contentLength, false, finishListener, guard); } /** * Construct a new instance. The given listener is called once all the bytes are read from the stream * or the stream is closed. This listener should cause the remaining data to be drained from the * underlying stream via the {@link #drain()} method if the underlying stream is to be reused. *

* Calling this constructor will replace the read listener of the underlying channel. The listener should be * restored from the {@code finishListener} object. The underlying stream should not be closed while this wrapper * stream is active. * * @param delegate the stream source channel to read from * @param contentLength the amount of content to read * @param configurable {@code true} to allow options to pass through to the delegate, {@code false} otherwise * @param finishListener the listener to call once the stream is exhausted or closed * @param guard the guard object to use */ public FixedLengthStreamSourceChannel(final StreamSourceChannel delegate, final long contentLength, final boolean configurable, final ChannelListener finishListener, final Object guard) { this(delegate, contentLength, configurable, false, finishListener, guard); } /** * Construct a new instance. The given listener is called once all the bytes are read from the stream * or the stream is closed. This listener should cause the remaining data to be drained from the * underlying stream via the {@link #drain()} method if the underlying stream is to be reused. *

* Calling this constructor will replace the read listener of the underlying channel. The listener should be * restored from the {@code finishListener} object. The underlying stream should not be closed while this wrapper * stream is active. * * @param delegate the stream source channel to read from * @param contentLength the amount of content to read * @param configurable {@code true} to allow options to pass through to the delegate, {@code false} otherwise * @param propagateClose {@code true} to propagate close/shutdown to the delegate, {@code false} otherwise * @param finishListener the listener to call once the stream is exhausted or closed * @param guard the guard object to use */ public FixedLengthStreamSourceChannel(final StreamSourceChannel delegate, final long contentLength, final boolean configurable, final boolean propagateClose, final ChannelListener finishListener, final Object guard) { this.guard = guard; this.finishListener = finishListener; if (contentLength < 0L) { throw msg.parameterOutOfRange("contentLength"); } this.delegate = delegate; remaining = contentLength; delegate.getReadSetter().set(new ChannelListener() { public void handleEvent(final StreamSourceChannel channel) { ChannelListeners.invokeChannelListener(FixedLengthStreamSourceChannel.this, readListener); } }); state = (configurable ? FLAG_CONFIGURABLE : 0) | (propagateClose ? FLAG_PASS_CLOSE : 0); } public void setReadListener(final ChannelListener readListener) { this.readListener = readListener; } public ChannelListener getReadListener() { return readListener; } public void setCloseListener(final ChannelListener closeListener) { this.closeListener = closeListener; } public ChannelListener getCloseListener() { return closeListener; } public ChannelListener.Setter getReadSetter() { return new ReadListenerSettable.Setter(this); } public ChannelListener.Setter getCloseSetter() { return new CloseListenerSettable.Setter(this); } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { final long remaining = this.remaining; if (anyAreSet(state, FLAG_CLOSED | FLAG_FINISHED) || remaining == 0L || count == 0L) { return 0L; } long res = 0L; try { return res = delegate.transferTo(position, min(count, remaining), target); } finally { if (res > 0L) { if ((this.remaining = remaining - res) == 0L) { state |= FLAG_FINISHED; callFinish(); } } } } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { final long remaining = this.remaining; if (anyAreSet(state, FLAG_CLOSED | FLAG_FINISHED) || remaining == 0L) { return -1L; } if (count == 0L) { return 0L; } long res = 0L; try { return res = delegate.transferTo(min(count, remaining), throughBuffer, target); } finally { if (res > 0L) { if ((this.remaining = remaining - res) == 0L) { state |= FLAG_FINISHED; callFinish(); } } } } public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { final long remaining = this.remaining; if (anyAreSet(state, FLAG_CLOSED | FLAG_FINISHED) || remaining == 0L) { return -1L; } if (length == 0) { return 0L; } else if (length == 1) { return read(dsts[offset]); } long res = 0L; try { int lim; // The total amount of buffer space discovered so far. long t = 0L; for (int i = 0; i < length; i ++) { final ByteBuffer buffer = dsts[i + offset]; // Grow the discovered buffer space by the remaining size of the current buffer. // We want to capture the limit so we calculate "remaining" ourselves. t += (lim = buffer.limit()) - buffer.position(); if (t > remaining) { // only read up to this point, and trim the last buffer by the number of extra bytes buffer.limit(lim - (int) (t - remaining)); try { return res = delegate.read(dsts, offset, i + 1); } finally { // restore the original limit buffer.limit(lim); } } } // the total buffer space is less than the remaining count. return res = t == 0L ? 0L : delegate.read(dsts, offset, length); } finally { if (res > 0L) { if ((this.remaining = remaining - res) == 0L) { state |= FLAG_FINISHED; callFinish(); } } } } public long read(final ByteBuffer[] dsts) throws IOException { return read(dsts, 0, dsts.length); } public int read(final ByteBuffer dst) throws IOException { final long remaining = this.remaining; if (anyAreSet(state, FLAG_CLOSED | FLAG_FINISHED) || remaining == 0L) { return -1; } int res = 0; try { final int lim = dst.limit(); final int pos = dst.position(); if (lim - pos > remaining) { dst.limit((int) (remaining - (long) pos)); try { return res = delegate.read(dst); } finally { dst.limit(lim); } } else { return res = delegate.read(dst); } } finally { if (res > 0) { if ((this.remaining = remaining - res) == 0L) { state |= FLAG_FINISHED; callFinish(); } } } } public void suspendReads() { if (allAreClear(state, FLAG_CLOSED | FLAG_FINISHED)) { delegate.suspendReads(); } } public void resumeReads() { if (allAreClear(state, FLAG_CLOSED | FLAG_FINISHED)) { delegate.resumeReads(); } else { delegate.getIoThread().execute(ChannelListeners.getChannelListenerTask(this, readListener)); } } public boolean isReadResumed() { return allAreClear(state, FLAG_CLOSED | FLAG_FINISHED) && delegate.isReadResumed(); } public void wakeupReads() { if (allAreClear(state, FLAG_CLOSED | FLAG_FINISHED)) { delegate.wakeupReads(); } else { delegate.getIoThread().execute(ChannelListeners.getChannelListenerTask(this, readListener)); } } public void shutdownReads() throws IOException { final int state = this.state; if (allAreClear(state, FLAG_CLOSED)) try { this.state = state | FLAG_CLOSED | FLAG_FINISHED; if (allAreSet(state, FLAG_PASS_CLOSE)) { delegate.shutdownReads(); } } finally { if (allAreClear(state, FLAG_FINISHED)) callFinish(); callClosed(); } } public void awaitReadable() throws IOException { if (anyAreSet(state, FLAG_CLOSED | FLAG_FINISHED)) { return; } delegate.awaitReadable(); } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { if (anyAreSet(state, FLAG_CLOSED | FLAG_FINISHED)) { return; } delegate.awaitReadable(time, timeUnit); } @Deprecated public XnioExecutor getReadThread() { return delegate.getReadThread(); } public XnioIoThread getIoThread() { return delegate.getIoThread(); } public XnioWorker getWorker() { return delegate.getWorker(); } public boolean isOpen() { return allAreClear(state, FLAG_CLOSED); } public void close() throws IOException { shutdownReads(); } public boolean supportsOption(final Option option) { return allAreSet(state, FLAG_CONFIGURABLE) && delegate.supportsOption(option); } public T getOption(final Option option) throws IOException { return allAreSet(state, FLAG_CONFIGURABLE) ? delegate.getOption(option) : null; } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return allAreSet(state, FLAG_CONFIGURABLE) ? delegate.setOption(option, value) : null; } public StreamSourceChannel getChannel(final Object guard) { final Object ourGuard = this.guard; if (ourGuard == null || guard == ourGuard) { return delegate; } else { return null; } } /** * Get the number of remaining bytes. * * @return the number of remaining bytes */ public long getRemaining() { return remaining; } private void callFinish() { ChannelListeners.invokeChannelListener(this, finishListener); } private void callClosed() { ChannelListeners.invokeChannelListener(this, closeListener); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/FixedLengthUnderflowException.java000066400000000000000000000047731257016060700311200ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.channels; import java.io.IOException; /** * Exception thrown when a fixed-length write channel is not written to its full length. * * @author David M. Lloyd */ public class FixedLengthUnderflowException extends IOException { private static final long serialVersionUID = 7294784996964683484L; /** * Constructs a {@code UnfinishedWriteException} with no detail message. The cause is not initialized, and may * subsequently be initialized by a call to {@link #initCause(Throwable) initCause}. */ public FixedLengthUnderflowException() { } /** * Constructs a {@code UnfinishedWriteException} with the specified detail message. The cause is not initialized, * and may subsequently be initialized by a call to {@link #initCause(Throwable) initCause}. * * @param msg the detail message */ public FixedLengthUnderflowException(final String msg) { super(msg); } /** * Constructs a {@code UnfinishedWriteException} with the specified cause. The detail message is set to: *

(cause == null ? null : cause.toString())
* (which typically contains the class and detail message of {@code cause}). * * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) */ public FixedLengthUnderflowException(final Throwable cause) { super(cause); } /** * Constructs a {@code UnfinishedWriteException} with the specified detail message and cause. * * @param msg the detail message * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) */ public FixedLengthUnderflowException(final String msg, final Throwable cause) { super(msg, cause); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/FramedMessageChannel.java000066400000000000000000000346201257016060700271400ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import static org.xnio._private.Messages.msg; import java.io.EOFException; import java.io.IOException; import java.net.SocketAddress; import java.nio.ByteBuffer; import org.jboss.logging.Logger; import org.xnio.Buffers; import org.xnio.IoUtils; import org.xnio.Pooled; /** * A connected message channel providing a SASL-style framing layer over a stream channel where each message is prepended * by a four-byte length field. * * @author David M. Lloyd * * @deprecated This class is deprecated; use conduits instead. */ @SuppressWarnings("unused") @Deprecated public class FramedMessageChannel extends TranslatingSuspendableChannel implements ConnectedMessageChannel { private static final Logger log = Logger.getLogger("org.xnio.channels.framed"); private final Pooled receiveBuffer; private final Pooled transmitBuffer; private final Object readLock = new Object(); private final Object writeLock = new Object(); /** * Construct a new instance. * * @param channel the channel to wrap * @param receiveBuffer the receive buffer (should be direct) * @param transmitBuffer the send buffer (should be direct) */ public FramedMessageChannel(final ConnectedStreamChannel channel, final ByteBuffer receiveBuffer, final ByteBuffer transmitBuffer) { super(channel); this.receiveBuffer = Buffers.pooledWrapper(receiveBuffer); this.transmitBuffer = Buffers.pooledWrapper(transmitBuffer); log.tracef("Created new framed message channel around %s, receive buffer %s, transmit buffer %s", channel, receiveBuffer, transmitBuffer); } /** * Construct a new instance. * * @param channel the channel to wrap * @param receiveBuffer the receive buffer (should be direct) * @param transmitBuffer the send buffer (should be direct) */ public FramedMessageChannel(final ConnectedStreamChannel channel, final Pooled receiveBuffer, final Pooled transmitBuffer) { super(channel); this.receiveBuffer = receiveBuffer; this.transmitBuffer = transmitBuffer; log.tracef("Created new framed message channel around %s, receive buffer %s, transmit buffer %s", channel, receiveBuffer, transmitBuffer); } /** {@inheritDoc} */ public int receive(final ByteBuffer buffer) throws IOException { synchronized (readLock) { if (isReadShutDown()) { return -1; } final ByteBuffer receiveBuffer = this.receiveBuffer.getResource(); int res; final ConnectedStreamChannel channel = (ConnectedStreamChannel) this.channel; do { res = channel.read(receiveBuffer); } while (res > 0); if (receiveBuffer.position() < 4) { if (res == -1) { receiveBuffer.clear(); } log.tracef("Did not read a length"); clearReadReady(); // must be <= 0 return res; } receiveBuffer.flip(); try { final int length = receiveBuffer.getInt(); if (length < 0 || length > receiveBuffer.capacity() - 4) { Buffers.unget(receiveBuffer, 4); throw msg.recvInvalidMsgLength(length); } if (receiveBuffer.remaining() < length) { if (res == -1) { receiveBuffer.clear(); } else { Buffers.unget(receiveBuffer, 4); receiveBuffer.compact(); } log.tracef("Did not read enough bytes for a full message"); clearReadReady(); // must be <= 0 return res; } if (buffer.hasRemaining()) { log.tracef("Copying message from %s into %s", receiveBuffer, buffer); Buffers.copy(buffer, Buffers.slice(receiveBuffer, length)); } else { log.tracef("Not copying message from %s into full buffer %s", receiveBuffer, buffer); Buffers.skip(receiveBuffer, length); } // move on to next message receiveBuffer.compact(); return length; } finally { if (res != -1) { if (receiveBuffer.position() >= 4 && receiveBuffer.position() >= 4 + receiveBuffer.getInt(0)) { // there's another packet ready to go setReadReady(); } } } } } /** {@inheritDoc} */ public long receive(final ByteBuffer[] buffers) throws IOException { return receive(buffers, 0, buffers.length); } /** {@inheritDoc} */ public long receive(final ByteBuffer[] buffers, final int offs, final int len) throws IOException { synchronized (readLock) { if (isReadShutDown()) { return -1; } final ByteBuffer receiveBuffer = this.receiveBuffer.getResource(); int res; final ConnectedStreamChannel channel = (ConnectedStreamChannel) this.channel; do { res = channel.read(receiveBuffer); } while (res > 0); if (receiveBuffer.position() < 4) { if (res == -1) { receiveBuffer.clear(); } log.tracef("Did not read a length"); clearReadReady(); return res; } receiveBuffer.flip(); try { final int length = receiveBuffer.getInt(); if (length < 0 || length > receiveBuffer.capacity() - 4) { Buffers.unget(receiveBuffer, 4); throw msg.recvInvalidMsgLength(length); } if (receiveBuffer.remaining() < length) { if (res == -1) { receiveBuffer.clear(); } else { Buffers.unget(receiveBuffer, 4); receiveBuffer.compact(); } log.tracef("Did not read enough bytes for a full message"); clearReadReady(); // must be <= 0 return res; } if (Buffers.hasRemaining(buffers)) { log.tracef("Copying message from %s into multiple buffers", receiveBuffer); Buffers.copy(buffers, offs, len, Buffers.slice(receiveBuffer, length)); } else { log.tracef("Not copying message from %s into multiple full buffers", receiveBuffer); Buffers.skip(receiveBuffer, length); } // move on to next message receiveBuffer.compact(); return length; } finally { if (res != -1) { if (receiveBuffer.position() >= 4 && receiveBuffer.position() >= 4 + receiveBuffer.getInt(0)) { // there's another packet ready to go setReadReady(); } } } } } protected void shutdownReadsAction(final boolean writeComplete) throws IOException { synchronized (readLock) { log.tracef("Shutting down reads on %s", this); try { receiveBuffer.getResource().clear(); } catch (Throwable t) { } try { receiveBuffer.free(); } catch (Throwable t) { } } channel.shutdownReads(); } /** {@inheritDoc} */ public boolean send(final ByteBuffer buffer) throws IOException { synchronized (writeLock) { if (isWriteShutDown()) { throw msg.writeShutDown(); } if (!buffer.hasRemaining()) { return true; } final ByteBuffer transmitBuffer = this.transmitBuffer.getResource(); final int remaining = buffer.remaining(); if (remaining > transmitBuffer.capacity() - 4) { throw msg.txMsgTooLarge(); } log.tracef("Accepting %s into %s", buffer, transmitBuffer); if (transmitBuffer.remaining() < 4 + remaining && ! doFlushBuffer()) { log.tracef("Insufficient room to accept %s into %s", buffer, transmitBuffer); return false; } transmitBuffer.putInt(remaining); transmitBuffer.put(buffer); log.tracef("Accepted a message into %s", transmitBuffer); doFlush(); return true; } } /** {@inheritDoc} */ public boolean send(final ByteBuffer[] buffers) throws IOException { return send(buffers, 0, buffers.length); } /** {@inheritDoc} */ public boolean send(final ByteBuffer[] buffers, final int offs, final int len) throws IOException { synchronized (writeLock) { if (isWriteShutDown()) { throw msg.writeShutDown(); } if (!Buffers.hasRemaining(buffers, offs, len)) { return true; } final ByteBuffer transmitBuffer = this.transmitBuffer.getResource(); final long remaining = Buffers.remaining(buffers, offs, len); if (remaining > transmitBuffer.capacity() - 4L) { throw msg.txMsgTooLarge(); } log.tracef("Accepting multiple buffers into %s", transmitBuffer); if (transmitBuffer.remaining() < 4 + remaining && ! doFlushBuffer()) { log.tracef("Insufficient room to accept multiple buffers into %s", transmitBuffer); return false; } transmitBuffer.putInt((int) remaining); Buffers.copy(transmitBuffer, buffers, offs, len); log.tracef("Accepted a message into %s", transmitBuffer); doFlush(); return true; } } @Override public boolean sendFinal(ByteBuffer buffer) throws IOException { if(send(buffer)) { shutdownWrites(); return true; } return false; } @Override public boolean sendFinal(ByteBuffer[] buffers) throws IOException { if(send(buffers)) { shutdownWrites(); return true; } return false; } @Override public boolean sendFinal(ByteBuffer[] buffers, int offs, int len) throws IOException { if(send(buffers, offs, len)) { shutdownWrites(); return true; } return false; } protected boolean flushAction(final boolean shutDown) throws IOException { synchronized (writeLock) { return (doFlushBuffer()) && channel.flush(); } } protected void shutdownWritesComplete(final boolean readShutDown) throws IOException { synchronized (writeLock) { log.tracef("Finished shutting down writes on %s", this); try { transmitBuffer.free(); } catch (Throwable t) {} } channel.shutdownWrites(); } private boolean doFlushBuffer() throws IOException { assert Thread.holdsLock(writeLock); final ByteBuffer buffer = transmitBuffer.getResource(); buffer.flip(); try { while (buffer.hasRemaining()) { final int res = channel.write(buffer); if (res == 0) { log.tracef("Did not fully flush %s", this); return false; } } log.tracef("Fully flushed %s", this); return true; } finally { buffer.compact(); } } private boolean doFlush() throws IOException { return doFlushBuffer() && channel.flush(); } protected void closeAction(final boolean readShutDown, final boolean writeShutDown) throws IOException { boolean error = false; if (! writeShutDown) { synchronized (writeLock) { try { if (! doFlush()) error = true; } catch (Throwable t) { error = true; } try { transmitBuffer.free(); } catch (Throwable t) { } } } if (! readShutDown) { synchronized (readLock) { try { receiveBuffer.free(); } catch (Throwable t) { } } } try { if (error) throw msg.unflushedData(); channel.close(); } finally { IoUtils.safeClose(channel); } } /** {@inheritDoc} */ public SocketAddress getPeerAddress() { return channel.getPeerAddress(); } /** {@inheritDoc} */ public A getPeerAddress(final Class type) { return channel.getPeerAddress(type); } /** {@inheritDoc} */ public SocketAddress getLocalAddress() { return channel.getLocalAddress(); } /** {@inheritDoc} */ public A getLocalAddress(final Class type) { return channel.getLocalAddress(type); } /** * Get the underlying channel. * * @return the underlying channel */ public ConnectedStreamChannel getChannel() { return channel; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/MessageChannel.java000066400000000000000000000010151257016060700260110ustar00rootroot00000000000000 package org.xnio.channels; import org.xnio.ChannelListener; /** * A channel that sends and receives whole messages. */ public interface MessageChannel extends ReadableMessageChannel, WritableMessageChannel, SuspendableChannel { /** {@inheritDoc} */ ChannelListener.Setter getReadSetter(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); /** {@inheritDoc} */ ChannelListener.Setter getWriteSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/MulticastMessageChannel.java000066400000000000000000000152471257016060700277130ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.net.InetAddress; import java.net.NetworkInterface; import java.io.IOException; import java.io.Closeable; import org.xnio.ChannelListener; /** * A multicast-capable point-to-multipoint channel. UDP channels are multipoint datagram channels which support multicast registration. * * @apiviz.landmark */ public interface MulticastMessageChannel extends BoundMultipointMessageChannel { /** * A registration key for a multicast group. * * @apiviz.exclude */ interface Key extends Closeable { /** * Block multicast packets from the given source address. * * If this membership key is not source-specific, and the implementation supports source filtering, * then this method blocks multicast packets from the given source addresses. After a source address is blocked * it may still be possible to receive datagrams from that source. This can arise when datagrams are waiting * to be received in the socket's receive buffer. * * @param source the source address to block * @return this key * @throws IOException if an I/O error occurs * @throws UnsupportedOperationException if the implementation does not support source filtering * @throws IllegalStateException if this key is source-specific or is no longer valid * @throws IllegalArgumentException if the {@code source} parameter is not a unicast address or is not the same address type as the multicast group */ Key block(InetAddress source) throws IOException, UnsupportedOperationException, IllegalStateException, IllegalArgumentException; /** * Unblock multicast packets from the given source address that was previously blocked using the {@link #block(InetAddress)} method. * * @param source the source address to unblock * @return this key * @throws IOException if an I/O error occurs * @throws IllegalStateException if the given source address is not currently blocked or the key is no longer valid * @throws UnsupportedOperationException if the implementation does not support source filtering */ Key unblock(InetAddress source) throws IOException, IllegalStateException, UnsupportedOperationException; /** * Return the channel associated with this key. This method will return the channel even after the membership * is dropped. * * @return the channel */ MulticastMessageChannel getChannel(); /** * Return the multicast group for which this key was created. This method will continue to return the group even * after the membership is dropped. * * @return the multicast group */ InetAddress getGroup(); /** * Return the network interface for which this key was created. This method will continue to return the network * interface even after the membership is dropped or the channel is closed. * * @return the network interface */ NetworkInterface getNetworkInterface(); /** * Return the source address if this membership key is source specific, or {@code null} if this membership is not * source specific. * * @return the source address */ InetAddress getSourceAddress(); /** * Determine if this membership is active. * * @return {@code true} if the membership is still active */ boolean isOpen(); } /** * Join a multicast group to begin receiving all datagrams sent to the group. * * A multicast channel may join several multicast groups, including the same group on more than one interface. An * implementation may impose a limit on the number of groups that may be joined at the same time. * * @param group the multicast address to join * @param iface the network interface to join on * @return a new key * @throws IOException if an I/O error occurs * @throws IllegalStateException if the channel is already a member of the group on this interface * @throws IllegalArgumentException if the {@code group} parameters is not a multicast address, or is an unsupported address type * @throws SecurityException if a security manager is set, and its {@link SecurityManager#checkMulticast(InetAddress)} method denies access to the group */ Key join(InetAddress group, NetworkInterface iface) throws IOException; /** * Join a multicast group to begin receiving all datagrams sent to the group from a given source address. * * A multicast channel may join several multicast groups, including the same group on more than one interface. An * implementation may impose a limit on the number of groups that may be joined at the same time. * * @param group the multicast address to join * @param iface the network interface to join on * @param source the source address to listen for * @return a new key * @throws IOException if an I/O error occurs * @throws IllegalStateException if the channel is already a member of the group on this interface * @throws IllegalArgumentException if the {@code group} parameters is not a multicast address, or is an unsupported address type * @throws SecurityException if a security manager is set, and its {@link SecurityManager#checkMulticast(InetAddress)} method denies access to the group * @throws UnsupportedOperationException if the implementation does not support source filtering */ Key join(InetAddress group, NetworkInterface iface, InetAddress source) throws IOException; /** {@inheritDoc} */ ChannelListener.Setter getReadSetter(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); /** {@inheritDoc} */ ChannelListener.Setter getWriteSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/MultipointMessageChannel.java000066400000000000000000000013611257016060700301020ustar00rootroot00000000000000 package org.xnio.channels; import org.xnio.ChannelListener; /** * A point-to-multipoint message channel. This type of channel is capable of sending to and receiving from multiple * peer endpoints; as such, the incoming and outgoing messages are each associated with a peer address. */ public interface MultipointMessageChannel extends ReadableMultipointMessageChannel, WritableMultipointMessageChannel, SuspendableChannel { /** {@inheritDoc} */ ChannelListener.Setter getReadSetter(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); /** {@inheritDoc} */ ChannelListener.Setter getWriteSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/NullStreamSinkChannel.java000066400000000000000000000202401257016060700273410ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.channels; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.Option; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import static org.xnio.Bits.*; /** * A bit-bucket stream sink channel. This channel type is always writable. * * @author David M. Lloyd */ public final class NullStreamSinkChannel implements StreamSinkChannel, WriteListenerSettable, CloseListenerSettable { private final XnioIoThread thread; @SuppressWarnings("unused") private volatile int state; private ChannelListener writeListener; private ChannelListener closeListener; private static final AtomicIntegerFieldUpdater stateUpdater = AtomicIntegerFieldUpdater.newUpdater(NullStreamSinkChannel.class, "state"); private static final int FLAG_ENTERED = 1 << 0; private static final int FLAG_CLOSED = 1 << 1; private static final int FLAG_RESUMED = 1 << 2; /** * Construct a new instance. * * @param thread the write thread for this channel */ public NullStreamSinkChannel(final XnioIoThread thread) { this.thread = thread; } public XnioWorker getWorker() { return thread.getWorker(); } public XnioIoThread getIoThread() { return thread; } @Deprecated public XnioExecutor getWriteThread() { return thread; } public long transferFrom(final FileChannel src, final long position, final long count) throws IOException { int val = enterWrite(); try { return Math.min(src.size() - position, count); } finally { exitWrite(val); } } public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { int val = enterWrite(); try { return Channels.drain(source, count); } finally { throughBuffer.limit(0); exitWrite(val); } } public void setWriteListener(final ChannelListener writeListener) { this.writeListener = writeListener; } public ChannelListener getWriteListener() { return writeListener; } public void setCloseListener(final ChannelListener closeListener) { this.closeListener = closeListener; } public ChannelListener getCloseListener() { return closeListener; } public ChannelListener.Setter getWriteSetter() { return new WriteListenerSettable.Setter(this); } public ChannelListener.Setter getCloseSetter() { return new CloseListenerSettable.Setter(this) ; } @Override public int writeFinal(ByteBuffer src) throws IOException { return Channels.writeFinalBasic(this, src); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { return Channels.writeFinalBasic(this, srcs, offset, length); } @Override public long writeFinal(ByteBuffer[] srcs) throws IOException { return Channels.writeFinalBasic(this, srcs, 0, srcs.length); } public int write(final ByteBuffer src) throws IOException { int val = enterWrite(); try { return src.remaining(); } finally { src.position(src.limit()); exitWrite(val); } } public long write(final ByteBuffer[] srcs) throws IOException { return write(srcs, 0, srcs.length); } public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException { if (length == 0) { return 0L; } int val = enterWrite(); try { long t = 0L; ByteBuffer src; for (int i = 0; i < length; i ++) { src = srcs[i]; t += src.remaining(); src.position(src.limit()); } return t; } finally { exitWrite(val); } } public void suspendWrites() { int oldVal, newVal; do { oldVal = state; if (allAreClear(oldVal, FLAG_RESUMED) || allAreSet(oldVal, FLAG_CLOSED)) { return; } newVal = oldVal & ~FLAG_RESUMED; } while (! stateUpdater.compareAndSet(this, oldVal, newVal)); } public void resumeWrites() { int oldVal, newVal; do { oldVal = state; if (anyAreSet(oldVal, FLAG_RESUMED | FLAG_CLOSED)) { return; } newVal = oldVal | FLAG_RESUMED; } while (! stateUpdater.compareAndSet(this, oldVal, newVal)); thread.execute(ChannelListeners.getChannelListenerTask(this, writeListener)); } public void wakeupWrites() { resumeWrites(); } public boolean isWriteResumed() { final int state = this.state; return allAreSet(state, FLAG_RESUMED) && allAreClear(state, FLAG_CLOSED); } public void shutdownWrites() throws IOException { int oldVal, newVal; do { oldVal = state; if (allAreSet(oldVal, FLAG_CLOSED)) { return; } newVal = oldVal | FLAG_CLOSED; } while (! stateUpdater.compareAndSet(this, oldVal, newVal)); writeListener = null; ChannelListeners.invokeChannelListener(this, closeListener); } public void awaitWritable() throws IOException { // always writable } public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException { // always writable } public boolean flush() throws IOException { return true; } public boolean isOpen() { return allAreClear(state, FLAG_CLOSED); } public void close() throws IOException { shutdownWrites(); } public boolean supportsOption(final Option option) { return false; } public T getOption(final Option option) throws IOException { return null; } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return null; } private int enterWrite() throws ClosedChannelException { int oldVal, newVal; do { oldVal = state; if (allAreSet(oldVal, FLAG_ENTERED)) { throw new ConcurrentStreamChannelAccessException(); } if (allAreSet(oldVal, FLAG_CLOSED)) { throw new ClosedChannelException(); } newVal = oldVal | FLAG_ENTERED; } while (! stateUpdater.compareAndSet(this, oldVal, newVal)); return newVal; } private void exitWrite(int oldVal) { int newVal = oldVal & ~FLAG_ENTERED; while (! stateUpdater.compareAndSet(this, oldVal, newVal)) { oldVal = state; newVal = oldVal & ~FLAG_ENTERED; } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/ProtectedWrappedChannel.java000066400000000000000000000023331257016060700277050ustar00rootroot00000000000000 /* * JBoss, Home of Professional Open Source * * Copyright 2012 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.nio.channels.Channel; /** * A protected, wrapped channel. A guard object is required to gain access to the underlying channel. * * @param the wrapped channel type * @author David M. Lloyd */ public interface ProtectedWrappedChannel { /** * Get the channel which is wrapped by this object, or {@code null} if the guard is invalid. * * @param guard the guard object * @return the wrapped channel */ C getChannel(Object guard); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/PushBackStreamChannel.java000066400000000000000000000343431257016060700273130ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import org.xnio.Buffers; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.Option; import org.xnio.Pooled; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; /** * A stream source channel which can have data pushed back into it. Note that waiting readers will NOT be interrupted * when data is pushed back; therefore data should only be pushed back at points when no waiters are expected to exist. * * @author David M. Lloyd */ public final class PushBackStreamChannel implements StreamSourceChannel, WrappedChannel { private final StreamSourceChannel firstChannel; private StreamSourceChannel channel; private ChannelListener readListener; private ChannelListener closeListener; /** * Construct a new instance. * * @param channel the channel to wrap */ public PushBackStreamChannel(final StreamSourceChannel channel) { this.channel = firstChannel = channel; firstChannel.getReadSetter().set(new ChannelListener() { public void handleEvent(final StreamSourceChannel channel) { ChannelListeners.invokeChannelListener(PushBackStreamChannel.this, readListener); } }); firstChannel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamSourceChannel channel) { ChannelListeners.invokeChannelListener(PushBackStreamChannel.this, closeListener); } }); } public void setReadListener(final ChannelListener readListener) { this.readListener = readListener; } public void setCloseListener(final ChannelListener closeListener) { this.closeListener = closeListener; } public ChannelListener.Setter getReadSetter() { return new ChannelListener.Setter() { public void set(final ChannelListener listener) { setReadListener(listener); } }; } public ChannelListener.Setter getCloseSetter() { return new ChannelListener.Setter() { public void set(final ChannelListener listener) { setCloseListener(listener); } }; } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { final StreamSourceChannel channel = this.channel; if (channel == null) { return 0; } return channel.transferTo(position, count, target); } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { final StreamSourceChannel channel = this.channel; if (channel == null) { return -1L; } return channel.transferTo(count, throughBuffer, target); } public int read(final ByteBuffer dst) throws IOException { final StreamSourceChannel channel = this.channel; if (channel == null) { return -1; } return channel.read(dst); } public long read(final ByteBuffer[] dsts) throws IOException { final StreamSourceChannel channel = this.channel; if (channel == null) { return -1L; } return channel.read(dsts); } public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { final StreamSourceChannel channel = this.channel; if (channel == null) { return -1L; } return channel.read(dsts, offset, length); } /** * Re-queue the given pooled buffer into this channel. This method transfers ownership of the given buffer * to this channel. The buffer should be flipped for emptying. * * @param buffer the buffer to re-queue */ public void unget(Pooled buffer) { StreamSourceChannel old; old = channel; if (old == null) { buffer.free(); return; } channel = new BufferHolder(old, buffer); } public void suspendReads() { firstChannel.suspendReads(); } public void resumeReads() { final StreamSourceChannel channel = this.channel; if (channel != null) { channel.resumeReads(); } } public boolean isReadResumed() { return firstChannel.isReadResumed(); } public void wakeupReads() { firstChannel.wakeupReads(); } public void shutdownReads() throws IOException { final StreamSourceChannel old = channel; if (old != null) { channel = null; old.shutdownReads(); } } public void awaitReadable() throws IOException { final StreamSourceChannel channel = this.channel; if (channel != null) { channel.awaitReadable(); } } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { final StreamSourceChannel channel = this.channel; if (channel != null) { channel.awaitReadable(time, timeUnit); } } @Deprecated public XnioExecutor getReadThread() { return firstChannel.getReadThread(); } public XnioIoThread getIoThread() { return firstChannel.getIoThread(); } public XnioWorker getWorker() { return firstChannel.getWorker(); } public boolean isOpen() { return firstChannel.isOpen(); } public void close() throws IOException { final StreamSourceChannel old = channel; if (old != null) { channel = null; old.close(); } } public boolean supportsOption(final Option option) { return firstChannel.supportsOption(option); } public T getOption(final Option option) throws IOException { return firstChannel.getOption(option); } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return firstChannel.setOption(option, value); } public StreamSourceChannel getChannel() { return firstChannel; } class BufferHolder implements StreamSourceChannel { private final StreamSourceChannel next; private final Pooled buffer; BufferHolder(final StreamSourceChannel next, final Pooled buffer) { this.next = next; this.buffer = buffer; } public long transferTo(long position, long count, FileChannel target) throws IOException { long cnt; final ByteBuffer src; try { src = buffer.getResource(); final int pos = src.position(); final int rem = src.remaining(); if (rem > count) try { // partial empty of our buffer src.limit(pos + (int) count); return target.write(src, position); } finally { src.limit(pos + rem); } else { // full empty of our buffer cnt = target.write(src, position); if (cnt == rem) { // we emptied our buffer channel = next; buffer.free(); } else { return cnt; } position += cnt; count -= cnt; } } catch (IllegalStateException ignored) { channel = next; cnt = 0L; } return cnt + next.transferTo(position, count, target); } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { long cnt; throughBuffer.clear(); final ByteBuffer src; try { src = buffer.getResource(); final int pos = src.position(); final int rem = src.remaining(); if (rem > count) try { // partial empty of our buffer src.limit(pos + (int) count); throughBuffer.limit(0); return target.write(src); } finally { src.limit(pos + rem); } else { // full empty of our buffer cnt = target.write(src); if (cnt == rem) { // we emptied our buffer channel = next; buffer.free(); } else { return cnt; } } } catch (IllegalStateException ignored) { channel = next; cnt = 0L; } final long res = next.transferTo(count - cnt, throughBuffer, target); return res > 0L ? cnt + res : cnt > 0L ? cnt : res; } public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { long cnt; try { final ByteBuffer src = buffer.getResource(); cnt = Buffers.copy(dsts, offset, length, src); if (src.hasRemaining()) { return cnt; } final StreamSourceChannel next = channel = this.next; buffer.free(); if (cnt > 0L && next == firstChannel) { // don't hit the main channel until the user wants to return cnt; } } catch (IllegalStateException ignored) { channel = next; cnt = 0; } final long res = next.read(dsts, offset, length); return res > 0 ? res + cnt : cnt > 0 ? cnt : res; } public long read(final ByteBuffer[] dsts) throws IOException { return read(dsts, 0, dsts.length); } public int read(final ByteBuffer dst) throws IOException { int cnt; if (! dst.hasRemaining()) { return 0; } try { final ByteBuffer src = buffer.getResource(); cnt = Buffers.copy(dst, src); if (src.hasRemaining()) { return cnt; } final StreamSourceChannel next = channel = this.next; buffer.free(); if (cnt > 0 && next == firstChannel) { // don't hit the main channel until the user wants to return cnt; } } catch (IllegalStateException ignored) { channel = next; cnt = 0; } final int res = next.read(dst); return res > 0 ? res + cnt : cnt > 0 ? cnt : res; } public void close() throws IOException { buffer.free(); next.close(); } public void resumeReads() { // reads are always ready in this case firstChannel.wakeupReads(); } public void shutdownReads() throws IOException { buffer.free(); next.shutdownReads(); } public void awaitReadable() throws IOException { // return immediately } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { // return immediately } // unused methods public boolean isOpen() { throw new UnsupportedOperationException(); } public ChannelListener.Setter getReadSetter() { throw new UnsupportedOperationException(); } public ChannelListener.Setter getCloseSetter() { throw new UnsupportedOperationException(); } public void suspendReads() { throw new UnsupportedOperationException(); } public boolean isReadResumed() { throw new UnsupportedOperationException(); } public void wakeupReads() { throw new UnsupportedOperationException(); } @Deprecated public XnioExecutor getReadThread() { throw new UnsupportedOperationException(); } public XnioIoThread getIoThread() { throw new UnsupportedOperationException(); } public XnioWorker getWorker() { throw new UnsupportedOperationException(); } public boolean supportsOption(final Option option) { throw new UnsupportedOperationException(); } public T getOption(final Option option) throws IOException { throw new UnsupportedOperationException(); } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { throw new UnsupportedOperationException(); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/ReadListenerSettable.java000066400000000000000000000036421257016060700272110ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.nio.channels.Channel; import org.xnio.ChannelListener; /** * An object which supports directly setting the read listener may implement this interface. * * @author David M. Lloyd */ public interface ReadListenerSettable { /** * Set the read listener. * * @param listener the read listener */ void setReadListener(ChannelListener listener); /** * Get the read listener. * * @return the read listener */ ChannelListener getReadListener(); /** * A channel listener setter implementation which delegates to the appropriate setter method. * * @param the channel type */ class Setter implements ChannelListener.Setter { private final ReadListenerSettable settable; /** * Construct a new instance. * * @param settable the settable to delegate to */ public Setter(final ReadListenerSettable settable) { this.settable = settable; } public void set(final ChannelListener listener) { settable.setReadListener(listener); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/ReadTimeoutException.java000066400000000000000000000045241257016060700272450ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2010 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.io.InterruptedIOException; /** * Thrown when a blocking read operation times out. */ public class ReadTimeoutException extends InterruptedIOException { private static final long serialVersionUID = 2058056832934733469L; /** * Constructs a {@code ReadTimeoutException} with no detail message. The cause is not initialized, and may subsequently * be initialized by a call to {@link #initCause(Throwable) initCause}. */ public ReadTimeoutException() { } /** * Constructs a {@code ReadTimeoutException} with the specified detail message. The cause is not initialized, and may * subsequently be initialized by a call to {@link #initCause(Throwable) initCause}. * * @param msg the detail message */ public ReadTimeoutException(final String msg) { super(msg); } /** * Constructs a {@code ReadTimeoutException} with the specified cause. The detail message is set to: *
(cause == null ? null : cause.toString())
* (which typically contains the class and detail message of {@code cause}). * * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) */ public ReadTimeoutException(final Throwable cause) { initCause(cause); } /** * Constructs a {@code ReadTimeoutException} with the specified detail message and cause. * * @param msg the detail message * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) */ public ReadTimeoutException(final String msg, final Throwable cause) { super(msg); initCause(cause); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/ReadableMessageChannel.java000066400000000000000000000045711257016060700274430ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.io.IOException; import java.nio.ByteBuffer; import org.xnio.ChannelListener; /** * A channel that can receive messages. Such a channel receives whole messages only. */ public interface ReadableMessageChannel extends SuspendableReadChannel, Configurable { /** * Receive a message. * * @param buffer the buffer that will hold the message * @return the size of the received message, 0 if no message is available, and -1 if the message channel has reached an end-of-file condition * @throws IOException if an I/O error occurs */ int receive(ByteBuffer buffer) throws IOException; /** * Receive a message. * * @param buffers the buffers that will hold the message * @return the size of the received message, 0 if no message is available, and -1 if the message channel has reached an end-of-file condition * @throws IOException if an I/O error occurs */ long receive(ByteBuffer[] buffers) throws IOException; /** * Receive a message. * * @param buffers the buffers that will hold the message * @param offs the offset into the array of buffers of the first buffer to read into * @param len the number of buffers to fill * @return the size of the received message, 0 if no message is available, and -1 if the message channel has reached an end-of-file condition * @throws IOException if an I/O error occurs */ long receive(ByteBuffer[] buffers, int offs, int len) throws IOException; /** {@inheritDoc} */ ChannelListener.Setter getReadSetter(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/ReadableMultipointMessageChannel.java000066400000000000000000000074701257016060700315310ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.nio.ByteBuffer; import java.io.IOException; import org.xnio.ChannelListener; /** * The readable side of a multipoint message channel. */ public interface ReadableMultipointMessageChannel extends SuspendableReadChannel { /** * Receive a message via this channel. * * If a message is immediately available, then the datagram is written into the given buffer and the source * and destination addresses (if available) read into the address buffer. If there is no message immediately available, * this method will return 0. * * @param addressBuffer the address buffer into which the source and destination addresses should be written ({@code null} to discard that information) * @param buffer the buffer into which data should be read * @return the size of the received message, 0 if no message is available, and -1 if the message channel has reached an end-of-file condition * @throws IOException if an I/O error occurs */ int receiveFrom(SocketAddressBuffer addressBuffer, ByteBuffer buffer) throws IOException; /** * Receive a message. * * If a message is immediately available, then the datagram is written into the given buffers in a "scatter" fashion and the source * and destination addresses (if available) read into the address buffer. If there is no message immediately available, * this method will return 0. * * @param addressBuffer the address buffer into which the source and destination addresses should be written ({@code null} to discard that information) * @param buffers the buffers that will hold the message * @return the size of the received message, 0 if no message is available, and -1 if the message channel has reached an end-of-file condition * @throws IOException if an I/O error occurs */ long receiveFrom(SocketAddressBuffer addressBuffer, ByteBuffer[] buffers) throws IOException; /** * Receive a message. * * If a message is immediately available, then the datagram is written into the given buffers in a "scatter" fashion and the source * and destination addresses (if available) read into the address buffer. If there is no message immediately available, * this method will return 0. * * @param addressBuffer the address buffer into which the source and destination addresses should be written ({@code null} to discard that information) * @param buffers the buffers that will hold the message * @param offs the offset into the array of buffers of the first buffer to read into * @param len the number of buffers to fill * @return the size of the received message, 0 if no message is available, and -1 if the message channel has reached an end-of-file condition * @throws IOException if an I/O error occurs */ long receiveFrom(SocketAddressBuffer addressBuffer, ByteBuffer[] buffers, int offs, int len) throws IOException; /** {@inheritDoc} */ ChannelListener.Setter getReadSetter(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/SimpleAcceptingChannel.java000066400000000000000000000027621257016060700275060ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import java.io.IOException; import org.xnio.ChannelListener; /** * A channel which can accept connections. * * @param the channel type * * @author David M. Lloyd */ public interface SimpleAcceptingChannel extends SuspendableAcceptChannel { /** * Attempt to accept a connection. * * @return the new connection, or {@code null} if none is available * @throws IOException if an I/O error occurs */ C accept() throws IOException; /** {@inheritDoc} */ ChannelListener.Setter> getAcceptSetter(); /** {@inheritDoc} */ ChannelListener.Setter> getCloseSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/SocketAddressBuffer.java000066400000000000000000000055441257016060700270370ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2010 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import java.net.SocketAddress; /** * A buffer for source and destination addresses. * * @author David M. Lloyd */ public final class SocketAddressBuffer { private SocketAddress sourceAddress; private SocketAddress destinationAddress; /** * Construct a new instance. */ public SocketAddressBuffer() { } /** * Get the source address. * * @return the source address, or {@code null} if not set */ public SocketAddress getSourceAddress() { return sourceAddress; } /** * Get the source address. * * @param type the address type to get * @return the source address, or {@code null} if not set */ public A getSourceAddress(Class type) { return type.isInstance(sourceAddress) ? type.cast(sourceAddress) : null; } /** * Set the source address. * * @param sourceAddress the source address, or {@code null} to clear */ public void setSourceAddress(final SocketAddress sourceAddress) { this.sourceAddress = sourceAddress; } /** * Get the destination address. * * @return the destination address, or {@code null} if not set */ public SocketAddress getDestinationAddress() { return destinationAddress; } /** * Get the destination address. * * @param type the address type to get * @return the destination address, or {@code null} if not set */ public A getDestinationAddress(Class type) { return type.isInstance(destinationAddress) ? type.cast(destinationAddress) : null; } /** * Set the destination address. * * @param destinationAddress the destination address, or {@code null} to clear */ public void setDestinationAddress(final SocketAddress destinationAddress) { this.destinationAddress = destinationAddress; } /** * Clear both addresses in the buffer. */ public void clear() { sourceAddress = null; destinationAddress = null; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/SplitStreamSinkChannel.java000066400000000000000000000166551257016060700275410ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2012 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import org.xnio.ChannelListener; import org.xnio.Option; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import static org.xnio.Bits.*; import static org.xnio.ChannelListeners.invokeChannelListener; /** * A half-duplex (write side) wrapper for a full-duplex channel. * * @author David M. Lloyd */ public final class SplitStreamSinkChannel implements StreamSinkChannel, WriteListenerSettable, CloseListenerSettable { private final StreamSinkChannel delegate; private volatile int state; private ChannelListener writeListener; private ChannelListener closeListener; private static final int FLAG_DELEGATE_CONFIG = 1 << 0; private static final int FLAG_CLOSE_REQ = 1 << 1; private static final int FLAG_CLOSE_COMP = 1 << 2; private static final AtomicIntegerFieldUpdater stateUpdater = AtomicIntegerFieldUpdater.newUpdater(SplitStreamSinkChannel.class, "state"); /** * Construct a new instance. * * @param delegate the delegate channel * @param delegateConfig {@code true} to delegate configuration, {@code false} otherwise */ public SplitStreamSinkChannel(final StreamSinkChannel delegate, boolean delegateConfig) { this.delegate = delegate; state = delegateConfig ? FLAG_DELEGATE_CONFIG : 0; delegate.getWriteSetter().set(new ChannelListener() { public void handleEvent(final StreamSinkChannel channel) { invokeChannelListener(SplitStreamSinkChannel.this, writeListener); } }); } /** * Construct a new instance which does not delegate configuration. * * @param delegate the delegate channel */ public SplitStreamSinkChannel(final StreamSinkChannel delegate) { this(delegate, false); } public void setWriteListener(final ChannelListener writeListener) { this.writeListener = writeListener; } public ChannelListener getWriteListener() { return writeListener; } public void setCloseListener(final ChannelListener closeListener) { this.closeListener = closeListener; } public ChannelListener getCloseListener() { return closeListener; } public ChannelListener.Setter getCloseSetter() { return new CloseListenerSettable.Setter(this); } @Override public int writeFinal(ByteBuffer src) throws IOException { return delegate.writeFinal(src); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { return delegate.writeFinal(srcs, offset, length); } @Override public long writeFinal(ByteBuffer[] srcs) throws IOException { return delegate.writeFinal(srcs); } public ChannelListener.Setter getWriteSetter() { return new WriteListenerSettable.Setter(this); } public void shutdownWrites() throws IOException { int oldVal, newVal; do { oldVal = state; if (allAreSet(oldVal, FLAG_CLOSE_REQ)) { return; } newVal = oldVal | FLAG_CLOSE_REQ; } while (! stateUpdater.compareAndSet(this, oldVal, newVal)); delegate.shutdownWrites(); } public boolean isOpen() { return allAreClear(state, FLAG_CLOSE_REQ); } public void close() throws IOException { shutdownWrites(); // best lame-duck effort; can't do any more than this really flush(); } public boolean flush() throws IOException { int oldVal, newVal; oldVal = state; if (allAreSet(oldVal, FLAG_CLOSE_COMP)) { return true; } final boolean flushed = delegate.flush(); if (! flushed) { return false; } do { if (allAreClear(oldVal, FLAG_CLOSE_REQ)) { return true; } newVal = oldVal | FLAG_CLOSE_COMP; } while (! stateUpdater.compareAndSet(this, oldVal, newVal)); invokeChannelListener(this, closeListener); return true; } public long transferFrom(final FileChannel src, final long position, final long count) throws IOException { return delegate.transferFrom(src, position, count); } public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { return delegate.transferFrom(source, count, throughBuffer); } public int write(final ByteBuffer src) throws IOException { return delegate.write(src); } public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException { return delegate.write(srcs, offset, length); } public long write(final ByteBuffer[] srcs) throws IOException { return delegate.write(srcs); } public void suspendWrites() { delegate.suspendWrites(); } public void resumeWrites() { delegate.resumeWrites(); } public boolean isWriteResumed() { return delegate.isWriteResumed(); } public void wakeupWrites() { delegate.wakeupWrites(); } public void awaitWritable() throws IOException { delegate.awaitWritable(); } public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException { delegate.awaitWritable(time, timeUnit); } @Deprecated public XnioExecutor getWriteThread() { return delegate.getWriteThread(); } public XnioIoThread getIoThread() { return delegate.getIoThread(); } public XnioWorker getWorker() { return delegate.getWorker(); } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return allAreSet(state, FLAG_DELEGATE_CONFIG) ? delegate.setOption(option, value) : null; } public T getOption(final Option option) throws IOException { return allAreSet(state, FLAG_DELEGATE_CONFIG) ? delegate.getOption(option) : null; } public boolean supportsOption(final Option option) { return allAreSet(state, FLAG_DELEGATE_CONFIG) ? delegate.supportsOption(option) : false; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/SplitStreamSourceChannel.java000066400000000000000000000145161257016060700300670ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2012 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import org.xnio.ChannelListener; import org.xnio.Option; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import static org.xnio.Bits.*; import static org.xnio.ChannelListeners.invokeChannelListener; /** * A half-duplex (read side) wrapper for a full-duplex channel. * * @author David M. Lloyd */ public final class SplitStreamSourceChannel implements StreamSourceChannel, ReadListenerSettable, CloseListenerSettable { private final StreamSourceChannel delegate; private volatile int state; private ChannelListener readListener; private ChannelListener closeListener; private static final int FLAG_DELEGATE_CONFIG = 1 << 0; private static final int FLAG_CLOSED = 1 << 1; private static final AtomicIntegerFieldUpdater stateUpdater = AtomicIntegerFieldUpdater.newUpdater(SplitStreamSourceChannel.class, "state"); /** * Construct a new instance. * * @param delegate the delegate channel * @param delegateConfig {@code true} to delegate configuration, {@code false} otherwise */ public SplitStreamSourceChannel(final StreamSourceChannel delegate, boolean delegateConfig) { this.delegate = delegate; delegate.getReadSetter().set(new ChannelListener() { public void handleEvent(final StreamSourceChannel channel) { invokeChannelListener(SplitStreamSourceChannel.this, readListener); } }); state = delegateConfig ? FLAG_DELEGATE_CONFIG : 0; } /** * Construct a new instance which doesn't delegate configuration. * * @param delegate the delegate channel */ public SplitStreamSourceChannel(final StreamSourceChannel delegate) { this(delegate, false); } public void setReadListener(final ChannelListener readListener) { this.readListener = readListener; } public ChannelListener getReadListener() { return readListener; } public void setCloseListener(final ChannelListener closeListener) { this.closeListener = closeListener; } public ChannelListener getCloseListener() { return closeListener; } public ChannelListener.Setter getReadSetter() { return new ReadListenerSettable.Setter(this); } public ChannelListener.Setter getCloseSetter() { return new CloseListenerSettable.Setter(this); } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { return delegate.transferTo(position, count, target); } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { return delegate.transferTo(count, throughBuffer, target); } public int read(final ByteBuffer dst) throws IOException { return delegate.read(dst); } public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { return delegate.read(dsts, offset, length); } public long read(final ByteBuffer[] dsts) throws IOException { return delegate.read(dsts); } public void suspendReads() { delegate.suspendReads(); } public void resumeReads() { delegate.resumeReads(); } public void wakeupReads() { delegate.wakeupReads(); } public boolean isReadResumed() { return delegate.isReadResumed(); } public void awaitReadable() throws IOException { delegate.awaitReadable(); } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { delegate.awaitReadable(time, timeUnit); } public XnioWorker getWorker() { return delegate.getWorker(); } public boolean supportsOption(final Option option) { return allAreSet(state, FLAG_DELEGATE_CONFIG) ? delegate.supportsOption(option) : false; } public T getOption(final Option option) throws IOException { return allAreSet(state, FLAG_DELEGATE_CONFIG) ? delegate.getOption(option) : null; } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return allAreSet(state, FLAG_DELEGATE_CONFIG) ? delegate.setOption(option, value) : null; } public void shutdownReads() throws IOException { int oldVal, newVal; do { oldVal = state; if (allAreSet(oldVal, FLAG_CLOSED)) { return; } newVal = oldVal | FLAG_CLOSED; } while (! stateUpdater.compareAndSet(this, oldVal, newVal)); delegate.shutdownReads(); invokeChannelListener(this, closeListener); } @Deprecated public XnioExecutor getReadThread() { return delegate.getReadThread(); } public XnioIoThread getIoThread() { return delegate.getIoThread(); } public boolean isOpen() { return allAreClear(state, FLAG_CLOSED); } public void close() throws IOException { shutdownReads(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/SslChannel.java000066400000000000000000000034351257016060700251760ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2009 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.io.IOException; import javax.net.ssl.SSLSession; import org.xnio.ChannelListener; /** * A channel which can use SSL/TLS to negotiate a security layer. */ public interface SslChannel extends ConnectedChannel { /** * Start or restart the SSL/TLS handshake. To force a complete SSL/TLS session renegotiation, the current * session should be invalidated prior to calling this method. This method is not needed for the initial handshake * as sending or receiving over the channel will automatically initiate it. * * @throws IOException if an I/O error occurs */ void startHandshake() throws IOException; /** * Get the current {@code SSLSession} for this channel. * * @return the current {@code SSLSession} */ SSLSession getSslSession(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); /** * Get the setter which can be used to change the handshake listener for this channel. * * @return the setter */ ChannelListener.Setter getHandshakeSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/StreamChannel.java000066400000000000000000000011231257016060700256600ustar00rootroot00000000000000 package org.xnio.channels; import org.xnio.ChannelListener; /** * A stream channel. This type of channel represents a stream of bytes flowing in two directions. * * @apiviz.landmark */ public interface StreamChannel extends SuspendableChannel, StreamSinkChannel, StreamSourceChannel, ByteChannel { /** {@inheritDoc} */ ChannelListener.Setter getReadSetter(); /** {@inheritDoc} */ ChannelListener.Setter getWriteSetter(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/StreamSinkChannel.java000066400000000000000000000147171257016060700265220ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; import java.nio.channels.GatheringByteChannel; import java.nio.channels.FileChannel; import java.io.IOException; import org.xnio.ChannelListener; /** * A stream sink channel. This type of channel is a writable destination for bytes. While all channel types are * thread-safe, writing a stream from more than one thread concurrently will cause data corruption and may be * disallowed at the option of the implementation. */ public interface StreamSinkChannel extends WritableByteChannel, GatheringByteChannel, SuspendableWriteChannel { /** * Transfer bytes into this channel from the given file. Using this method in preference to {@link FileChannel#transferTo(long, long, WritableByteChannel)} * may provide a performance advantage on some platforms. *

* If the current thread is interrupted when this method is called, it may throw a {@link java.io.InterruptedIOException}; * however, if this exception is thrown, the {@link java.io.InterruptedIOException#bytesTransferred} field is * guaranteed to be 0. * * @param src the file to read from * @param position the position within the file from which the transfer is to begin * @param count the number of bytes to be transferred * @return the number of bytes (possibly 0) that were actually transferred * @throws IOException if an I/O error occurs */ long transferFrom(FileChannel src, long position, long count) throws IOException; /** * Transfers bytes from the given channel source. On some platforms, this may avoid copying bytes between user * and kernel space. On other platforms, bytes are passed through the {@code throughBuffer} parameter's buffer * space. On entry, {@code throughBuffer} will be cleared. On exit, the buffer will be * flipped for emptying, and may be empty or may contain data. If this method returns a value less than * {@code count}, then the remaining data in {@code throughBuffer} may contain data read from {@code source} which must * be written to this channel to complete the operation. Note that using a direct buffer may provide an * intermediate performance gain on platforms without zero-copy facilities. *

* If the current thread is interrupted when this method is called, it may throw a {@link java.io.InterruptedIOException}; * however, if this exception is thrown, the {@link java.io.InterruptedIOException#bytesTransferred} field is * guaranteed to be 0. * * @param source the source to read from * @param count the number of bytes to be transferred * @param throughBuffer the buffer to copy through. * @return the number of bytes (possibly 0) that were actually transferred, or -1 if the end of input was reached * @throws IOException if an I/O error occurs */ long transferFrom(StreamSourceChannel source, long count, ByteBuffer throughBuffer) throws IOException; /** {@inheritDoc} */ ChannelListener.Setter getWriteSetter(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); /** * * Writes some data to the channel, with the same semantics as * {@link #write(java.nio.ByteBuffer)}. If all the data is written * out then the channel will have its writes shutdown. Semantically this * method is equivalent to: * * int rem = src.remaining(); * int written = channel.write(src); * if(written == rem) { * channel.shutdownWrites() * } * * * If an exception is thrown the caller is still responsible for closing the channel. * * @see WritableByteChannel#write(java.nio.ByteBuffer) * @see SuspendableWriteChannel#shutdownWrites() * @param src The data to write * @return The amount of data that was actually written. */ public int writeFinal(ByteBuffer src) throws IOException; /** * * Writes some data to the channel, with the same semantics as * {@link #write(java.nio.ByteBuffer[], int, int)}. If all the data is written * out then the channel will have its writes shutdown. * * If an exception is thrown the caller is still responsible for closing the channel. * * @see GatheringByteChannel#write(java.nio.ByteBuffer[], int, int) * * @see SuspendableWriteChannel#shutdownWrites() * * @param srcs * The buffers from which bytes are to be retrieved * * @param offset * The offset within the buffer array of the first buffer from * which bytes are to be retrieved; must be non-negative and no * larger than srcs.length * * @param length * The maximum number of buffers to be accessed; must be * non-negative and no larger than * srcs.length - offset * * @return The amount of data that was actually written */ public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException; /** * * Writes some data to the channel, with the same semantics as * {@link #write(java.nio.ByteBuffer[])}. If all the data is written * out then the channel will have its writes shutdown. * * If an exception is thrown the caller is still responsible for closing the channel. * * @see GatheringByteChannel#write(java.nio.ByteBuffer[]) * * @see SuspendableWriteChannel#shutdownWrites() * * @param srcs * The buffers from which bytes are to be retrieved * * @return The amount of data that was actually written */ public long writeFinal(ByteBuffer[] srcs) throws IOException; } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/StreamSourceChannel.java000066400000000000000000000102271257016060700270460ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.nio.ByteBuffer; import java.nio.channels.ScatteringByteChannel; import java.nio.channels.ReadableByteChannel; import java.nio.channels.FileChannel; import java.io.IOException; import org.xnio.ChannelListener; /** * A stream source channel. This type of channel is a readable source for bytes. While all channel types are * thread-safe, reading a stream from more than one thread concurrently will cause data corruption and may be * disallowed at the option of the implementation. */ public interface StreamSourceChannel extends ReadableByteChannel, ScatteringByteChannel, SuspendableReadChannel { /** * Transfers bytes into the given file from this channel. Using this method in preference to {@link FileChannel#transferFrom(ReadableByteChannel, long, long)} * may provide a performance advantage on some platforms. *

* If the current thread is interrupted when this method is called, it may throw a {@link java.io.InterruptedIOException}; * however, if this exception is thrown, the {@link java.io.InterruptedIOException#bytesTransferred} field is * guaranteed to be 0. * * @param position the position within the file from which the transfer is to begin * @param count the number of bytes to be transferred * @param target the file to write to * @return the number of bytes (possibly 0) that were actually transferred * @throws IOException if an I/O error occurs */ long transferTo(long position, long count, FileChannel target) throws IOException; /** * Transfers bytes into the given channel target. On some platforms, this may avoid copying bytes between user * and kernel space. On other platforms, bytes are passed through the {@code throughBuffer} parameter's buffer * space. On entry, {@code throughBuffer} will be cleared. On exit, the buffer will be * flipped for emptying, and may possibly be empty or may contain data. If this method returns a value less than * {@code count}, then the remaining data in {@code throughBuffer} may contain data read from this channel which must * be written to {@code target} to complete the operation. Note that using a direct buffer may provide an * intermediate performance gain on platforms without zero-copy facilities. *

* If the current thread is interrupted when this method is called, it may throw a {@link java.io.InterruptedIOException}; * however, if this exception is thrown, the {@link java.io.InterruptedIOException#bytesTransferred} field is * guaranteed to be 0. * * Note that the return value is the amount of data that was actually transferred to the {@link StreamSinkChannel}. * The actual amount of data read could be larger than this, and can be calculated by adding the return value and * the amount of data left in {@code throughBuffer}. * * @param count the number of bytes to be transferred * @param throughBuffer the buffer to copy through. * @param target the destination to write to * @return the number of bytes (possibly 0) that were actually transferred, or -1 if the end of input was reached * @throws IOException if an I/O error occurs */ long transferTo(long count, ByteBuffer throughBuffer, StreamSinkChannel target) throws IOException; /** {@inheritDoc} */ ChannelListener.Setter getReadSetter(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/SuspendableAcceptChannel.java000066400000000000000000000071451257016060700300240ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2010 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.io.IOException; import java.io.InterruptedIOException; import java.util.concurrent.TimeUnit; import org.xnio.ChannelListener; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; /** * A suspendable accept channel. This type of channel is associated with a listener which can suspend and resume * accepting connections as needed. * * @since 3.0 */ public interface SuspendableAcceptChannel extends CloseableChannel { /** * Suspend further read notifications on this channel. */ void suspendAccepts(); /** * Resume reads on this channel. The accept listener will be * called as soon as there is a connection available to be accepted. */ void resumeAccepts(); /** * Determine whether accepts are resumed. * * @return {@code true} if accepts are resumed, {@code false} if accepts are suspended */ boolean isAcceptResumed(); /** * {@link #resumeAccepts()} Resume accepts} on this channel, and force the accept listener to be triggered even if the * channel isn't actually ready. * * @deprecated Users should instead submit {@code Runnable} tasks to the channel thread when this functionality is needed. */ @Deprecated void wakeupAccepts(); /** * Block until this channel becomes acceptable again. This method may return spuriously * before the channel becomes acceptable. * * @throws InterruptedIOException if the operation is interrupted; the thread's interrupt flag will be set as well * @throws IOException if an I/O error occurs */ void awaitAcceptable() throws IOException; /** * Block until this channel becomes acceptable again, or until the timeout expires. This method may return spuriously * before the channel becomes acceptable or the timeout expires. * * @param time the time to wait * @param timeUnit the time unit * @throws InterruptedIOException if the operation is interrupted; the thread's interrupt flag will be set as well * @throws IOException if an I/O error occurs */ void awaitAcceptable(long time, TimeUnit timeUnit) throws IOException; /** * Get an accept thread for this channel. If more than one is configured, any of them may be returned. * * @return the thread * @deprecated The {@link #getIoThread()} method should be used instead. */ @Deprecated XnioExecutor getAcceptThread(); /** * Get an accept thread for this channel. If more than one is configured, any of them may be returned. * * @return the thread */ XnioIoThread getIoThread(); /** * Get the setter which can be used to change the accept listener for this channel. * * @return the setter */ ChannelListener.Setter getAcceptSetter(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/SuspendableChannel.java000066400000000000000000000010171257016060700266740ustar00rootroot00000000000000 package org.xnio.channels; import org.xnio.ChannelListener; /** * A suspendable bidirectional channel. */ public interface SuspendableChannel extends CloseableChannel, SuspendableReadChannel, SuspendableWriteChannel { /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); /** {@inheritDoc} */ ChannelListener.Setter getReadSetter(); /** {@inheritDoc} */ ChannelListener.Setter getWriteSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/SuspendableReadChannel.java000066400000000000000000000072551257016060700275020ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.io.IOException; import java.io.InterruptedIOException; import java.util.concurrent.TimeUnit; import org.xnio.ChannelListener; import org.xnio.XnioExecutor; /** * A suspendable readable channel. This type of channel is associated with a listener which can suspend and resume * reads as needed. */ public interface SuspendableReadChannel extends CloseableChannel { /** * Suspend further read notifications on this channel. */ void suspendReads(); /** * Resume reads on this channel. The read listener will be * called as soon as there is data available to be read. */ void resumeReads(); /** * Determine whether reads are resumed. * * @return {@code true} if reads are resumed, {@code false} if reads are suspended */ boolean isReadResumed(); /** * {@link #resumeReads() Resume reads} on this channel, and force the read listener to be triggered even if the * channel isn't actually readable. * * @deprecated Users should instead submit {@code Runnable} tasks to the channel thread when this functionality is needed. */ @Deprecated void wakeupReads(); /** * Places this readable channel at "end of stream". Further reads will result in EOF. * Shutting down all directions of a channel will cause {@link #close()} to be called automatically. * * @throws IOException if an I/O error occurs */ void shutdownReads() throws IOException; /** * Block until this channel becomes readable again. This method may return spuriously * before the channel becomes readable. * * @throws InterruptedIOException if the operation is interrupted; the thread's interrupt flag will be set as well * @throws IOException if an I/O error occurs * * @since 1.2 */ void awaitReadable() throws IOException; /** * Block until this channel becomes readable again, or until the timeout expires. This method may return spuriously * before the channel becomes readable or the timeout expires. * * @param time the time to wait * @param timeUnit the time unit * @throws InterruptedIOException if the operation is interrupted; the thread's interrupt flag will be set as well * @throws IOException if an I/O error occurs * * @since 1.2 */ void awaitReadable(long time, TimeUnit timeUnit) throws IOException; /** * Get the read thread for this channel. * * @return the thread, or {@code null} if none is configured or available * @deprecated The {@link #getIoThread()} method should be used instead. */ @Deprecated XnioExecutor getReadThread(); /** * Get the setter which can be used to change the read listener for this channel. * * @return the setter * * @since 2.0 */ ChannelListener.Setter getReadSetter(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/SuspendableWriteChannel.java000066400000000000000000000127061257016060700277160ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.io.IOException; import java.io.InterruptedIOException; import java.util.concurrent.TimeUnit; import org.xnio.ChannelListener; import org.xnio.XnioExecutor; /** * A suspendable writable channel. This type of channel is associated with a listener which can suspend and resume * writes as needed. */ public interface SuspendableWriteChannel extends CloseableChannel { /** * Suspend further write notifications on this channel. */ void suspendWrites(); /** * Resume writes on this channel. The write listener will be * called as soon as the channel becomes writable. */ void resumeWrites(); /** * Determine whether writes are resumed. * * @return {@code true} if writes are resumed, {@code false} if writes are suspended */ boolean isWriteResumed(); /** * {@link #resumeWrites() Resume writes} on this channel, and force the write listener to be triggered even if the * channel isn't actually writable. * * @deprecated Users should instead submit {@code Runnable} tasks to the channel thread when this functionality is needed. */ @Deprecated void wakeupWrites(); /** * Indicate that writing is complete for this channel. Further attempts to write data to this channel * after this method is invoked will result in an exception. If this method was already called, calling this method * again will have no additional effect. After this method is called, any remaining data still must be flushed out * via the {@link #flush()} method; once this is done, if the read side of the channel was shut down, the channel will * automatically close. * * @throws IOException if an I/O error occurs */ void shutdownWrites() throws IOException; /** * Block until this channel becomes writable again. This method may return spuriously * before the channel becomes writable. * * @throws InterruptedIOException if the operation is interrupted; the thread's interrupt flag will be set as well * @throws IOException if an I/O error occurs * * @since 1.2 */ void awaitWritable() throws IOException; /** * Block until this channel becomes writable again, or until the timeout expires. This method may return spuriously * before the channel becomes writable or the timeout expires. * * @param time the time to wait * @param timeUnit the time unit * @throws InterruptedIOException if the operation is interrupted; the thread's interrupt flag will be set as well * @throws IOException if an I/O error occurs * * @since 1.2 */ void awaitWritable(long time, TimeUnit timeUnit) throws IOException; /** * Get the write thread for this channel. * * @return the thread, or {@code null} if none is configured or available * @deprecated The {@link #getIoThread()} method should be used instead. */ @Deprecated XnioExecutor getWriteThread(); /** * Get the setter which can be used to change the write listener for this channel. * * @return the setter * * @since 2.0 */ ChannelListener.Setter getWriteSetter(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); /** * Flush any waiting partial send or write. If there is no data to flush, or if the flush completed successfully, * this method will return {@code true}. If there is data to flush which cannot be immediately written, this method * will return {@code false}. If this method returns {@code true} after {@link #shutdownWrites()} was called on * this channel, the write listener will no longer be invoked on this channel. If this is case and additionally * this is a write-only channel or the read side was previously shut down, then the channel will * automatically be closed. * * @return {@code true} if the message was flushed, or {@code false} if the result would block * @throws IOException if an I/O error occurs */ boolean flush() throws IOException; /** * Determine whether this channel is open. This method will return {@code false} if all directions are shut down, * even if there is unflushed write data pending. * * @return {@code true} if the channel is open, {@code false} otherwise */ boolean isOpen(); /** * Close this channel. If data has been written but not flushed, that data may be discarded, depending on the * channel implementation. When a channel is closed, its close listener is invoked. Invoking this method more than * once has no additional effect. * * @throws IOException if the close failed */ void close() throws IOException; } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/TranslatingSuspendableChannel.java000066400000000000000000001022651257016060700311120ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import static java.lang.Thread.currentThread; import static java.util.concurrent.locks.LockSupport.park; import static java.util.concurrent.locks.LockSupport.parkNanos; import static java.util.concurrent.locks.LockSupport.unpark; import static org.xnio.Bits.allAreClear; import static org.xnio.Bits.allAreSet; import static org.xnio.Bits.anyAreSet; import static org.xnio.Bits.intBitMask; import static org.xnio._private.Messages.msg; import java.io.IOException; import java.io.InterruptedIOException; import java.nio.channels.Channel; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.IoUtils; import org.xnio.Option; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; /** * An abstract wrapped channel. * * @param the channel type implemented by this class * @param the channel type being wrapped by this class * * @author David M. Lloyd * * @deprecated This class is deprecated; use conduits instead. */ @Deprecated public abstract class TranslatingSuspendableChannel implements SuspendableChannel, WrappedChannel, ReadListenerSettable, WriteListenerSettable, CloseListenerSettable { /** * The wrapped channel. */ protected final W channel; private ChannelListener readListener; private ChannelListener writeListener; private ChannelListener closeListener; @SuppressWarnings("unused") private volatile int state; @SuppressWarnings("unused") private volatile Thread readWaiter; @SuppressWarnings("unused") private volatile Thread writeWaiter; @SuppressWarnings("rawtypes") private static final AtomicIntegerFieldUpdater stateUpdater = AtomicIntegerFieldUpdater.newUpdater(TranslatingSuspendableChannel.class, "state"); @SuppressWarnings("rawtypes") private static final AtomicReferenceFieldUpdater readWaiterUpdater = AtomicReferenceFieldUpdater.newUpdater(TranslatingSuspendableChannel.class, Thread.class, "readWaiter"); @SuppressWarnings("rawtypes") private static final AtomicReferenceFieldUpdater writeWaiterUpdater = AtomicReferenceFieldUpdater.newUpdater(TranslatingSuspendableChannel.class, Thread.class, "writeWaiter"); // read-side private static final int READ_REQUESTED = 1 << 0x00; // user wants to be notified on read private static final int READ_REQUIRES_WRITE = 1 << 0x01; // channel cannot be read due to pending write private static final int READ_READY = 1 << 0x02; // channel is always ready to be read private static final int READ_SHUT_DOWN = 1 << 0x03; // user shut down reads private static final int READ_REQUIRES_EXT = intBitMask(0x0B, 0x0F); // channel cannot be read until external event completes, up to 31 events private static final int READ_SINGLE_EXT = 1 << 0x0B; // one external event count value @SuppressWarnings("unused") private static final int READ_FLAGS = intBitMask(0x00, 0x0F); // write-side private static final int WRITE_REQUESTED = 1 << 0x10; private static final int WRITE_REQUIRES_READ = 1 << 0x11; private static final int WRITE_READY = 1 << 0x12; private static final int WRITE_SHUT_DOWN = 1 << 0x13; // user requested shut down of writes private static final int WRITE_COMPLETE = 1 << 0x14; // flush acknowledged full write shutdown private static final int WRITE_REQUIRES_EXT = intBitMask(0x1B, 0x1F); // up to 32 events private static final int WRITE_SINGLE_EXT = 1 << 0x1B; @SuppressWarnings("unused") private static final int WRITE_FLAGS = intBitMask(0x10, 0x1F); private final ChannelListener delegateReadListener = new ChannelListener() { public void handleEvent(final Channel channel) { handleReadable(); } public String toString() { return "Read listener for " + TranslatingSuspendableChannel.this; } }; private final ChannelListener delegateWriteListener = new ChannelListener() { public void handleEvent(final Channel channel) { handleWritable(); } public String toString() { return "Write listener for " + TranslatingSuspendableChannel.this; } }; private final ChannelListener delegateCloseListener = new ChannelListener() { public void handleEvent(final Channel channel) { IoUtils.safeClose(TranslatingSuspendableChannel.this); } public String toString() { return "Close listener for " + TranslatingSuspendableChannel.this; } }; /** * Construct a new instance. * * @param channel the channel being wrapped */ protected TranslatingSuspendableChannel(final W channel) { if (channel == null) { throw msg.nullParameter("channel"); } this.channel = channel; channel.getReadSetter().set(delegateReadListener); channel.getWriteSetter().set(delegateWriteListener); channel.getCloseSetter().set(delegateCloseListener); } /** * Called when the underlying channel is readable. */ protected void handleReadable() { int oldState; oldState = clearFlags(WRITE_REQUIRES_READ); if (allAreSet(oldState, WRITE_REQUIRES_READ)) { unparkWriteWaiters(); if (allAreSet(oldState, WRITE_REQUESTED)) { channel.wakeupWrites(); } } if (allAreClear(oldState, READ_READY) && anyAreSet(oldState, READ_REQUIRES_WRITE | READ_REQUIRES_EXT)) { channel.suspendReads(); oldState = state; if (anyAreSet(oldState, READ_READY) || allAreClear(oldState, READ_REQUIRES_WRITE | READ_REQUIRES_EXT)) { // undo channel.resumeReads(); } else { return; } } do { if (anyAreSet(oldState, READ_SHUT_DOWN)) { channel.suspendReads(); return; } if (allAreClear(oldState, READ_REQUESTED)) { channel.suspendReads(); oldState = state; if (allAreSet(oldState, READ_REQUESTED)) { // undo channel.resumeReads(); } else { return; } } unparkReadWaiters(); final ChannelListener listener = readListener; if (listener == null) { // damage control oldState = clearFlag(READ_REQUESTED | WRITE_REQUIRES_READ) & ~READ_REQUESTED; } else { ChannelListeners.invokeChannelListener(thisTyped(), listener); oldState = clearFlags(WRITE_REQUIRES_READ); } if (allAreSet(oldState, WRITE_REQUIRES_READ)) { unparkWriteWaiters(); // race is OK channel.wakeupWrites(); } } while (allAreSet(oldState, READ_READY)); } /** * Called when the underlying channel is writable. */ protected void handleWritable() { int oldState; oldState = clearFlags(READ_REQUIRES_WRITE); if (allAreSet(oldState, READ_REQUIRES_WRITE)) { unparkReadWaiters(); if (allAreSet(oldState, READ_REQUESTED)) { channel.wakeupReads(); } } if (allAreClear(oldState, WRITE_READY) && anyAreSet(oldState, WRITE_REQUIRES_READ | WRITE_REQUIRES_EXT)) { channel.suspendWrites(); oldState = state; if (anyAreSet(oldState, WRITE_READY) || allAreClear(oldState, WRITE_REQUIRES_READ | WRITE_REQUIRES_EXT)) { // undo channel.resumeWrites(); } else { return; } } do { if (anyAreSet(oldState, WRITE_COMPLETE)) { channel.suspendWrites(); return; } if (allAreClear(oldState, WRITE_REQUESTED)) { channel.suspendWrites(); oldState = state; if (allAreSet(oldState, WRITE_REQUESTED)) { // undo channel.resumeWrites(); } else { return; } } unparkWriteWaiters(); final ChannelListener listener = writeListener; if (listener == null) { // damage control oldState = clearFlags(WRITE_REQUESTED | READ_REQUIRES_WRITE) & ~WRITE_REQUESTED; } else { ChannelListeners.invokeChannelListener(thisTyped(), listener); oldState = clearFlags(READ_REQUIRES_WRITE); } if (allAreSet(oldState, READ_REQUIRES_WRITE)) { unparkReadWaiters(); // race is OK channel.wakeupReads(); } } while (allAreSet(oldState, WRITE_READY)); } /** * Called when the underlying channel is closed. * */ protected void handleClosed() { ChannelListeners.invokeChannelListener(thisTyped(), closeListener); } // --- read --- /** * Indicate that the channel is definitely immediately readable, regardless of the underlying channel state. */ protected void setReadReady() { int oldState = setFlags(READ_READY); unparkReadWaiters(); if (allAreSet(oldState, READ_READY)) { // idempotent return; } if (allAreSet(oldState, READ_REQUESTED) && anyAreSet(oldState, READ_REQUIRES_EXT | READ_REQUIRES_WRITE)) { // wakeup is required to proceed channel.wakeupReads(); } } /** * Indicate that the channel is no longer definitely immediately readable. */ protected void clearReadReady() { int oldState = clearFlags(READ_READY); if (allAreClear(oldState, READ_READY)) { // idempotent return; } if (!allAreClear(oldState, READ_REQUESTED) && !anyAreSet(oldState, READ_REQUIRES_EXT | READ_REQUIRES_WRITE)) { // we can read again when the underlying channel is ready channel.resumeReads(); } } /** * Indicate that the channel will not be readable until the write handler is called. */ protected void setReadRequiresWrite() { int oldState = setFlags(READ_REQUIRES_WRITE); if (allAreSet(oldState, READ_REQUIRES_WRITE)) { // not the first caller return; } if (allAreClear(oldState, READ_READY | READ_REQUIRES_EXT)) { // read cannot proceed until write does channel.resumeWrites(); } } /** * Indicate if the channel is not readable until the write handler is called. */ protected boolean readRequiresWrite() { return allAreSet(state, READ_REQUIRES_WRITE); } /** * Indicate that the channel no longer requires writability for reads to proceed. */ protected void clearReadRequiresWrite() { int oldState = clearFlags(READ_REQUIRES_WRITE); if (allAreClear(oldState, READ_REQUIRES_WRITE)) { // idempotent return; } if (allAreClear(oldState, READ_REQUIRES_EXT) && allAreSet(oldState, READ_REQUESTED)) { if (allAreSet(oldState, READ_READY)) { channel.wakeupReads(); } else { channel.resumeReads(); } } } /** * Indicate that read requires an external task to complete. * * @return {@code true} if the flag was set, {@code false} if too many tasks are already outstanding */ protected boolean tryAddReadRequiresExternal() { int oldState = addFlag(READ_REQUIRES_EXT, READ_SINGLE_EXT); return (oldState & READ_REQUIRES_EXT) != READ_REQUIRES_EXT; } /** * Indicate that one external read task was completed. This method should be called once for every time * that {@link #tryAddReadRequiresExternal()} returned {@code true}. */ protected void removeReadRequiresExternal() { clearFlag(READ_SINGLE_EXT); } /** * Set the channel read shut down flag. * * @return {@code true} if the channel has fully closed due to this call, {@code false} otherwise */ protected boolean setReadShutDown() { return (setFlags(READ_SHUT_DOWN) & (READ_SHUT_DOWN | WRITE_SHUT_DOWN)) == WRITE_SHUT_DOWN; } // --- write --- /** * Indicate that the channel is definitely immediately writable, regardless of the underlying channel state. */ protected void setWriteReady() { int oldState = setFlags(WRITE_READY); unparkWriteWaiters(); if (allAreSet(oldState, WRITE_READY)) { // idempotent return; } if (allAreSet(oldState, WRITE_REQUESTED) && anyAreSet(oldState, WRITE_REQUIRES_EXT | WRITE_REQUIRES_READ)) { // wakeup is required to proceed channel.wakeupWrites(); } } /** * Indicate that the channel is no longer definitely immediately writable. */ protected void clearWriteReady() { int oldState = clearFlags(WRITE_READY); if (allAreClear(oldState, WRITE_READY)) { // idempotent return; } if (!allAreClear(oldState, WRITE_REQUESTED) && ! anyAreSet(oldState, WRITE_REQUIRES_EXT | WRITE_REQUIRES_READ)) { // we can write again when the underlying channel is ready channel.resumeWrites(); } } /** * Indicate that the channel will not be writable until the read handler is called. */ protected void setWriteRequiresRead() { int oldState = setFlags(WRITE_REQUIRES_READ); if (allAreSet(oldState, WRITE_REQUIRES_READ)) { // not the first caller return; } if (allAreClear(oldState, WRITE_READY | WRITE_REQUIRES_EXT)) { // write cannot proceed until read does channel.resumeReads(); } } /** * Indicate if the channel is not writable until the read handler is called. */ protected boolean writeRequiresRead() { return allAreSet(state, WRITE_REQUIRES_READ); } /** * Indicate that the channel no longer requires writability for writes to proceed. */ protected void clearWriteRequiresRead() { int oldState = clearFlags(WRITE_REQUIRES_READ); if (allAreClear(oldState, WRITE_REQUIRES_READ)) { // idempotent return; } if (allAreClear(oldState, WRITE_REQUIRES_EXT) && allAreSet(oldState, WRITE_REQUESTED)) { if (allAreSet(oldState, WRITE_READY)) { channel.wakeupWrites(); } else { channel.resumeWrites(); } } } /** * Indicate that write requires an external task to complete. * * @return {@code true} if the flag was set, {@code false} if too many tasks are already outstanding */ protected boolean tryAddWriteRequiresExternal() { int oldState = addFlag(WRITE_REQUIRES_EXT, WRITE_SINGLE_EXT); return (oldState & WRITE_REQUIRES_EXT) != WRITE_REQUIRES_EXT; } /** * Indicate that one external write task was completed. This method should be called once for every time * that {@link #tryAddWriteRequiresExternal()} returned {@code true}. */ protected void removeWriteRequiresExternal() { clearFlag(WRITE_SINGLE_EXT); } /** * Set the channel write shut down flag. * * @return {@code true} if the channel has fully closed due to this call, {@code false} otherwise */ protected boolean setWriteShutDown() { return (setFlags(WRITE_SHUT_DOWN) & (WRITE_SHUT_DOWN | READ_SHUT_DOWN)) == READ_SHUT_DOWN; } // --- read & write --- /** * Set both the channel read and write shut down flags. * * @return {@code true} if the channel has fully closed (for the first time) due to this call, {@code false} otherwise */ protected boolean setClosed() { return (setFlags(READ_SHUT_DOWN | WRITE_SHUT_DOWN) & (READ_SHUT_DOWN | WRITE_SHUT_DOWN)) != (READ_SHUT_DOWN | WRITE_SHUT_DOWN); } /** * Get this channel, cast to the implemented channel type. * * @return {@code this} */ @SuppressWarnings("unchecked") protected final C thisTyped() { return (C) this; } public void setReadListener(final ChannelListener readListener) { this.readListener = readListener; } public ChannelListener getReadListener() { return readListener; } public void setWriteListener(final ChannelListener writeListener) { this.writeListener = writeListener; } public ChannelListener getWriteListener() { return writeListener; } public void setCloseListener(final ChannelListener closeListener) { this.closeListener = closeListener; } public ChannelListener getCloseListener() { return closeListener; } /** {@inheritDoc} */ public ChannelListener.Setter getCloseSetter() { return new CloseListenerSettable.Setter(this); } /** {@inheritDoc} */ public ChannelListener.Setter getReadSetter() { return new ReadListenerSettable.Setter(this) ; } /** {@inheritDoc} */ public ChannelListener.Setter getWriteSetter() { return new WriteListenerSettable.Setter(this); } /** {@inheritDoc} */ public void suspendReads() { clearFlags(READ_REQUESTED); // let the read/write handler actually suspend, to avoid awkward race conditions } /** {@inheritDoc} */ public void resumeReads() { final int oldState = setFlags(READ_REQUESTED); if (anyAreSet(oldState, READ_REQUESTED | READ_SHUT_DOWN)) { // idempotent or shut down, either way return; } if (allAreSet(oldState, READ_READY)) { // reads are known to be ready so trigger listener right away channel.wakeupReads(); return; } if (allAreClear(oldState, READ_REQUIRES_EXT)) { if (allAreSet(oldState, READ_REQUIRES_WRITE)) { channel.resumeWrites(); } else { channel.resumeReads(); } } } public boolean isReadResumed() { return allAreSet(state, READ_REQUESTED); } /** {@inheritDoc} */ public void wakeupReads() { if (anyAreSet(state, READ_SHUT_DOWN)) { return; } setFlags(READ_REQUESTED); channel.wakeupReads(); } /** {@inheritDoc} */ public void suspendWrites() { clearFlags(WRITE_REQUESTED); // let the read/write handler actually suspend, to avoid awkward race conditions } /** {@inheritDoc} */ public void resumeWrites() { final int oldState = setFlags(WRITE_REQUESTED); if (anyAreSet(oldState, WRITE_REQUESTED | WRITE_COMPLETE)) { // idempotent or shut down, either way return; } if (allAreSet(oldState, WRITE_READY)) { // reads are known to be ready so trigger listener right away channel.wakeupWrites(); return; } if (allAreClear(oldState, WRITE_REQUIRES_EXT)) { if (allAreSet(oldState, WRITE_REQUIRES_READ)) { channel.resumeReads(); } else { channel.resumeWrites(); } } } public boolean isWriteResumed() { return allAreSet(state, WRITE_REQUESTED); } /** {@inheritDoc} */ public void wakeupWrites() { if (anyAreSet(state, WRITE_SHUT_DOWN)) { return; } setFlags(WRITE_REQUESTED); channel.wakeupWrites(); unparkWriteWaiters(); } /** {@inheritDoc} */ public boolean supportsOption(final Option option) { return channel.supportsOption(option); } /** {@inheritDoc} */ public T getOption(final Option option) throws IOException { return channel.getOption(option); } /** {@inheritDoc} */ public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return channel.setOption(option, value); } /** * Perform channel flush. To change the action taken to flush, subclasses should override {@link #flushAction(boolean)}. * * @return {@code true} if the flush completed, or {@code false} if the operation would block * @throws IOException if an error occurs */ public final boolean flush() throws IOException { int oldState, newState; oldState = stateUpdater.get(this); if (allAreSet(oldState, WRITE_COMPLETE)) { return channel.flush(); } final boolean shutDown = allAreSet(oldState, WRITE_SHUT_DOWN); if (! flushAction(shutDown)) { return false; } if (! shutDown) { return true; } newState = oldState | WRITE_COMPLETE; while (! stateUpdater.compareAndSet(this, oldState, newState)) { oldState = stateUpdater.get(this); if (allAreSet(oldState, WRITE_COMPLETE)) { return channel.flush(); } newState = oldState | WRITE_COMPLETE; } final boolean readShutDown = allAreSet(oldState, READ_SHUT_DOWN); try { shutdownWritesComplete(readShutDown); } finally { if (readShutDown) ChannelListeners.invokeChannelListener(thisTyped(), closeListener); } return channel.flush(); } /** * The action to perform when the channel is flushed. By default, this method delegates to the underlying channel. * If the {@code shutDown} parameter is set, and this method returns {@code true}, the underlying channel will be * shut down and this method will never be called again (future calls to {@link #flush()} will flush the underlying * channel until it returns {@code true}). * * @param shutDown {@code true} if the channel's write side has been shut down, {@code false} otherwise * @return {@code true} if the flush succeeded, {@code false} if it would block * @throws IOException if an error occurs */ protected boolean flushAction(final boolean shutDown) throws IOException { return channel.flush(); } /** * Notification that the channel has successfully flushed after having shut down writes. The underlying * channel may not yet be fully flushed at this time. * * @param readShutDown {@code true} if the read side was already shut down, {@code false} otherwise * @throws IOException if an error occurs */ protected void shutdownWritesComplete(final boolean readShutDown) throws IOException { } /** * Perform the read shutdown action if it hasn't been performed already. * * @throws IOException if an I/O error occurs */ public void shutdownReads() throws IOException { int old = setFlags(READ_SHUT_DOWN); if (allAreClear(old, READ_SHUT_DOWN)) { final boolean writeComplete = allAreSet(old, WRITE_COMPLETE); try { shutdownReadsAction(writeComplete); } finally { if (writeComplete) { ChannelListeners.invokeChannelListener(thisTyped(), closeListener); } } } } /** * The action to perform when reads are shut down. By default, this method delegates to the underlying channel. * * @throws IOException if an error occurs * @param writeComplete */ protected void shutdownReadsAction(final boolean writeComplete) throws IOException { channel.shutdownReads(); } /** * Determine whether the channel is shut down for reads. * * @return whether the channel is shut down for reads */ protected boolean isReadShutDown() { return allAreSet(state, READ_SHUT_DOWN); } /** * Perform the write shutdown action if it hasn't been performed already. * * @throws IOException if an I/O error occurs */ public void shutdownWrites() throws IOException { int old = setFlags(WRITE_SHUT_DOWN); if (allAreClear(old, WRITE_SHUT_DOWN)) { shutdownWritesAction(); } } /** * The action to perform when writes are requested to be shut down. By default, this method delegates to the * underlying channel. * * @throws IOException if an error occurs */ protected void shutdownWritesAction() throws IOException { channel.shutdownWrites(); } /** * Determine whether the channel is shut down for writes. * * @return whether the channel is shut down for writes */ protected boolean isWriteShutDown() { return allAreSet(state, WRITE_SHUT_DOWN); } protected boolean isWriteComplete() { return allAreSet(state, WRITE_COMPLETE); } /** {@inheritDoc} */ public void awaitReadable() throws IOException { int oldState = state; if (anyAreSet(oldState, READ_READY | READ_SHUT_DOWN)) { return; } final Thread thread = currentThread(); final Thread next = readWaiterUpdater.getAndSet(this, thread); try { if (anyAreSet(oldState = state, READ_READY | READ_SHUT_DOWN)) { return; } if (allAreSet(oldState, READ_REQUIRES_WRITE)) { channel.resumeWrites(); } else { channel.resumeReads(); } park(this); if (thread.isInterrupted()) { throw msg.interruptedIO(); } } finally { // always unpark because we cannot know if our awaken was spurious if (next != null) unpark(next); } } /** {@inheritDoc} */ public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { int oldState = state; if (anyAreSet(oldState, READ_READY | READ_SHUT_DOWN)) { return; } final Thread thread = currentThread(); final Thread next = readWaiterUpdater.getAndSet(this, thread); long duration = timeUnit.toNanos(time); try { if (anyAreSet(oldState = state, READ_READY | READ_SHUT_DOWN)) { return; } if (allAreSet(oldState, READ_REQUIRES_WRITE)) { channel.resumeWrites(); } else { channel.resumeReads(); } parkNanos(this, duration); if (thread.isInterrupted()) { throw msg.interruptedIO(); } } finally { // always unpark because we cannot know if our awaken was spurious if (next != null) unpark(next); } } @Deprecated public XnioExecutor getReadThread() { return channel.getReadThread(); } /** {@inheritDoc} */ public void awaitWritable() throws IOException { int oldState = state; if (anyAreSet(oldState, WRITE_READY | WRITE_SHUT_DOWN)) { return; } final Thread thread = currentThread(); final Thread next = writeWaiterUpdater.getAndSet(this, thread); try { if (anyAreSet(oldState = state, WRITE_READY | WRITE_SHUT_DOWN)) { return; } if (allAreSet(oldState, WRITE_REQUIRES_READ)) { channel.resumeReads(); } else { channel.resumeWrites(); } park(this); if (thread.isInterrupted()) { throw msg.interruptedIO(); } } finally { // always unpark because we cannot know if our awaken was spurious if (next != null) unpark(next); } } /** {@inheritDoc} */ public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException { int oldState = state; if (anyAreSet(oldState, WRITE_READY | WRITE_SHUT_DOWN)) { return; } final Thread thread = currentThread(); final Thread next = writeWaiterUpdater.getAndSet(this, thread); long duration = timeUnit.toNanos(time); try { if (anyAreSet(oldState = state, WRITE_READY | WRITE_SHUT_DOWN)) { return; } if (allAreSet(oldState, WRITE_REQUIRES_READ)) { channel.resumeReads(); } else { channel.resumeWrites(); } parkNanos(this, duration); if (thread.isInterrupted()) { throw msg.interruptedIO(); } } finally { // always unpark because we cannot know if our awaken was spurious if (next != null) unpark(next); } } private void unparkReadWaiters() { final Thread waiter = readWaiterUpdater.getAndSet(this, null); if (waiter != null) { unpark(waiter); } } private void unparkWriteWaiters() { final Thread waiter = writeWaiterUpdater.getAndSet(this, null); if (waiter != null) { unpark(waiter); } } @Deprecated public XnioExecutor getWriteThread() { return channel.getWriteThread(); } /** * Close this channel. This method is idempotent. * * @throws IOException if an I/O error occurs */ public void close() throws IOException { int old = setFlags(READ_SHUT_DOWN | WRITE_SHUT_DOWN | WRITE_COMPLETE); final boolean readShutDown = allAreSet(old, READ_SHUT_DOWN), writeShutDown = allAreSet(old, WRITE_COMPLETE); if (! (readShutDown && writeShutDown)) try { closeAction(readShutDown, writeShutDown); } finally { ChannelListeners.invokeChannelListener(thisTyped(), closeListener); } } /** * The action to perform when the channel is closed via the {@link #close()} method. By default, the underlying * channel is closed. * * @param readShutDown if reads were previously shut down * @param writeShutDown if writes were previously shut down * @throws IOException if an error occurs */ protected void closeAction(final boolean readShutDown, final boolean writeShutDown) throws IOException { channel.close(); } /** {@inheritDoc} */ public boolean isOpen() { return ! allAreSet(state, READ_SHUT_DOWN | WRITE_COMPLETE); } /** {@inheritDoc} */ public W getChannel() { return channel; } /** {@inheritDoc} */ public XnioWorker getWorker() { return channel.getWorker(); } /** {@inheritDoc} */ public XnioIoThread getIoThread() { return channel.getIoThread(); } /** {@inheritDoc} */ public String toString() { return getClass().getName() + " around " + channel; } // state operations private int setFlags(int flags) { int oldState; do { oldState = state; if ((oldState & flags) == flags) { return oldState; } } while (! stateUpdater.compareAndSet(this, oldState, oldState | flags)); return oldState; } private int clearFlags(int flags) { int oldState; do { oldState = state; if ((oldState & flags) == 0) { return oldState; } } while (! stateUpdater.compareAndSet(this, oldState, oldState & ~flags)); return oldState; } private int addFlag(final int mask, final int count) { int oldState; do { oldState = state; if ((oldState & mask) == mask) { return oldState; } } while (! stateUpdater.compareAndSet(this, oldState, oldState + count)); return oldState; } private int clearFlag(final int count) { return stateUpdater.getAndAdd(this, -count); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/UnsupportedOptionException.java000066400000000000000000000035161257016060700305440ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; /** * An exception that is thrown when an invalid option is specified for a {@link Configurable}. * * @apiviz.exclude */ public class UnsupportedOptionException extends IllegalArgumentException { private static final long serialVersionUID = 250195510855241708L; /** * Construct a {@code UnsupportedOptionException} instance. */ public UnsupportedOptionException() { } /** * Construct a {@code UnsupportedOptionException} instance with the given message. * * @param message the message */ public UnsupportedOptionException(final String message) { super(message); } /** * Construct a {@code UnsupportedOptionException} instance with the given message and cause. * * @param message the message * @param cause the cause */ public UnsupportedOptionException(final String message, final Throwable cause) { super(message, cause); } /** * Construct a {@code UnsupportedOptionException} instance with the given cause. * * @param cause the cause */ public UnsupportedOptionException(final Throwable cause) { super(cause); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/WrappedChannel.java000066400000000000000000000006141257016060700260330ustar00rootroot00000000000000 package org.xnio.channels; import java.nio.channels.Channel; /** * A wrapped channel. * * @param the wrapped channel type * @author David M. Lloyd */ public interface WrappedChannel { /** * Get the channel which is wrapped by this object. * * @return the wrapped channel */ C getChannel(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/WritableMessageChannel.java000066400000000000000000000072401257016060700275110ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.io.IOException; import java.nio.ByteBuffer; import org.xnio.ChannelListener; /** * A channel that can send messages. */ public interface WritableMessageChannel extends SuspendableWriteChannel, Configurable { /** * Send a complete message. * * @param buffer the message to send * @return the result of the send operation; {@code true} if the message was sent, or {@code false} if it would block * @throws IOException if an I/O error occurs */ boolean send(ByteBuffer buffer) throws IOException; /** * Send a complete message. * * @param buffers the buffers holding the message to send * @return the result of the send operation; {@code true} if the message was sent, or {@code false} if it would block * @throws IOException if an I/O error occurs */ boolean send(ByteBuffer[] buffers) throws IOException; /** * Send a complete message. * * @param buffers the buffers holding the message to send * @param offs the offset into the buffer array of the first buffer * @param len the number of buffers that contain data to send * @return the result of the send operation; {@code true} if the message was sent, or {@code false} if it would block * @throws IOException if an I/O error occurs */ boolean send(ByteBuffer[] buffers, int offs, int len) throws IOException; /** * Send a complete message. If the message was successfully sent the channel with have its writes shutdown. * * @param buffer the message to send * @return the result of the send operation; {@code true} if the message was sent, or {@code false} if it would block * @throws IOException if an I/O error occurs */ boolean sendFinal(ByteBuffer buffer) throws IOException; /** * Send a complete message. If the message was successfully sent the channel with have its writes shutdown. * * @param buffers the buffers holding the message to send * @return the result of the send operation; {@code true} if the message was sent, or {@code false} if it would block * @throws IOException if an I/O error occurs */ boolean sendFinal(ByteBuffer[] buffers) throws IOException; /** * Send a complete message. If the message was successfully sent the channel with have its writes shutdown. * * @param buffers the buffers holding the message to send * @param offs the offset into the buffer array of the first buffer * @param len the number of buffers that contain data to send * @return the result of the send operation; {@code true} if the message was sent, or {@code false} if it would block * @throws IOException if an I/O error occurs */ boolean sendFinal(ByteBuffer[] buffers, int offs, int len) throws IOException; /** {@inheritDoc} */ ChannelListener.Setter getWriteSetter(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/WritableMultipointMessageChannel.java000066400000000000000000000050301257016060700315710ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.io.IOException; import org.xnio.ChannelListener; /** * The writable side of a multipoint message channel. * * @see MultipointMessageChannel */ public interface WritableMultipointMessageChannel extends SuspendableWriteChannel { /** * Send a buffer to a destination. * * @param target the destination * @param buffer the data to send * @return {@code true} if the message was sent, or {@code false} if the channel is not currently writable * @throws IOException if an I/O error occurs */ boolean sendTo(SocketAddress target, ByteBuffer buffer) throws IOException; /** * Send a message with data from multiple buffers to a destination. * * @param target the destination * @param buffers the data to send * @return {@code true} if the message was sent, or {@code false} if the channel is not currently writable * @throws IOException if an I/O error occurs */ boolean sendTo(SocketAddress target, ByteBuffer[] buffers) throws IOException; /** * Send a message with data from multiple buffers to a destination. * * @param target the destination * @param buffers the data to send * @param offset the offset into the {@code buffers} array * @param length the number of buffers to read from * @return {@code true} if the message was sent, or {@code false} if the channel is not currently writable * @throws IOException if an I/O error occurs */ boolean sendTo(SocketAddress target, ByteBuffer[] buffers, int offset, int length) throws IOException; /** {@inheritDoc} */ ChannelListener.Setter getWriteSetter(); /** {@inheritDoc} */ ChannelListener.Setter getCloseSetter(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/WriteListenerSettable.java000066400000000000000000000036551257016060700274340ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.nio.channels.Channel; import org.xnio.ChannelListener; /** * An object which supports directly setting the write listener may implement this interface. * * @author David M. Lloyd */ public interface WriteListenerSettable { /** * Set the write listener. * * @param listener the write listener */ void setWriteListener(ChannelListener listener); /** * Get the write listener. * * @return the write listener */ ChannelListener getWriteListener(); /** * A channel listener setter implementation which delegates to the appropriate setter method. * * @param the channel type */ class Setter implements ChannelListener.Setter { private final WriteListenerSettable settable; /** * Construct a new instance. * * @param settable the settable to delegate to */ public Setter(final WriteListenerSettable settable) { this.settable = settable; } public void set(final ChannelListener listener) { settable.setWriteListener(listener); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/WriteTimeoutException.java000066400000000000000000000045361257016060700274670ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2010 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.channels; import java.io.InterruptedIOException; /** * Thrown when a blocking write operation times out. */ public class WriteTimeoutException extends InterruptedIOException { private static final long serialVersionUID = 2058056832934733469L; /** * Constructs a {@code WriteTimeoutException} with no detail message. The cause is not initialized, and may subsequently * be initialized by a call to {@link #initCause(Throwable) initCause}. */ public WriteTimeoutException() { } /** * Constructs a {@code WriteTimeoutException} with the specified detail message. The cause is not initialized, and may * subsequently be initialized by a call to {@link #initCause(Throwable) initCause}. * * @param msg the detail message */ public WriteTimeoutException(final String msg) { super(msg); } /** * Constructs a {@code WriteTimeoutException} with the specified cause. The detail message is set to: *

(cause == null ? null : cause.toString())
* (which typically contains the class and detail message of {@code cause}). * * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) */ public WriteTimeoutException(final Throwable cause) { initCause(cause); } /** * Constructs a {@code WriteTimeoutException} with the specified detail message and cause. * * @param msg the detail message * @param cause the cause (which is saved for later retrieval by the {@link #getCause()} method) */ public WriteTimeoutException(final String msg, final Throwable cause) { super(msg); initCause(cause); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/channels/package-info.java000066400000000000000000000001011257016060700254530ustar00rootroot00000000000000/** * The core XNIO channel API. */ package org.xnio.channels; xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/000077500000000000000000000000001257016060700223315ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/AbstractConduit.java000066400000000000000000000025651257016060700262750ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import static org.xnio._private.Messages.msg; import org.xnio.XnioWorker; /** * An abstract base class for filtering conduits. * * @author David M. Lloyd */ public abstract class AbstractConduit implements Conduit { /** * The delegate conduit. */ protected final D next; /** * Construct a new instance. * * @param next the delegate conduit to set */ protected AbstractConduit(final D next) { if (next == null) { throw msg.nullParameter("next"); } this.next = next; } public XnioWorker getWorker() { return next.getWorker(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/AbstractMessageSinkConduit.java000066400000000000000000000033441257016060700304230ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; /** * An abstract base class for filtering message sink conduits. * * @author David M. Lloyd */ public abstract class AbstractMessageSinkConduit extends AbstractSinkConduit implements MessageSinkConduit { /** * Construct a new instance. * * @param next the delegate conduit to set */ protected AbstractMessageSinkConduit(final D next) { super(next); } public boolean send(final ByteBuffer src) throws IOException { return next.send(src); } public boolean send(final ByteBuffer[] srcs, final int offs, final int len) throws IOException { return next.send(srcs, offs, len); } @Override public boolean sendFinal(ByteBuffer[] srcs, int offs, int len) throws IOException { return next.sendFinal(srcs, offs, len); } @Override public boolean sendFinal(ByteBuffer src) throws IOException { return next.sendFinal(src); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/AbstractMessageSourceConduit.java000066400000000000000000000027351257016060700307620ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; /** * An abstract base class for filtering message source conduits. * * @author David M. Lloyd */ public abstract class AbstractMessageSourceConduit extends AbstractSourceConduit implements MessageSourceConduit { /** * Construct a new instance. * * @param next the delegate conduit to set */ protected AbstractMessageSourceConduit(final D next) { super(next); } public int receive(final ByteBuffer dst) throws IOException { return next.receive(dst); } public long receive(final ByteBuffer[] dsts, final int offs, final int len) throws IOException { return next.receive(dsts, offs, len); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/AbstractSinkConduit.java000066400000000000000000000044221257016060700271140ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.util.concurrent.TimeUnit; import org.xnio.XnioIoThread; /** * An abstract base class for filtering output conduits. * * @author David M. Lloyd */ public abstract class AbstractSinkConduit extends AbstractConduit implements SinkConduit { /** * Construct a new instance. * * @param next the delegate conduit to set */ protected AbstractSinkConduit(final D next) { super(next); } public void terminateWrites() throws IOException { next.terminateWrites(); } public boolean isWriteShutdown() { return next.isWriteShutdown(); } public void resumeWrites() { next.resumeWrites(); } public void suspendWrites() { next.suspendWrites(); } public void wakeupWrites() { next.wakeupWrites(); } public boolean isWriteResumed() { return next.isWriteResumed(); } public void awaitWritable() throws IOException { next.awaitWritable(); } public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException { next.awaitWritable(time, timeUnit); } public XnioIoThread getWriteThread() { return next.getWriteThread(); } public void setWriteReadyHandler(final WriteReadyHandler handler) { next.setWriteReadyHandler(handler); } public void truncateWrites() throws IOException { next.truncateWrites(); } public boolean flush() throws IOException { return next.flush(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/AbstractSourceConduit.java000066400000000000000000000041311257016060700274450ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.util.concurrent.TimeUnit; import org.xnio.XnioIoThread; /** * An abstract base class for filtering source conduits. * * @author David M. Lloyd */ public abstract class AbstractSourceConduit extends AbstractConduit implements SourceConduit { /** * Construct a new instance. * * @param next the delegate conduit to set */ protected AbstractSourceConduit(final D next) { super(next); } public void terminateReads() throws IOException { next.terminateReads(); } public boolean isReadShutdown() { return next.isReadShutdown(); } public void resumeReads() { next.resumeReads(); } public void suspendReads() { next.suspendReads(); } public void wakeupReads() { next.wakeupReads(); } public boolean isReadResumed() { return next.isReadResumed(); } public void awaitReadable() throws IOException { next.awaitReadable(); } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { next.awaitReadable(time, timeUnit); } public XnioIoThread getReadThread() { return next.getReadThread(); } public void setReadReadyHandler(final ReadReadyHandler handler) { next.setReadReadyHandler(handler); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/AbstractStreamSinkConduit.java000066400000000000000000000042631257016060700302730ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import org.xnio.channels.StreamSourceChannel; /** * An abstract base class for filtering stream sink conduits. * * @author David M. Lloyd */ public abstract class AbstractStreamSinkConduit extends AbstractSinkConduit implements StreamSinkConduit { /** * Construct a new instance. * * @param next the delegate conduit to set */ protected AbstractStreamSinkConduit(final D next) { super(next); } public long transferFrom(final FileChannel src, final long position, final long count) throws IOException { return next.transferFrom(src, position, count); } public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { return next.transferFrom(source, count, throughBuffer); } public int write(final ByteBuffer src) throws IOException { return next.write(src); } public long write(final ByteBuffer[] srcs, final int offs, final int len) throws IOException { return next.write(srcs, offs, len); } @Override public int writeFinal(ByteBuffer src) throws IOException { return next.writeFinal(src); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { return next.writeFinal(srcs, offset, length); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/AbstractStreamSourceConduit.java000066400000000000000000000036261257016060700306310ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import org.xnio.channels.StreamSinkChannel; /** * An abstract base class for filtering stream source conduits. * * @author David M. Lloyd */ public abstract class AbstractStreamSourceConduit extends AbstractSourceConduit implements StreamSourceConduit { /** * Construct a new instance. * * @param next the delegate conduit to set */ protected AbstractStreamSourceConduit(final D next) { super(next); } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { return next.transferTo(position, count, target); } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { return next.transferTo(count, throughBuffer, target); } public int read(final ByteBuffer dst) throws IOException { return next.read(dst); } public long read(final ByteBuffer[] dsts, final int offs, final int len) throws IOException { return next.read(dsts, offs, len); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/AbstractSynchronizedConduit.java000066400000000000000000000030221257016060700306620ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; /** * An abstract synchronized conduit. All conduit operations are wrapped in synchronization blocks for simplified * thread safety. * * @author David M. Lloyd */ public abstract class AbstractSynchronizedConduit extends AbstractConduit { protected final Object lock; /** * Construct a new instance. A new lock object is created. * * @param next the next conduit in the chain */ protected AbstractSynchronizedConduit(final D next) { this(next, new Object()); } /** * Construct a new instance. * * @param next the next conduit in the chain * @param lock the lock object to use */ protected AbstractSynchronizedConduit(final D next, final Object lock) { super(next); this.lock = lock; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/AbstractSynchronizedSinkConduit.java000066400000000000000000000053531257016060700315200ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.util.concurrent.TimeUnit; import org.xnio.XnioIoThread; /** * @author David M. Lloyd */ public abstract class AbstractSynchronizedSinkConduit extends AbstractSynchronizedConduit implements SinkConduit { protected AbstractSynchronizedSinkConduit(final D next) { super(next); } protected AbstractSynchronizedSinkConduit(final D next, final Object lock) { super(next, lock); } public void terminateWrites() throws IOException { synchronized (lock) { next.terminateWrites(); } } public boolean isWriteShutdown() { synchronized (lock) { return next.isWriteShutdown(); } } public void resumeWrites() { synchronized (lock) { next.resumeWrites(); } } public void suspendWrites() { synchronized (lock) { next.suspendWrites(); } } public void wakeupWrites() { synchronized (lock) { next.wakeupWrites(); } } public boolean isWriteResumed() { synchronized (lock) { return next.isWriteResumed(); } } public void awaitWritable() throws IOException { synchronized (lock) { next.awaitWritable(); } } public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException { synchronized (lock) { next.awaitWritable(time, timeUnit); } } public XnioIoThread getWriteThread() { return next.getWriteThread(); } public void setWriteReadyHandler(final WriteReadyHandler handler) { synchronized (lock) { next.setWriteReadyHandler(handler); } } public void truncateWrites() throws IOException { synchronized (lock) { next.truncateWrites(); } } public boolean flush() throws IOException { synchronized (lock) { return next.flush(); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/AbstractSynchronizedSourceConduit.java000066400000000000000000000056051257016060700320540ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.util.concurrent.TimeUnit; import org.xnio.XnioIoThread; /** * An abstract synchronized source conduit. All conduit operations are wrapped in synchronization blocks for simplified * thread safety. * * @author David M. Lloyd */ public abstract class AbstractSynchronizedSourceConduit extends AbstractSynchronizedConduit implements SourceConduit { /** * Construct a new instance. A new lock object is created. * * @param next the next conduit in the chain */ protected AbstractSynchronizedSourceConduit(final D next) { super(next); } /** * Construct a new instance. * * @param next the next conduit in the chain * @param lock the lock object to use */ protected AbstractSynchronizedSourceConduit(final D next, final Object lock) { super(next, lock); } public void terminateReads() throws IOException { synchronized (lock) { next.terminateReads(); } } public boolean isReadShutdown() { synchronized (lock) { return next.isReadShutdown(); } } public void resumeReads() { synchronized (lock) { next.resumeReads(); } } public void suspendReads() { synchronized (lock) { next.suspendReads(); } } public void wakeupReads() { synchronized (lock) { next.wakeupReads(); } } public boolean isReadResumed() { synchronized (lock) { return next.isReadResumed(); } } public void awaitReadable() throws IOException { synchronized (lock) { next.awaitReadable(); } } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { synchronized (lock) { next.awaitReadable(time, timeUnit); } } public XnioIoThread getReadThread() { return next.getReadThread(); } public void setReadReadyHandler(final ReadReadyHandler handler) { synchronized (lock) { next.setReadReadyHandler(handler); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/BlockingStreamSinkConduit.java000066400000000000000000000077601257016060700302650ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import org.xnio.channels.StreamSourceChannel; /** * @author David M. Lloyd */ public final class BlockingStreamSinkConduit extends AbstractStreamSinkConduit { private boolean resumed; public BlockingStreamSinkConduit(final StreamSinkConduit next) { super(next); } public long transferFrom(final FileChannel src, final long position, final long count) throws IOException { if (resumed) return next.transferFrom(src, position, count); long res; while ((res = next.transferFrom(src, position, count)) == 0L) { next.awaitWritable(); } return res; } public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { if (resumed) return next.transferFrom(source, count, throughBuffer); long res; while ((res = next.transferFrom(source, count, throughBuffer)) == 0L) { next.awaitWritable(); } return res; } @Override public int write(final ByteBuffer src) throws IOException { return write(src, false); } @Override public long write(final ByteBuffer[] srcs, final int offs, final int len) throws IOException { return write(srcs, offs, len, false); } @Override public int writeFinal(ByteBuffer src) throws IOException { return write(src, true); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { return write(srcs, offset, length, true); } private int write(final ByteBuffer src, final boolean writeFinal) throws IOException { if (resumed) { return doWrite(src, writeFinal); } int res; while ((res = doWrite(src, writeFinal)) == 0L) { next.awaitWritable(); } return res; } private long write(final ByteBuffer[] srcs, final int offs, final int len, final boolean writeFinal) throws IOException { if (resumed) return doWrite(srcs, offs, len, writeFinal); long res; while ((res = next.write(srcs, offs, len)) == 0L) { next.awaitWritable(); } return res; } private int doWrite(ByteBuffer src, boolean writeFinal) throws IOException { if(writeFinal) { return next.writeFinal(src); } return next.write(src); } private long doWrite(ByteBuffer[] srcs,final int offs, final int len, boolean writeFinal) throws IOException { if(writeFinal) { return next.writeFinal(srcs, offs, len); } return next.write(srcs, offs, len); } public boolean flush() throws IOException { if (resumed) return next.flush(); while (! next.flush()) { next.awaitWritable(); } return true; } public void resumeWrites() { resumed = true; next.resumeWrites(); } public void suspendWrites() { resumed = false; next.suspendWrites(); } public void wakeupWrites() { resumed = true; next.wakeupWrites(); } public boolean isWriteResumed() { return resumed; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/BlockingStreamSourceConduit.java000066400000000000000000000056311257016060700306140ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import org.xnio.channels.StreamSinkChannel; /** * A stream source conduit which can switch into and out of blocking mode. * * @author David M. Lloyd */ public final class BlockingStreamSourceConduit extends AbstractStreamSourceConduit { private boolean resumed; /** * Construct a new instance. * * @param next the delegate conduit to set */ public BlockingStreamSourceConduit(final StreamSourceConduit next) { super(next); } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { if (resumed) return next.transferTo(position, count, target); long res; while ((res = next.transferTo(position, count, target)) == 0L) { next.awaitReadable(); } return res; } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { if (resumed) return next.transferTo(count, throughBuffer, target); long res; while ((res = next.transferTo(count, throughBuffer, target)) == 0L && ! throughBuffer.hasRemaining()) { next.awaitReadable(); } return res; } public int read(final ByteBuffer dst) throws IOException { if (resumed) return next.read(dst); int res; while ((res = next.read(dst)) == 0) { next.awaitReadable(); } return res; } public long read(final ByteBuffer[] dsts, final int offs, final int len) throws IOException { if (resumed) return next.read(dsts, offs, len); long res; while ((res = next.read(dsts, offs, len)) == 0L) { next.awaitReadable(); } return res; } public void resumeReads() { resumed = true; next.resumeReads(); } public void wakeupReads() { resumed = true; next.wakeupReads(); } public void suspendReads() { resumed = false; next.suspendReads(); } public boolean isReadResumed() { return resumed; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/BufferedStreamSinkConduit.java000066400000000000000000000153521257016060700302530ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.util.Arrays; import org.xnio.Buffers; import org.xnio.Pooled; import org.xnio.channels.StreamSourceChannel; /** * A stream sink conduit that buffers output data. * * @author David M. Lloyd */ public final class BufferedStreamSinkConduit extends AbstractStreamSinkConduit { private final Pooled pooledBuffer; private boolean terminate; /** * Construct a new instance. * * @param next the delegate conduit to set * @param pooledBuffer the pooled buffer to use */ public BufferedStreamSinkConduit(final StreamSinkConduit next, final Pooled pooledBuffer) { super(next); this.pooledBuffer = pooledBuffer; } public long transferFrom(final FileChannel src, final long position, final long count) throws IOException { return flushLocal() ? super.transferFrom(src, position, count) : 0L; } public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { // todo: optimize to include our buffer in the copies if (flushLocal()) { return super.transferFrom(source, count, throughBuffer); } else { throughBuffer.limit(0); return 0L; } } public int write(final ByteBuffer src) throws IOException { try { final ByteBuffer buffer = pooledBuffer.getResource(); final int pos = buffer.position(); final int lim = buffer.limit(); final int srcRem = src.remaining(); final int ourRem = lim - pos; if (srcRem < ourRem) { buffer.put(src); return srcRem; } else if (buffer.position() == 0) { final int res = super.write(src); if (srcRem > res) { final int cnt = Buffers.copy(buffer, src); return res + cnt; } else { return res; } } else { buffer.flip(); try { super.write(new ByteBuffer[] { buffer, src }, 0, 2); } finally { buffer.compact(); } if (src.hasRemaining()) { Buffers.copy(buffer, src); } return srcRem - src.remaining(); } } catch (IllegalStateException ignored) { throw new ClosedChannelException(); } } public long write(final ByteBuffer[] srcs, final int offs, final int len) throws IOException { if (len == 0) { return 0L; } else if (len == 1) { return write(srcs[offs]); } else try { final ByteBuffer buffer = pooledBuffer.getResource(); final int pos = buffer.position(); final int lim = buffer.limit(); final long srcRem = Buffers.remaining(srcs, offs, len); final int ourRem = lim - pos; if (srcRem < ourRem) { for (int i = 0; i < len; i++) { buffer.put(srcs[i]); } return srcRem; } else if (buffer.position() == 0) { final long res = super.write(srcs, offs, len); if (srcRem > res) { final int cnt = Buffers.copy(buffer, srcs, offs, len); return res + cnt; } else { return res; } } else { buffer.flip(); try { final ByteBuffer[] buffers; if (offs > 0) { buffers = Arrays.copyOfRange(srcs, offs - 1, offs + len); } else { buffers = new ByteBuffer[len + 1]; System.arraycopy(srcs, offs, buffers, 1, len); } buffers[0] = buffer; super.write(buffers, 0, buffers.length); } finally { buffer.compact(); } Buffers.copy(buffer, srcs, offs, len); return srcRem - Buffers.remaining(srcs, offs, len); } } catch (IllegalStateException ignored) { throw new ClosedChannelException(); } } private boolean flushLocal() throws IOException { try { final ByteBuffer buffer = pooledBuffer.getResource(); if (buffer.position() > 0) { buffer.flip(); try { for (;;) { super.write(buffer); if (! buffer.hasRemaining()) { if (terminate) { pooledBuffer.free(); } return true; } } } finally { buffer.compact(); } } else { return true; } } catch (IllegalStateException ignored) { return true; } } @Override public int writeFinal(ByteBuffer src) throws IOException { //todo: non-naive implementations of this return Conduits.writeFinalBasic(this, src); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { //todo: non-naive implementations of this return Conduits.writeFinalBasic(this, srcs, offset, length); } public boolean flush() throws IOException { return flushLocal() && super.flush(); } public void truncateWrites() throws IOException { pooledBuffer.free(); super.truncateWrites(); } public void terminateWrites() throws IOException { terminate = true; super.terminateWrites(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/BufferedStreamSourceConduit.java000066400000000000000000000135601257016060700306060ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.Arrays; import org.xnio.Buffers; import org.xnio.Pooled; import org.xnio.channels.StreamSinkChannel; /** * A stream source conduit which buffers input. * * @author David M. Lloyd */ public final class BufferedStreamSourceConduit extends AbstractStreamSourceConduit { private final Pooled pooledBuffer; /** * Construct a new instance. * * @param next the delegate conduit to set * @param pooledBuffer the buffer to use */ public BufferedStreamSourceConduit(final StreamSourceConduit next, final Pooled pooledBuffer) { super(next); this.pooledBuffer = pooledBuffer; } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { try { final ByteBuffer buffer = pooledBuffer.getResource(); final int lim = buffer.limit(); final int pos = buffer.position(); final int rem = lim - pos; if (rem > 0) { if ((long)rem > count) { buffer.limit(pos + (int)count); try { return target.write(buffer, position); } finally { buffer.limit(lim); } } else { return target.write(buffer, position); } } else { return super.transferTo(position, count, target); } } catch (IllegalStateException ignored) { return 0L; } } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { try { final ByteBuffer buffer = pooledBuffer.getResource(); int lim; int pos; int rem; lim = buffer.limit(); pos = buffer.position(); rem = lim - pos; throughBuffer.clear(); int res; long t = 0L; while (rem > 0) { if ((long)rem > count) { buffer.limit(pos + (int)count); try { t += res = target.write(buffer); } finally { buffer.limit(lim); } } else { t += res = target.write(buffer); } if (res == 0) { return t; } pos = buffer.position(); rem = lim - pos; } final long lres = Conduits.transfer(next, count, throughBuffer, target); if (lres > 0) t += lres; return t == 0L && lres == -1L ? -1L : t; } catch (IllegalStateException ignored) { return -1L; } } public int read(final ByteBuffer dst) throws IOException { try { final ByteBuffer buffer = pooledBuffer.getResource(); final int lim = buffer.limit(); final int pos = buffer.position(); final int rem = lim - pos; if (rem > 0) { return Buffers.copy(dst, buffer); } else { final int dstRem = dst.remaining(); buffer.clear(); try { final long rres = next.read(new ByteBuffer[] { dst, buffer }, 0, 2); if (rres == -1L) { return -1; } } finally { buffer.flip(); } return dst.remaining() - dstRem; } } catch (IllegalStateException ignored) { return -1; } } public long read(final ByteBuffer[] dsts, final int offs, final int len) throws IOException { if (len == 0) { return 0L; } else if (len == 1) { return read(dsts[offs]); } else try { final ByteBuffer buffer = pooledBuffer.getResource(); final int lim = buffer.limit(); final int pos = buffer.position(); final int rem = lim - pos; if (rem > 0) { return Buffers.copy(dsts, offs, len, buffer); } else { final long dstRem = Buffers.remaining(dsts, offs, len); buffer.clear(); try { final ByteBuffer[] buffers = Arrays.copyOfRange(dsts, offs, offs + len + 1); buffers[buffers.length - 1] = buffer; final long rres = next.read(buffers, 0, buffers.length); if (rres == -1) { return -1L; } } finally { buffer.flip(); } return Buffers.remaining(dsts, offs, len) - dstRem; } } catch (IllegalStateException ignored) { return -1; } } public void terminateReads() throws IOException { pooledBuffer.free(); super.terminateReads(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/Conduit.java000066400000000000000000000020661257016060700246050ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import org.xnio.XnioWorker; /** * A conduit, or stage which data transfer is processed by or provided by. * * @author David M. Lloyd */ public interface Conduit { /** * Get the XNIO worker associated with this conduit. * * @return the XNIO worker associated with this conduit */ XnioWorker getWorker(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/ConduitReadableByteChannel.java000066400000000000000000000027741257016060700303500ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ReadableByteChannel; /** * A byte channel which wraps a conduit. * * @author David M. Lloyd */ public final class ConduitReadableByteChannel implements ReadableByteChannel { private StreamSourceConduit conduit; /** * Construct a new instance. * * @param conduit the conduit to delegate to */ public ConduitReadableByteChannel(final StreamSourceConduit conduit) { this.conduit = conduit; } public int read(final ByteBuffer dst) throws IOException { return conduit.read(dst); } public boolean isOpen() { return ! conduit.isReadShutdown(); } public void close() throws IOException { conduit.terminateReads(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/ConduitReadableMessageChannel.java000066400000000000000000000134331257016060700310230ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.util.concurrent.TimeUnit; import org.xnio.ChannelListener; import org.xnio.Option; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.CloseListenerSettable; import org.xnio.channels.Configurable; import org.xnio.channels.ReadListenerSettable; import org.xnio.channels.ReadableMessageChannel; /** * A readable message channel which is backed by a message source conduit. * * @author David M. Lloyd */ public final class ConduitReadableMessageChannel implements ReadableMessageChannel, ReadListenerSettable, CloseListenerSettable, Cloneable { private final Configurable configurable; private MessageSourceConduit conduit; private ChannelListener readListener; private ChannelListener closeListener; /** * Construct a new instance. * * @param configurable the configurable to delegate configuration requests to * @param conduit the initial conduit to use for data transport */ public ConduitReadableMessageChannel(final Configurable configurable, final MessageSourceConduit conduit) { this.configurable = configurable; this.conduit = conduit; conduit.setReadReadyHandler(new ReadReadyHandler.ChannelListenerHandler(this)); } /** * Get the underlying conduit for this channel. * * @return the underlying conduit for this channel */ public MessageSourceConduit getConduit() { return conduit; } /** * Set the underlying conduit for this channel. * * @param conduit the underlying conduit for this channel */ public void setConduit(final MessageSourceConduit conduit) { this.conduit = conduit; } public boolean isOpen() { return ! conduit.isReadShutdown(); } public void setReadListener(final ChannelListener readListener) { this.readListener = readListener; } public ChannelListener getReadListener() { return readListener; } public void setCloseListener(final ChannelListener closeListener) { this.closeListener = closeListener; } public ChannelListener getCloseListener() { return closeListener; } public ChannelListener.Setter getReadSetter() { return new ReadListenerSettable.Setter(this); } public ChannelListener.Setter getCloseSetter() { return new CloseListenerSettable.Setter(this); } public XnioWorker getWorker() { return conduit.getWorker(); } public long receive(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { return conduit.receive(dsts, offset, length); } public long receive(final ByteBuffer[] dsts) throws IOException { return conduit.receive(dsts, 0, dsts.length); } public int receive(final ByteBuffer dst) throws IOException { return conduit.receive(dst); } public void suspendReads() { conduit.suspendReads(); } public void resumeReads() { conduit.resumeReads(); } public boolean isReadResumed() { return conduit.isReadResumed(); } public void wakeupReads() { conduit.wakeupReads(); } public void shutdownReads() throws IOException { conduit.terminateReads(); } public void awaitReadable() throws IOException { conduit.awaitReadable(); } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { conduit.awaitReadable(time, timeUnit); } @Deprecated public XnioExecutor getReadThread() { return conduit.getReadThread(); } public XnioIoThread getIoThread() { return conduit.getReadThread(); } public void close() throws IOException { conduit.terminateReads(); } public boolean supportsOption(final Option option) { return configurable.supportsOption(option); } public T getOption(final Option option) throws IOException { return configurable.getOption(option); } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return configurable.setOption(option, value); } /** * Duplicate this channel. Changing the delegate conduit in one channel will not affect the other. * * @return the cloned channel */ public ConduitReadableMessageChannel clone() { try { return (ConduitReadableMessageChannel) super.clone(); } catch (CloneNotSupportedException e) { throw new IllegalStateException(e); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/ConduitStreamSinkChannel.java000066400000000000000000000152111257016060700300730ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import org.xnio.ChannelListener; import org.xnio.Option; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.CloseListenerSettable; import org.xnio.channels.Configurable; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; import org.xnio.channels.WriteListenerSettable; /** * A stream sink channel which wraps a stream sink conduit. * * @author David M. Lloyd */ public final class ConduitStreamSinkChannel implements StreamSinkChannel, WriteListenerSettable, CloseListenerSettable, Cloneable { private final Configurable configurable; private StreamSinkConduit conduit; private ChannelListener writeListener; private ChannelListener closeListener; /** * Construct a new instance. * * @param configurable the configurable to delegate configuration requests to * @param conduit the initial conduit to use for data transport */ public ConduitStreamSinkChannel(final Configurable configurable, final StreamSinkConduit conduit) { this.configurable = configurable; this.conduit = conduit; conduit.setWriteReadyHandler(new WriteReadyHandler.ChannelListenerHandler(this)); } /** * Get the underlying conduit for this channel. * * @return the underlying conduit for this channel */ public StreamSinkConduit getConduit() { return conduit; } /** * Set the underlying conduit for this channel. * * @param conduit the underlying conduit for this channel */ public void setConduit(final StreamSinkConduit conduit) { this.conduit = conduit; } public ChannelListener getWriteListener() { return writeListener; } public void setWriteListener(final ChannelListener writeListener) { this.writeListener = writeListener; } public ChannelListener getCloseListener() { return closeListener; } public void setCloseListener(final ChannelListener closeListener) { this.closeListener = closeListener; } public ChannelListener.Setter getWriteSetter() { return new WriteListenerSettable.Setter(this); } public ChannelListener.Setter getCloseSetter() { return new CloseListenerSettable.Setter(this); } @Override public int writeFinal(ByteBuffer src) throws IOException { return conduit.writeFinal(src); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { return conduit.writeFinal(srcs, offset, length); } @Override public long writeFinal(ByteBuffer[] srcs) throws IOException { return conduit.writeFinal(srcs, 0, srcs.length); } public void suspendWrites() { conduit.suspendWrites(); } public void resumeWrites() { conduit.resumeWrites(); } public void wakeupWrites() { conduit.wakeupWrites(); } public boolean isWriteResumed() { return conduit.isWriteResumed(); } public void awaitWritable() throws IOException { conduit.awaitWritable(); } public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException { conduit.awaitWritable(time, timeUnit); } public long transferFrom(final FileChannel src, final long position, final long count) throws IOException { return conduit.transferFrom(src, position, count); } public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { return conduit.transferFrom(source, count, throughBuffer); } public int write(final ByteBuffer dst) throws IOException { return conduit.write(dst); } public long write(final ByteBuffer[] srcs) throws IOException { return conduit.write(srcs, 0, srcs.length); } public long write(final ByteBuffer[] dsts, final int offs, final int len) throws IOException { return conduit.write(dsts, offs, len); } public boolean flush() throws IOException { return conduit.flush(); } public boolean supportsOption(final Option option) { return configurable.supportsOption(option); } public T getOption(final Option option) throws IOException { return configurable.getOption(option); } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return configurable.setOption(option, value); } public void shutdownWrites() throws IOException { conduit.terminateWrites(); } public boolean isOpen() { return ! conduit.isWriteShutdown(); } public void close() throws IOException { conduit.truncateWrites(); } @Deprecated public XnioExecutor getWriteThread() { return conduit.getWriteThread(); } public XnioIoThread getIoThread() { return conduit.getWriteThread(); } public XnioWorker getWorker() { return conduit.getWorker(); } /** * Duplicate this channel. Changing the delegate conduit in one channel will not affect the other. * * @return the cloned channel */ public ConduitStreamSinkChannel clone() { try { return (ConduitStreamSinkChannel) super.clone(); } catch (CloneNotSupportedException e) { throw new IllegalStateException(e); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/ConduitStreamSourceChannel.java000066400000000000000000000142211257016060700304270ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import org.xnio.ChannelListener; import org.xnio.Option; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.CloseListenerSettable; import org.xnio.channels.Configurable; import org.xnio.channels.ReadListenerSettable; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; /** * A stream source channel which wraps a stream source conduit. * * @author David M. Lloyd */ public final class ConduitStreamSourceChannel implements StreamSourceChannel, ReadListenerSettable, CloseListenerSettable, Cloneable { private final Configurable configurable; private StreamSourceConduit conduit; private ChannelListener readListener; private ChannelListener closeListener; /** * Construct a new instance. * * @param configurable the configurable to delegate configuration requests to * @param conduit the initial conduit to use for data transport */ public ConduitStreamSourceChannel(final Configurable configurable, final StreamSourceConduit conduit) { this.configurable = configurable; this.conduit = conduit; conduit.setReadReadyHandler(new ReadReadyHandler.ChannelListenerHandler(this)); } /** * Get the underlying conduit for this channel. * * @return the underlying conduit for this channel */ public StreamSourceConduit getConduit() { return conduit; } /** * Set the underlying conduit for this channel. * * @param conduit the underlying conduit for this channel */ public void setConduit(final StreamSourceConduit conduit) { this.conduit = conduit; } public boolean isOpen() { return ! conduit.isReadShutdown(); } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { return conduit.transferTo(position, count, target); } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { return conduit.transferTo(count, throughBuffer, target); } public void setReadListener(final ChannelListener readListener) { this.readListener = readListener; } public ChannelListener getReadListener() { return readListener; } public void setCloseListener(final ChannelListener closeListener) { this.closeListener = closeListener; } public ChannelListener getCloseListener() { return closeListener; } public ChannelListener.Setter getReadSetter() { return new ReadListenerSettable.Setter(this); } public ChannelListener.Setter getCloseSetter() { return new CloseListenerSettable.Setter(this); } public XnioWorker getWorker() { return conduit.getWorker(); } public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { return conduit.read(dsts, offset, length); } public long read(final ByteBuffer[] dsts) throws IOException { return conduit.read(dsts, 0, dsts.length); } public int read(final ByteBuffer dst) throws IOException { return conduit.read(dst); } public void suspendReads() { conduit.suspendReads(); } public void resumeReads() { conduit.resumeReads(); } public boolean isReadResumed() { return conduit.isReadResumed(); } public void wakeupReads() { conduit.wakeupReads(); } public void shutdownReads() throws IOException { conduit.terminateReads(); } public void awaitReadable() throws IOException { conduit.awaitReadable(); } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { conduit.awaitReadable(time, timeUnit); } @Deprecated public XnioExecutor getReadThread() { return conduit.getReadThread(); } public XnioIoThread getIoThread() { return conduit.getReadThread(); } public void close() throws IOException { conduit.terminateReads(); } public boolean supportsOption(final Option option) { return configurable.supportsOption(option); } public T getOption(final Option option) throws IOException { return configurable.getOption(option); } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return configurable.setOption(option, value); } /** * Duplicate this channel. Changing the delegate conduit in one channel will not affect the other. * * @return the cloned channel */ public ConduitStreamSourceChannel clone() { try { return (ConduitStreamSourceChannel) super.clone(); } catch (CloneNotSupportedException e) { throw new IllegalStateException(e); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/ConduitWritableByteChannel.java000066400000000000000000000027731257016060700304210ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.WritableByteChannel; /** * A byte channel which wraps a conduit. * * @author David M. Lloyd */ public final class ConduitWritableByteChannel implements WritableByteChannel { private StreamSinkConduit conduit; /** * Construct a new instance. * * @param conduit the conduit to delegate to */ public ConduitWritableByteChannel(final StreamSinkConduit conduit) { this.conduit = conduit; } public int write(final ByteBuffer src) throws IOException { return conduit.write(src); } public boolean isOpen() { return ! conduit.isWriteShutdown(); } public void close() throws IOException { conduit.truncateWrites(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/ConduitWritableMessageChannel.java000066400000000000000000000144661257016060700311040ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.util.concurrent.TimeUnit; import org.xnio.ChannelListener; import org.xnio.Option; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.CloseListenerSettable; import org.xnio.channels.Configurable; import org.xnio.channels.WritableMessageChannel; import org.xnio.channels.WriteListenerSettable; /** * A writable message channel which is backed by a message sink conduit. * * @author David M. Lloyd */ public final class ConduitWritableMessageChannel implements WritableMessageChannel, WriteListenerSettable, CloseListenerSettable, Cloneable { private final Configurable configurable; private MessageSinkConduit conduit; private ChannelListener writeListener; private ChannelListener closeListener; /** * Construct a new instance. * * @param configurable the configurable to delegate configuration requests to * @param conduit the initial conduit to use for data transport */ public ConduitWritableMessageChannel(final Configurable configurable, final MessageSinkConduit conduit) { this.configurable = configurable; this.conduit = conduit; conduit.setWriteReadyHandler(new WriteReadyHandler.ChannelListenerHandler(this)); } /** * Get the underlying conduit for this channel. * * @return the underlying conduit for this channel */ public MessageSinkConduit getConduit() { return conduit; } /** * Set the underlying conduit for this channel. * * @param conduit the underlying conduit for this channel */ public void setConduit(final MessageSinkConduit conduit) { this.conduit = conduit; } public ChannelListener getWriteListener() { return writeListener; } public void setWriteListener(final ChannelListener writeListener) { this.writeListener = writeListener; } public ChannelListener getCloseListener() { return closeListener; } public void setCloseListener(final ChannelListener closeListener) { this.closeListener = closeListener; } public ChannelListener.Setter getWriteSetter() { return new WriteListenerSettable.Setter(this); } public ChannelListener.Setter getCloseSetter() { return new CloseListenerSettable.Setter(this); } public void suspendWrites() { conduit.suspendWrites(); } public void resumeWrites() { conduit.resumeWrites(); } public void wakeupWrites() { conduit.wakeupWrites(); } public boolean isWriteResumed() { return conduit.isWriteResumed(); } public void awaitWritable() throws IOException { conduit.awaitWritable(); } public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException { conduit.awaitWritable(time, timeUnit); } public boolean send(final ByteBuffer dst) throws IOException { return conduit.send(dst); } public boolean send(final ByteBuffer[] srcs) throws IOException { return conduit.send(srcs, 0, srcs.length); } public boolean send(final ByteBuffer[] dsts, final int offs, final int len) throws IOException { return conduit.send(dsts, offs, len); } @Override public boolean sendFinal(ByteBuffer buffer) throws IOException { return conduit.sendFinal(buffer); } @Override public boolean sendFinal(ByteBuffer[] buffers) throws IOException { return conduit.sendFinal(buffers, 0, buffers.length); } @Override public boolean sendFinal(ByteBuffer[] buffers, int offs, int len) throws IOException { return conduit.sendFinal(buffers, offs, len); } public boolean flush() throws IOException { return conduit.flush(); } public boolean supportsOption(final Option option) { return configurable.supportsOption(option); } public T getOption(final Option option) throws IOException { return configurable.getOption(option); } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return configurable.setOption(option, value); } public void shutdownWrites() throws IOException { conduit.terminateWrites(); } public boolean isOpen() { return ! conduit.isWriteShutdown(); } public void close() throws IOException { conduit.truncateWrites(); } @Deprecated public XnioExecutor getWriteThread() { return conduit.getWriteThread(); } public XnioIoThread getIoThread() { return conduit.getWriteThread(); } public XnioWorker getWorker() { return conduit.getWorker(); } /** * Duplicate this channel. Changing the delegate conduit in one channel will not affect the other. * * @return the cloned channel */ public ConduitWritableMessageChannel clone() { try { return (ConduitWritableMessageChannel) super.clone(); } catch (CloneNotSupportedException e) { throw new IllegalStateException(e); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/Conduits.java000066400000000000000000000227641257016060700247770ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import org.xnio.Buffers; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOError; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.Locale; /** * General utility methods for manipulating conduits. * * @author David M. Lloyd */ public final class Conduits { /** * Platform-independent channel-to-channel transfer method. Uses regular {@code read} and {@code write} operations * to move bytes from the {@code source} channel to the {@code sink} channel. After this call, the {@code throughBuffer} * should be checked for remaining bytes; if there are any, they should be written to the {@code sink} channel before * proceeding. This method may be used with NIO channels, XNIO channels, or a combination of the two. *

* If either or both of the given channels are blocking channels, then this method may block. * * @param source the source channel to read bytes from * @param count the number of bytes to transfer (must be >= {@code 0L}) * @param throughBuffer the buffer to transfer through (must not be {@code null}) * @param sink the sink channel to write bytes to * @return the number of bytes actually transferred (possibly 0) * @throws java.io.IOException if an I/O error occurs during the transfer of bytes */ public static long transfer(final StreamSourceConduit source, final long count, final ByteBuffer throughBuffer, final WritableByteChannel sink) throws IOException { long res; long total = 0L; throughBuffer.limit(0); while (total < count) { throughBuffer.compact(); try { if (count - total < (long) throughBuffer.remaining()) { throughBuffer.limit((int) (count - total)); } res = source.read(throughBuffer); if (res <= 0) { return total == 0L ? res : total; } } finally { throughBuffer.flip(); } res = sink.write(throughBuffer); if (res == 0) { return total; } total += res; } return total; } /** * Platform-independent channel-to-channel transfer method. Uses regular {@code read} and {@code write} operations * to move bytes from the {@code source} channel to the {@code sink} channel. After this call, the {@code throughBuffer} * should be checked for remaining bytes; if there are any, they should be written to the {@code sink} channel before * proceeding. This method may be used with NIO channels, XNIO channels, or a combination of the two. *

* If either or both of the given channels are blocking channels, then this method may block. * * @param source the source channel to read bytes from * @param count the number of bytes to transfer (must be >= {@code 0L}) * @param throughBuffer the buffer to transfer through (must not be {@code null}) * @param sink the sink channel to write bytes to * @return the number of bytes actually transferred (possibly 0) * @throws java.io.IOException if an I/O error occurs during the transfer of bytes */ public static long transfer(final ReadableByteChannel source, final long count, final ByteBuffer throughBuffer, final StreamSinkConduit sink) throws IOException { long res; long total = 0L; throughBuffer.limit(0); while (total < count) { throughBuffer.compact(); try { if (count - total < (long) throughBuffer.remaining()) { throughBuffer.limit((int) (count - total)); } res = source.read(throughBuffer); if (res <= 0) { return total == 0L ? res : total; } } finally { throughBuffer.flip(); } res = sink.write(throughBuffer); if (res == 0) { return total; } total += res; } return total; } /** * Writes the buffer to the conduit, and terminates writes if all the data is written * @param conduit The conduit to write to * @param src The data to write * @return The number of bytes written * @throws IOException */ public static int writeFinalBasic(StreamSinkConduit conduit, ByteBuffer src) throws IOException { int res = conduit.write(src); if(!src.hasRemaining()) { conduit.terminateWrites(); } return res; } /** * Writes the buffer to the conduit, and terminates writes if all the data is written * @param conduit The conduit to write to * @param srcs The data to write * @param offset The offset into the data array * @param length The number of buffers to write * @return The number of bytes written * @throws IOException */ public static long writeFinalBasic(StreamSinkConduit conduit, ByteBuffer[] srcs, int offset, int length) throws IOException { final long res = conduit.write(srcs, offset, length); if (!Buffers.hasRemaining(srcs, offset, length)) { conduit.terminateWrites(); } return res; } /** * Writes a message to the conduit, and terminates writes if the send was successfully. * @param conduit The conduit * @param src The message buffer * @return true if the message was sent successfully */ public static boolean sendFinalBasic(MessageSinkConduit conduit, ByteBuffer src) throws IOException { if(conduit.send(src)) { conduit.terminateWrites(); return true; } return false; } /** * Writes a message to the conduit, and terminates writes if the send was successfully. * @param conduit The conduit * @param srcs The message buffers * @param offset The offset in the message buffers * @param length The number of buffers to send * @return true if the message was sent successfully */ public static boolean sendFinalBasic(MessageSinkConduit conduit, ByteBuffer[] srcs, int offset, int length) throws IOException { if(conduit.send(srcs, offset, length)) { conduit.terminateWrites(); return true; } return false; } private static final FileChannel NULL_FILE_CHANNEL; private static final ByteBuffer DRAIN_BUFFER = ByteBuffer.allocateDirect(16384); /** * Attempt to drain the given number of bytes from the stream source conduit. * * @param conduit the conduit to drain * @param count the number of bytes * @return the number of bytes drained, 0 if reading the conduit would block, or -1 if the EOF was reached * @throws IOException if an error occurs */ public static long drain(StreamSourceConduit conduit, long count) throws IOException { long total = 0L, lres; int ires; ByteBuffer buffer = null; for (;;) { if (count == 0L) return total; if (NULL_FILE_CHANNEL != null) { while (count > 0) { if ((lres = conduit.transferTo(0, count, NULL_FILE_CHANNEL)) == 0L) { break; } total += lres; count -= lres; } // jump out quick if we drained the fast way if (total > 0L) return total; } if (buffer == null) buffer = DRAIN_BUFFER.duplicate(); if ((long) buffer.limit() > count) buffer.limit((int) count); ires = conduit.read(buffer); buffer.clear(); switch (ires) { case -1: return total == 0L ? -1L : total; case 0: return total; default: total += (long) ires; } } } static { NULL_FILE_CHANNEL = AccessController.doPrivileged(new PrivilegedAction() { public FileChannel run() { final String osName = System.getProperty("os.name", "unknown").toLowerCase(Locale.US); try { if (osName.contains("windows")) { return new FileOutputStream("NUL:").getChannel(); } else { return new FileOutputStream("/dev/null").getChannel(); } } catch (FileNotFoundException e) { throw new IOError(e); } } }); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/DeflatingStreamSinkConduit.java000066400000000000000000000174011257016060700304230ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import static org.xnio._private.Messages.msg; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.zip.Deflater; import org.xnio.Buffers; import org.xnio.channels.StreamSourceChannel; /** * A filtering stream sink conduit which compresses the written data. * * @author David M. Lloyd */ public final class DeflatingStreamSinkConduit extends AbstractStreamSinkConduit implements StreamSinkConduit { private static final byte[] NO_BYTES = new byte[0]; private final Deflater deflater; private final ByteBuffer outBuffer; /** * Construct a new instance. * * @param next the delegate conduit to set * @param deflater the initialized deflater to use */ public DeflatingStreamSinkConduit(final StreamSinkConduit next, final Deflater deflater) { super(next); this.deflater = deflater; outBuffer = ByteBuffer.allocate(16384); } public long transferFrom(final FileChannel src, final long position, final long count) throws IOException { return src.transferTo(position, count, new ConduitWritableByteChannel(this)); } public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { return Conduits.transfer(source, count, throughBuffer, this); } public int write(final ByteBuffer src) throws IOException { final ByteBuffer outBuffer = this.outBuffer; final byte[] outArray = outBuffer.array(); final Deflater deflater = this.deflater; assert outBuffer.arrayOffset() == 0; int cnt = 0; int rem; int c1, t; int pos; while ((rem = src.remaining()) > 0) { if (! outBuffer.hasRemaining()) { outBuffer.flip(); try { if (next.write(outBuffer) == 0) { return cnt; } } finally { outBuffer.compact(); } } pos = src.position(); if (src.hasArray()) { final byte[] array = src.array(); final int arrayOffset = src.arrayOffset(); deflater.setInput(array, arrayOffset + pos, rem); c1 = deflater.getTotalIn(); final int dc = deflater.deflate(outArray, outBuffer.position(), outBuffer.remaining()); outBuffer.position(outBuffer.position() + dc); t = deflater.getTotalIn() - c1; src.position(pos + t); cnt += t; } else { final byte[] bytes = Buffers.take(src); deflater.setInput(bytes); c1 = deflater.getTotalIn(); final int dc = deflater.deflate(outArray, outBuffer.position(), outBuffer.remaining()); outBuffer.position(outBuffer.position() + dc); t = deflater.getTotalIn() - c1; src.position(pos + t); cnt += t; } } return cnt; } public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException { final ByteBuffer outBuffer = this.outBuffer; final byte[] outArray = outBuffer.array(); final Deflater deflater = this.deflater; assert outBuffer.arrayOffset() == 0; long cnt = 0; int rem; int c1, t; int pos; for (int i = 0; i < length; i ++) { final ByteBuffer src = srcs[i + offset]; while ((rem = src.remaining()) > 0) { if (! outBuffer.hasRemaining()) { outBuffer.flip(); try { if (next.write(outBuffer) == 0) { return cnt; } } finally { outBuffer.compact(); } } pos = src.position(); if (src.hasArray()) { final byte[] array = src.array(); final int arrayOffset = src.arrayOffset(); deflater.setInput(array, arrayOffset + pos, rem); c1 = deflater.getTotalIn(); final int dc = deflater.deflate(outArray, outBuffer.position(), outBuffer.remaining()); outBuffer.position(outBuffer.position() + dc); t = deflater.getTotalIn() - c1; src.position(pos + t); cnt += t; } else { final byte[] bytes = Buffers.take(src); deflater.setInput(bytes); c1 = deflater.getTotalIn(); final int dc = deflater.deflate(outArray, outBuffer.position(), outBuffer.remaining()); outBuffer.position(outBuffer.position() + dc); t = deflater.getTotalIn() - c1; src.position(pos + t); cnt += t; } } } return cnt; } public boolean flush() throws IOException { final ByteBuffer outBuffer = this.outBuffer; final byte[] outArray = outBuffer.array(); final Deflater deflater = this.deflater; assert outBuffer.arrayOffset() == 0; int res; int rem; int pos; deflater.setInput(NO_BYTES); for (;;) { rem = outBuffer.remaining(); pos = outBuffer.position(); res = deflater.deflate(outArray, pos, rem, Deflater.SYNC_FLUSH); if (pos == 0 && res == rem) { // hmm, we're stuck (shouldn't be possible) throw msg.flushSmallBuffer(); } else { if (res > 0) { outBuffer.flip(); try { if (next.write(outBuffer) == 0) { return false; } } finally { outBuffer.compact(); } } else if (deflater.needsInput() && pos == 0) { if (deflater.finished()) { // idempotent next.terminateWrites(); } return next.flush(); } else { throw msg.deflaterState(); } } } } @Override public int writeFinal(ByteBuffer src) throws IOException { //todo: non-naive implementations of this return Conduits.writeFinalBasic(this, src); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { //todo: non-naive implementations of this return Conduits.writeFinalBasic(this, srcs, offset, length); } public void terminateWrites() throws IOException { deflater.finish(); } public void truncateWrites() throws IOException { deflater.finish(); next.truncateWrites(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/EmptyStreamSourceConduit.java000066400000000000000000000065231257016060700301630ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.StreamSinkChannel; /** * A stream source conduit which is always empty. * * @author David M. Lloyd */ public final class EmptyStreamSourceConduit implements StreamSourceConduit { private final XnioWorker worker; private final XnioIoThread readThread; private ReadReadyHandler readReadyHandler; private boolean shutdown; private boolean resumed; /** * Construct a new instance. * * @param readThread the read thread for this conduit */ public EmptyStreamSourceConduit(final XnioIoThread readThread) { this.worker = readThread.getWorker(); this.readThread = readThread; } public void setReadReadyHandler(final ReadReadyHandler handler) { readReadyHandler = handler; } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { return 0; } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { resumed = false; return -1L; } public int read(final ByteBuffer dst) throws IOException { resumed = false; return -1; } public long read(final ByteBuffer[] dsts, final int offs, final int len) throws IOException { resumed = false; return -1L; } public boolean isReadShutdown() { return shutdown; } public void resumeReads() { resumed = true; readThread.execute(new Runnable() { public void run() { final ReadReadyHandler handler = readReadyHandler; if (handler != null) { handler.readReady(); } } }); } public void suspendReads() { resumed = false; } public void wakeupReads() { resumeReads(); } public boolean isReadResumed() { return resumed; } public void awaitReadable() throws IOException { // always ready } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { // always ready } public void terminateReads() throws IOException { if (! shutdown) { shutdown = true; readReadyHandler.terminated(); } } public XnioIoThread getReadThread() { return readThread; } public XnioWorker getWorker() { return worker; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/FixedLengthStreamSinkConduit.java000066400000000000000000000147431257016060700307350ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import org.xnio.channels.FixedLengthOverflowException; import org.xnio.channels.FixedLengthUnderflowException; import org.xnio.channels.StreamSourceChannel; import static java.lang.Math.min; import static org.xnio._private.Messages.msg; /** * A stream sink conduit with a limited length. * * @author David M. Lloyd */ public final class FixedLengthStreamSinkConduit extends AbstractStreamSinkConduit implements StreamSinkConduit { private long remaining; /** * Construct a new instance. * * @param next the delegate conduit to set */ public FixedLengthStreamSinkConduit(final FixedLengthStreamSinkConduit next) { super(next); } public long transferFrom(final FileChannel src, final long position, final long count) throws IOException { if (count == 0L) return 0L; final long remaining = this.remaining; if (remaining == 0L) { throw msg.fixedOverflow(); } long res = 0L; try { return res = next.transferFrom(src, position, min(count, remaining)); } finally { this.remaining = remaining - res; } } public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { if (count == 0L) return 0L; final long remaining = this.remaining; if (remaining == 0L) { throw msg.fixedOverflow(); } long res = 0L; try { return res = next.transferFrom(source, min(count, remaining), throughBuffer); } finally { this.remaining = remaining - res; } } @Override public int writeFinal(ByteBuffer src) throws IOException { return write(src, true); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { return write(srcs, offset, length, true); } @Override public int write(final ByteBuffer src) throws IOException { return write(src, false); } @Override public long write(final ByteBuffer[] srcs, final int offs, final int len) throws IOException { return write(srcs, offs, len, false); } private int write(final ByteBuffer src, final boolean writeFinal) throws IOException { if (! src.hasRemaining()) { return 0; } int res = 0; final long remaining = this.remaining; if (remaining == 0L) { throw msg.fixedOverflow(); } try { final int lim = src.limit(); final int pos = src.position(); if (lim - pos > remaining) { src.limit((int) (remaining - (long) pos)); try { return res = doWrite(src, writeFinal); } finally { src.limit(lim); } } else { return res = doWrite(src, writeFinal); } } finally { this.remaining = remaining - res; } } private long write(final ByteBuffer[] srcs, final int offs, final int len, boolean writeFinal) throws IOException { if (len == 0) { return 0L; } else if (len == 1) { return write(srcs[offs], writeFinal); } final long remaining = this.remaining; if (remaining == 0L) { throw msg.fixedOverflow(); } long res = 0L; try { int lim; // The total amount of buffer space discovered so far. long t = 0L; for (int i = 0; i < len; i ++) { final ByteBuffer buffer = srcs[i + offs]; // Grow the discovered buffer space by the remaining size of the current buffer. // We want to capture the limit so we calculate "remaining" ourselves. t += (lim = buffer.limit()) - buffer.position(); if (t > remaining) { // only read up to this point, and trim the last buffer by the number of extra bytes buffer.limit(lim - (int) (t - (remaining))); try { return res = doWrite(srcs, offs, i + 1, writeFinal); } finally { // restore the original limit buffer.limit(lim); } } } if (t == 0L) { return 0L; } // the total buffer space is less than the remaining count. return res = doWrite(srcs, offs, len, writeFinal); } finally { this.remaining = remaining - res; } } private long doWrite(ByteBuffer[] srcs, int offs, int len, boolean writeFinal) throws IOException { if(writeFinal) { return next.writeFinal(srcs, offs, len); } else { return next.write(srcs, offs, len); } } private int doWrite(ByteBuffer src, boolean writeFinal) throws IOException { if(writeFinal) { return next.writeFinal(src); } else { return next.write(src); } } public void terminateWrites() throws IOException { next.terminateWrites(); if (remaining > 0L) { throw msg.fixedOverflow(); } } public void truncateWrites() throws IOException { next.terminateWrites(); if (remaining > 0L) { throw msg.fixedOverflow(); } } /** * Get the number of remaining bytes available to read. * * @return the number of remaining bytes available to read */ public long getRemaining() { return remaining; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/FixedLengthStreamSourceConduit.java000066400000000000000000000112731257016060700312640ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import org.xnio.channels.StreamSinkChannel; /** * A stream source conduit which limits the length of input. * * @author David M. Lloyd */ public final class FixedLengthStreamSourceConduit extends AbstractStreamSourceConduit implements StreamSourceConduit { private long remaining; /** * Construct a new instance. * * @param next the conduit to limit * @param remaining the number of bytes to limit to */ public FixedLengthStreamSourceConduit(final StreamSourceConduit next, final long remaining) { super(next); this.remaining = remaining; } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { long length = this.remaining; if (length > 0) { final long res = next.transferTo(position, Math.min(count, length), target); if (res > 0L) { this.remaining = length - res; } return res; } else { return 0; } } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { long length = this.remaining; if (length > 0) { final long res = next.transferTo(Math.min(count, length), throughBuffer, target); if (res > 0L) { this.remaining = length - res; } return res; } else { return -1L; } } public int read(final ByteBuffer dst) throws IOException { final int limit = dst.limit(); final int pos = dst.position(); final int res; final long length = this.remaining; if (length == 0L) { return -1; } if (limit - pos > length) { dst.limit(pos + (int) length); try { res = next.read(dst); } finally { dst.limit(limit); } } else { res = next.read(dst); } if (res > 0L) { this.remaining = length - res; } return res; } public long read(final ByteBuffer[] dsts, final int offs, final int len) throws IOException { if (len == 0) { return 0L; } else if (len == 1) { return read(dsts[offs]); } final long length = this.remaining; if (length == 0L) { return -1L; } long res; int lim; // The total amount of buffer space discovered so far. long t = 0L; for (int i = 0; i < length; i ++) { final ByteBuffer buffer = dsts[i + offs]; // Grow the discovered buffer space by the remaining size of the current buffer. // We want to capture the limit so we calculate "remaining" ourselves. t += (lim = buffer.limit()) - buffer.position(); if (t > length) { // only read up to this point, and trim the last buffer by the number of extra bytes buffer.limit(lim - (int) (t - length)); try { res = next.read(dsts, offs, i + 1); if (res > 0L) { this.remaining = length - res; } return res; } finally { // restore the original limit buffer.limit(lim); } } } // the total buffer space is less than the remaining count. res = t == 0L ? 0L : next.read(dsts, offs, len); if (res > 0L) { this.remaining = length - res; } return res; } /** * Get the number of bytes which remain available to read. * * @return the number of bytes which remain available to read */ public long getRemaining() { return remaining; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/FramingMessageSinkConduit.java000066400000000000000000000114731257016060700302450ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import static org.xnio._private.Messages.msg; import java.io.IOException; import java.nio.ByteBuffer; import org.xnio.Buffers; import org.xnio.Pooled; /** * A message sink conduit which implements a simple message framing protocol over a stream conduit. * * @author David M. Lloyd */ public final class FramingMessageSinkConduit extends AbstractSinkConduit implements MessageSinkConduit { private final boolean longLengths; private final Pooled transmitBuffer; /** * Construct a new instance. * * @param next the delegate conduit to set * @param longLengths {@code true} to use 4-byte lengths, {@code false} to use 2-byte lengths * @param transmitBuffer the transmit buffer to use */ public FramingMessageSinkConduit(final StreamSinkConduit next, final boolean longLengths, final Pooled transmitBuffer) { super(next); this.longLengths = longLengths; this.transmitBuffer = transmitBuffer; } public boolean send(final ByteBuffer src) throws IOException { if (!src.hasRemaining()) { // no zero messages return false; } final ByteBuffer transmitBuffer = this.transmitBuffer.getResource(); final int remaining = src.remaining(); final boolean longLengths = this.longLengths; final int lengthFieldSize = longLengths ? 4 : 2; if (remaining > transmitBuffer.capacity() - lengthFieldSize || ! longLengths && remaining > 65535) { throw msg.txMsgTooLarge(); } if (transmitBuffer.remaining() < lengthFieldSize + remaining && ! writeBuffer()) { return false; } if (longLengths) { transmitBuffer.putInt(remaining); } else { transmitBuffer.putShort((short) remaining); } transmitBuffer.put(src); writeBuffer(); return true; } public boolean send(final ByteBuffer[] srcs, final int offs, final int len) throws IOException { if (len == 1) { return send(srcs[offs]); } else if (! Buffers.hasRemaining(srcs, offs, len)) { return false; } final ByteBuffer transmitBuffer = this.transmitBuffer.getResource(); final long remaining = Buffers.remaining(srcs, offs, len); final boolean longLengths = this.longLengths; final int lengthFieldSize = longLengths ? 4 : 2; if (remaining > transmitBuffer.capacity() - lengthFieldSize || ! longLengths && remaining > 65535) { throw msg.txMsgTooLarge(); } if (transmitBuffer.remaining() < lengthFieldSize + remaining && ! writeBuffer()) { return false; } if (longLengths) { transmitBuffer.putInt((int) remaining); } else { transmitBuffer.putShort((short) remaining); } Buffers.copy(transmitBuffer, srcs, offs, len); writeBuffer(); return true; } @Override public boolean sendFinal(ByteBuffer src) throws IOException { //TODO: non-naive implementation return Conduits.sendFinalBasic(this, src); } @Override public boolean sendFinal(ByteBuffer[] srcs, int offs, int len) throws IOException { return Conduits.sendFinalBasic(this, srcs, offs, len); } private boolean writeBuffer() throws IOException { final ByteBuffer buffer = transmitBuffer.getResource(); if (buffer.position() > 0) buffer.flip(); try { while (buffer.hasRemaining()) { final int res = next.write(buffer); if (res == 0) { return false; } } return true; } finally { buffer.compact(); } } public boolean flush() throws IOException { return writeBuffer() && next.flush(); } public void terminateWrites() throws IOException { transmitBuffer.free(); next.terminateWrites(); } public void truncateWrites() throws IOException { transmitBuffer.free(); next.truncateWrites(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/FramingMessageSourceConduit.java000066400000000000000000000124221257016060700305740ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import static org.xnio._private.Messages.msg; import java.io.IOException; import java.nio.ByteBuffer; import java.util.concurrent.TimeUnit; import org.xnio.Buffers; import org.xnio.Pooled; /** * A message source conduit which implements a simple message framing protocol over a stream conduit. * * @author David M. Lloyd */ public final class FramingMessageSourceConduit extends AbstractSourceConduit implements MessageSourceConduit { private final Pooled receiveBuffer; private boolean ready; /** * Construct a new instance. * * @param next the delegate conduit to set * @param receiveBuffer the transmit buffer to use */ public FramingMessageSourceConduit(final StreamSourceConduit next, final Pooled receiveBuffer) { super(next); this.receiveBuffer = receiveBuffer; } public void resumeReads() { if (ready) next.wakeupReads(); else next.resumeReads(); } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { if (! ready) next.awaitReadable(time, timeUnit); } public void awaitReadable() throws IOException { if (! ready) next.awaitReadable(); } public void terminateReads() throws IOException { receiveBuffer.free(); next.terminateReads(); } public int receive(final ByteBuffer dst) throws IOException { final ByteBuffer receiveBuffer = this.receiveBuffer.getResource(); int res; do { res = next.read(receiveBuffer); } while (res > 0); if (receiveBuffer.position() < 4) { if (res == -1) { receiveBuffer.clear(); } ready = false; return res; } receiveBuffer.flip(); try { final int length = receiveBuffer.getInt(); if (length < 0 || length > receiveBuffer.capacity() - 4) { Buffers.unget(receiveBuffer, 4); throw msg.recvInvalidMsgLength(length); } if (receiveBuffer.remaining() < length) { if (res == -1) { receiveBuffer.clear(); } else { Buffers.unget(receiveBuffer, 4); } ready = false; // must be <= 0 return res; } if (dst.hasRemaining()) { return Buffers.copy(length, dst, receiveBuffer); } else { Buffers.skip(receiveBuffer, length); return 0; } } finally { if (res != -1) { receiveBuffer.compact(); if (receiveBuffer.position() >= 4 && receiveBuffer.position() >= 4 + receiveBuffer.getInt(0)) { // there's another packet ready to go ready = true; } } } } public long receive(final ByteBuffer[] dsts, final int offs, final int len) throws IOException { final ByteBuffer receiveBuffer = this.receiveBuffer.getResource(); int res; do { res = next.read(receiveBuffer); } while (res > 0); if (receiveBuffer.position() < 4) { if (res == -1) { receiveBuffer.clear(); } ready = false; return res; } receiveBuffer.flip(); try { final int length = receiveBuffer.getInt(); if (length < 0 || length > receiveBuffer.capacity() - 4) { Buffers.unget(receiveBuffer, 4); throw msg.recvInvalidMsgLength(length); } if (receiveBuffer.remaining() < length) { if (res == -1) { receiveBuffer.clear(); } else { Buffers.unget(receiveBuffer, 4); } ready = false; // must be <= 0 return res; } if (Buffers.hasRemaining(dsts, offs, len)) { return Buffers.copy(length, dsts, offs, len, receiveBuffer); } else { Buffers.skip(receiveBuffer, length); return 0; } } finally { if (res != -1) { receiveBuffer.compact(); if (receiveBuffer.position() >= 4 && receiveBuffer.position() >= 4 + receiveBuffer.getInt(0)) { // there's another packet ready to go ready = true; } } } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/InflatingStreamSourceConduit.java000066400000000000000000000120511257016060700307710ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import static org.xnio._private.Messages.msg; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import java.util.zip.DataFormatException; import java.util.zip.Inflater; import org.xnio.channels.StreamSinkChannel; /** * A filtering stream source conduit which decompresses the source data. * * @author David M. Lloyd */ public final class InflatingStreamSourceConduit extends AbstractStreamSourceConduit implements StreamSourceConduit { private final Inflater inflater; private final ByteBuffer buffer; /** * Construct a new instance. * * @param next the underlying conduit for this channel * @param inflater the initialized inflater to use */ public InflatingStreamSourceConduit(final StreamSourceConduit next, final Inflater inflater) { super(next); this.inflater = inflater; buffer = ByteBuffer.allocate(16384); } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { return target.transferFrom(new ConduitReadableByteChannel(this), position, count); } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { return Conduits.transfer(this, count, throughBuffer, target); } public int read(final ByteBuffer dst) throws IOException { final int remaining = dst.remaining(); final int position = dst.position(); final Inflater inflater = this.inflater; int res; if (dst.hasArray()) { // fast path final byte[] array = dst.array(); final int off = dst.arrayOffset(); for (;;) { try { res = inflater.inflate(array, off + position, remaining); } catch (DataFormatException e) { throw new IOException(e); } if (res > 0) { dst.position(position + res); return res; } if (inflater.needsDictionary()) { throw msg.inflaterNeedsDictionary(); } final ByteBuffer buffer = this.buffer; buffer.clear(); res = next.read(buffer); if (res > 0) { inflater.setInput(buffer.array(), buffer.arrayOffset(), res); } else { return res; } } } else { final byte[] space = new byte[remaining]; for (;;) { try { res = inflater.inflate(space); } catch (DataFormatException e) { throw new IOException(e); } if (res > 0) { dst.put(space, 0, res); return res; } if (inflater.needsDictionary()) { throw msg.inflaterNeedsDictionary(); } final ByteBuffer buffer = this.buffer; buffer.clear(); res = next.read(buffer); if (res > 0) { inflater.setInput(buffer.array(), buffer.arrayOffset(), res); } else { return res; } } } } public long read(final ByteBuffer[] dsts) throws IOException { return read(dsts, 0, dsts.length); } public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { for (int i = 0; i < length; i ++) { final ByteBuffer buffer = dsts[i + offset]; if (buffer.hasRemaining()) { return read(buffer); } } return 0L; } public void terminateReads() throws IOException { inflater.end(); next.terminateReads(); } public void awaitReadable() throws IOException { if (! inflater.needsInput()) { return; } next.awaitReadable(); } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { if (! inflater.needsInput()) { return; } next.awaitReadable(time, timeUnit); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/MessageSinkConduit.java000066400000000000000000000052571257016060700267440ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; /** * A message sink conduit. * * @author David M. Lloyd */ public interface MessageSinkConduit extends SinkConduit { /** * Send a complete message. * * @param src the message to send * @return the result of the send operation; {@code true} if the message was sent, or {@code false} if it would block * @throws IOException if an I/O error occurs */ boolean send(ByteBuffer src) throws IOException; /** * Send a complete message. * * @param srcs the buffers holding the message to send * @param offs the offset into the buffer array of the first buffer * @param len the number of buffers that contain data to send * @return the result of the send operation; {@code true} if the message was sent, or {@code false} if it would block * @throws IOException if an I/O error occurs */ boolean send(ByteBuffer[] srcs, int offs, int len) throws IOException; /** * Send a complete message. If the message is successfully sent then the sink will have its writes terminated. * * @param src the message to send * @return the result of the send operation; {@code true} if the message was sent, or {@code false} if it would block * @throws IOException if an I/O error occurs */ boolean sendFinal(ByteBuffer src) throws IOException; /** * Send a complete message. If the message is successfully sent then the sink will have its writes terminated. * * @param srcs the buffers holding the message to send * @param offs the offset into the buffer array of the first buffer * @param len the number of buffers that contain data to send * @return the result of the send operation; {@code true} if the message was sent, or {@code false} if it would block * @throws IOException if an I/O error occurs */ boolean sendFinal(ByteBuffer[] srcs, int offs, int len) throws IOException; } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/MessageSourceConduit.java000066400000000000000000000034121257016060700272670ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; /** * A message source conduit. * * @author David M. Lloyd */ public interface MessageSourceConduit extends SourceConduit { /** * Receive a message. * * @param buffer the buffer that will hold the message * @return the size of the received message, 0 if no message is available, and -1 if the message channel has reached an end-of-file condition * @throws IOException if an I/O error occurs */ int receive(ByteBuffer dst) throws IOException; /** * Receive a message. * * @param buffers the buffers that will hold the message * @param offs the offset into the array of buffers of the first buffer to read into * @param len the number of buffers to fill * @return the size of the received message, 0 if no message is available, and -1 if the message channel has reached an end-of-file condition * @throws IOException if an I/O error occurs */ long receive(ByteBuffer[] dsts, int offs, int len) throws IOException; } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/MessageStreamSinkConduit.java000066400000000000000000000046451257016060700301200ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import org.xnio.Buffers; import org.xnio.channels.StreamSourceChannel; /** * A stream sink conduit which wraps each write into a single message. * * @author David M. Lloyd */ public final class MessageStreamSinkConduit extends AbstractSinkConduit implements StreamSinkConduit { /** * Construct a new instance. * * @param next the delegate conduit to set */ public MessageStreamSinkConduit(final MessageSinkConduit next) { super(next); } public long transferFrom(final FileChannel src, final long position, final long count) throws IOException { return src.transferTo(position, count, new ConduitWritableByteChannel(this)); } public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { return Conduits.transfer(source, count, throughBuffer, this); } public int write(final ByteBuffer src) throws IOException { final int remaining = src.remaining(); return next.send(src) ? remaining : 0; } public long write(final ByteBuffer[] srcs, final int offs, final int len) throws IOException { final long remaining = Buffers.remaining(srcs, offs, len); return next.send(srcs, offs, len) ? remaining : 0L; } @Override public int writeFinal(ByteBuffer src) throws IOException { return Conduits.writeFinalBasic(this, src); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { return Conduits.writeFinalBasic(this, srcs, offset, length); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/MessageStreamSourceConduit.java000066400000000000000000000041011257016060700304370ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import org.xnio.channels.StreamSinkChannel; /** * A stream source conduit which reads stream data from messages. The receive buffer should always be as large as * the largest possible incoming message, or larger, to avoid data loss. * * @author David M. Lloyd */ public final class MessageStreamSourceConduit extends AbstractSourceConduit implements StreamSourceConduit { /** * Construct a new instance. * * @param next the delegate conduit to set */ public MessageStreamSourceConduit(final MessageSourceConduit next) { super(next); } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { return target.transferFrom(new ConduitReadableByteChannel(this), position, count); } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { return Conduits.transfer(this, count, throughBuffer, target); } public int read(final ByteBuffer dst) throws IOException { return next.receive(dst); } public long read(final ByteBuffer[] dsts, final int offs, final int len) throws IOException { return next.receive(dsts, offs, len); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/NullStreamSinkConduit.java000066400000000000000000000076471257016060700274530ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.Channels; import org.xnio.channels.StreamSourceChannel; /** * A stream sink conduit which discards all data written to it. * * @author David M. Lloyd */ public final class NullStreamSinkConduit implements StreamSinkConduit { private final XnioWorker worker; private final XnioIoThread writeThread; private WriteReadyHandler writeReadyHandler; private boolean shutdown; private boolean resumed; /** * Construct a new instance. * * @param writeThread the write thread for this conduit */ public NullStreamSinkConduit(final XnioIoThread writeThread) { this.worker = writeThread.getWorker(); this.writeThread = writeThread; } public long transferFrom(final FileChannel src, final long position, final long count) throws IOException { return Channels.drain(src, position, count); } public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { throughBuffer.limit(0); return Channels.drain(source, count); } public int write(final ByteBuffer src) throws IOException { try { return src.remaining(); } finally { src.position(src.limit()); } } public long write(final ByteBuffer[] srcs, final int offs, final int len) throws IOException { long t = 0L; for (int i = 0; i < len; i++) { t += write(srcs[i + offs]); } return t; } @Override public int writeFinal(ByteBuffer src) throws IOException { return Conduits.writeFinalBasic(this, src); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { return Conduits.writeFinalBasic(this, srcs, offset, length); } public boolean flush() throws IOException { return true; } public boolean isWriteShutdown() { return shutdown; } public void suspendWrites() { resumed = false; } public void resumeWrites() { resumed = true; final WriteReadyHandler handler = writeReadyHandler; writeThread.execute(new WriteReadyHandler.ReadyTask(handler)); } public void wakeupWrites() { resumeWrites(); } public boolean isWriteResumed() { return resumed; } public void awaitWritable() throws IOException { } public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException { } public XnioIoThread getWriteThread() { return writeThread; } public void setWriteReadyHandler(final WriteReadyHandler handler) { writeReadyHandler = handler; } public void truncateWrites() throws IOException { terminateWrites(); } public void terminateWrites() throws IOException { if (! shutdown) { shutdown = true; writeReadyHandler.terminated(); } } public XnioWorker getWorker() { return worker; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/PushBackStreamSourceConduit.java000066400000000000000000000227671257016060700305750ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import org.xnio.Buffers; import org.xnio.Pooled; import org.xnio.channels.StreamSinkChannel; /** * A stream source conduit which allows buffers to be "pushed back" to the head of the stream. * * @author David M. Lloyd */ public final class PushBackStreamSourceConduit extends AbstractStreamSourceConduit implements StreamSourceConduit { private StreamSourceConduit current = next; private boolean shutdown; /** * Construct a new instance. * * @param next the delegate conduit to set */ public PushBackStreamSourceConduit(final StreamSourceConduit next) { super(next); } public void resumeReads() { current.resumeReads(); } public int read(final ByteBuffer dst) throws IOException { return current.read(dst); } public long read(final ByteBuffer[] dsts, final int offs, final int len) throws IOException { return current.read(dsts, offs, len); } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { return current.transferTo(position, count, target); } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { return current.transferTo(count, throughBuffer, target); } public void awaitReadable() throws IOException { current.awaitReadable(); } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { current.awaitReadable(time, timeUnit); } public void terminateReads() throws IOException { shutdown = true; current.terminateReads(); } public void setReadReadyHandler(final ReadReadyHandler handler) { current.setReadReadyHandler(handler); } /** * Push a buffer back to the head of the stream. Once the buffer data is consumed, it will * be released back to its original pool (if any). * * @param pooledBuffer the buffer to push back */ public void pushBack(Pooled pooledBuffer) { if (pooledBuffer == null) { return; } if (shutdown || ! pooledBuffer.getResource().hasRemaining()) { pooledBuffer.free(); } else { current = new BufferConduit(current, pooledBuffer); } } class BufferConduit extends AbstractStreamSourceConduit implements StreamSourceConduit { private final Pooled pooledBuffer; BufferConduit(final StreamSourceConduit next, final Pooled pooledBuffer) { super(next); this.pooledBuffer = pooledBuffer; } public void resumeReads() { next.wakeupReads(); } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { // readable } public void awaitReadable() throws IOException { // readable } public int read(final ByteBuffer dst) throws IOException { int cnt; if (! dst.hasRemaining()) { return 0; } final StreamSourceConduit next = this.next; try { final ByteBuffer src = pooledBuffer.getResource(); cnt = Buffers.copy(dst, src); if (src.hasRemaining()) { return cnt; } current = next; pooledBuffer.free(); if (cnt > 0 && next == PushBackStreamSourceConduit.this.next) { // don't hit the main channel until the user wants to return cnt; } } catch (IllegalStateException ignored) { current = next; cnt = 0; } final int res = next.read(dst); return res > 0 ? res + cnt : cnt > 0 ? cnt : res; } public long read(final ByteBuffer[] dsts, final int offs, final int len) throws IOException { long cnt; final StreamSourceConduit next = this.next; try { final ByteBuffer src = pooledBuffer.getResource(); cnt = Buffers.copy(dsts, offs, len, src); if (src.hasRemaining()) { return cnt; } current = next; pooledBuffer.free(); if (cnt > 0L && next == PushBackStreamSourceConduit.this.next) { // don't hit the main channel until the user wants to return cnt; } } catch (IllegalStateException ignored) { current = next; cnt = 0; } final long res = next.read(dsts, offs, len); return res > 0 ? res + cnt : cnt > 0 ? cnt : res; } public long transferTo(long position, long count, final FileChannel target) throws IOException { long cnt; final ByteBuffer src; try { src = pooledBuffer.getResource(); final int pos = src.position(); final int rem = src.remaining(); if (rem > count) try { // partial empty of our buffer src.limit(pos + (int) count); return target.write(src, position); } finally { src.limit(pos + rem); } else { // full empty of our buffer cnt = target.write(src, position); if (cnt == rem) { // we emptied our buffer current = next; pooledBuffer.free(); } else { return cnt; } position += cnt; count -= cnt; } } catch (IllegalStateException ignored) { current = next; cnt = 0L; } return cnt + next.transferTo(position, count, target); } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { long cnt; final ByteBuffer src; try { src = pooledBuffer.getResource(); final int pos = src.position(); final int rem = src.remaining(); if (rem > count) try { // partial empty of our buffer src.limit(pos + (int) count); int res = target.write(src); if(res == 0) { //a bit yuck, but if we have filed to copy anything we need to transfer data into the throughbuffer //this signals to the called that it was not the read that did not succeed, but the write throughBuffer.clear(); Buffers.copy(throughBuffer, src); throughBuffer.flip(); } else { //make sure throughbuffer is empty throughBuffer.clear(); throughBuffer.flip(); } return res; } finally { src.limit(pos + rem); } else { // full empty of our buffer cnt = target.write(src); if (cnt == rem) { // we emptied our buffer current = next; pooledBuffer.free(); } else { if (cnt == 0) { //a bit yuck, but if we have filed to copy anything we need to transfer data into the throughbuffer //this signals to the called that it was not the read that did not succeed, but the write throughBuffer.clear(); Buffers.copy(throughBuffer, src); throughBuffer.flip(); } else { //make sure throughbuffer is empty throughBuffer.clear(); throughBuffer.flip(); } return cnt; } } } catch (IllegalStateException ignored) { current = next; cnt = 0L; } final long res = next.transferTo(count - cnt, throughBuffer, target); return res > 0L ? cnt + res : cnt > 0L ? cnt : res; } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/ReadReadyHandler.java000066400000000000000000000053341257016060700263370ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.IoUtils; import org.xnio.channels.CloseListenerSettable; import org.xnio.channels.ReadListenerSettable; import org.xnio.channels.SuspendableReadChannel; /** * A conduit read-ready handler. * * @author David M. Lloyd */ public interface ReadReadyHandler extends TerminateHandler { /** * Signify that reads are ready. */ void readReady(); /** * A read ready handler which calls channel listener(s). * * @param the channel type */ class ChannelListenerHandler & CloseListenerSettable> implements ReadReadyHandler { private final C channel; /** * Construct a new instance. * * @param channel the channel */ public ChannelListenerHandler(final C channel) { this.channel = channel; } public void forceTermination() { IoUtils.safeClose(channel); } public void readReady() { final ChannelListener readListener = channel.getReadListener(); if (readListener == null) { channel.suspendReads(); } else { ChannelListeners.invokeChannelListener(channel, readListener); } } public void terminated() { ChannelListeners.invokeChannelListener(channel, channel.getCloseListener()); } } /** * A runnable task which invokes the {@link ReadReadyHandler#readReady()} method of the given handler. */ class ReadyTask implements Runnable { private final ReadReadyHandler handler; /** * Construct a new instance. * * @param handler the handler to invoke */ public ReadyTask(final ReadReadyHandler handler) { this.handler = handler; } public void run() { handler.readReady(); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/SinkConduit.java000066400000000000000000000100501257016060700254220ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.io.InterruptedIOException; import java.util.concurrent.TimeUnit; import org.xnio.XnioIoThread; /** * A conduit which is a target or output for data. * * @author David M. Lloyd */ public interface SinkConduit extends Conduit { /** * Signal that no more write data is forthcoming. The conduit must be {@link #flush()}ed before it is considered * to be shut down. * * @throws IOException */ void terminateWrites() throws IOException; /** * Determine whether writes have been fully shut down on this conduit. * * @return {@code true} if writes are fully shut down, {@code false} otherwise */ boolean isWriteShutdown(); /** * Indicate that the conduit's {@link WriteReadyHandler} should be invoked as soon as data can be written * without blocking. */ void resumeWrites(); /** * Indicate that calling the conduit's {@link WriteReadyHandler} should be suspended. */ void suspendWrites(); /** * Indicate that the conduit's {@link WriteReadyHandler} should be invoked immediately, and then again as soon * as data can be written without blocking. */ void wakeupWrites(); /** * Determine whether write notifications are currently enabled. * * @return {@code true} if write notifications are enabled */ boolean isWriteResumed(); /** * Block until this channel becomes writable again. This method may return spuriously before the channel becomes * writable. * * @throws InterruptedIOException if the operation is interrupted; the thread's interrupt flag will be set * as well * @throws IOException if an I/O error occurs */ void awaitWritable() throws IOException; /** * Block until this conduit becomes writable again, or until the timeout expires. This method may return * spuriously before the conduit becomes writable or the timeout expires. * * @param time the time to wait * @param timeUnit the time unit * * @throws InterruptedIOException if the operation is interrupted; the thread's interrupt flag will be set * as well * @throws IOException if an I/O error occurs */ void awaitWritable(long time, TimeUnit timeUnit) throws IOException; /** * Get the write thread for this conduit. * * @return the thread, or {@code null} if none is configured or available */ XnioIoThread getWriteThread(); /** * Set the handler which should receive readiness notifications. A filter may * pass this invocation on to the filter it wraps, or it may substitute itself. * * @param next the filter to receive readiness notifications */ void setWriteReadyHandler(WriteReadyHandler handler); /** * Terminate writes and discard any outstanding write data. The conduit is terminated and flushed regardless * of the outcome of this method. * * @throws java.io.IOException if channel termination failed for some reason */ void truncateWrites() throws IOException; /** * Flush out any unwritten, buffered output. * * @return {@code true} if everything is flushed, {@code false} otherwise * @throws java.io.IOException if flush fails */ boolean flush() throws IOException; } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/SourceConduit.java000066400000000000000000000065641257016060700257750ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.io.InterruptedIOException; import java.util.concurrent.TimeUnit; import org.xnio.XnioIoThread; /** * @author David M. Lloyd */ public interface SourceConduit extends Conduit { /** * Indicate that no more data will be read from this conduit. If unread data exists, an exception * may be thrown. * * @throws IOException if there was a problem */ void terminateReads() throws IOException; /** * Determine whether reads have been shut down on this conduit. * * @return {@code true} if writes are shut down, {@code false} otherwise */ boolean isReadShutdown(); /** * Indicate that the conduit's {@link ReadReadyHandler} should be invoked as soon as data can be read * without blocking. */ void resumeReads(); /** * Indicate that calling the conduit's {@link ReadReadyHandler} should be suspended. */ void suspendReads(); /** * Indicate that the conduit's {@link ReadReadyHandler} should be invoked immediately, and then again as soon * as data can be read without blocking. */ void wakeupReads(); /** * Determine whether read notifications are currently enabled. * * @return {@code true} if read notifications are enabled */ boolean isReadResumed(); /** * Block until this channel becomes readable again. This method may return spuriously before the channel becomes * readable. * * @throws InterruptedIOException if the operation is interrupted; the thread's interrupt flag will be set as well * @throws IOException if an I/O error occurs */ void awaitReadable() throws IOException; /** * Block until this conduit becomes readable again, or until the timeout expires. This method may return * spuriously before the conduit becomes readable or the timeout expires. * * @param time the time to wait * @param timeUnit the time unit * * @throws InterruptedIOException if the operation is interrupted; the thread's interrupt flag will be set as well * @throws IOException if an I/O error occurs */ void awaitReadable(long time, TimeUnit timeUnit) throws IOException; /** * Get the XNIO read thread. * * @return the XNIO read thread */ XnioIoThread getReadThread(); /** * Set the handler which should receive readiness notifications. A filter may * pass this invocation on to the filter it wraps, or it may substitute itself. * * @param next the filter to receive readiness notifications */ void setReadReadyHandler(ReadReadyHandler handler); } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/StreamSinkChannelWrappingConduit.java000066400000000000000000000073101257016060700316040ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import org.xnio.ChannelListener; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; /** * A conduit which wraps a channel, for compatibility. * * @author David M. Lloyd */ public final class StreamSinkChannelWrappingConduit implements StreamSinkConduit { private final StreamSinkChannel channel; /** * Construct a new instance. * * @param channel the channel to wrap */ public StreamSinkChannelWrappingConduit(final StreamSinkChannel channel) { this.channel = channel; } public long transferFrom(final FileChannel src, final long position, final long count) throws IOException { return channel.transferFrom(src, position, count); } public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { return channel.transferFrom(source, count, throughBuffer); } public int write(final ByteBuffer src) throws IOException { return channel.write(src); } public long write(final ByteBuffer[] srcs, final int offs, final int len) throws IOException { return channel.write(srcs, offs, len); } @Override public int writeFinal(ByteBuffer src) throws IOException { return channel.writeFinal(src); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { return channel.writeFinal(srcs, offset, length); } public void terminateWrites() throws IOException { channel.shutdownWrites(); } public boolean isWriteShutdown() { return ! channel.isOpen(); } public void resumeWrites() { channel.resumeWrites(); } public void suspendWrites() { channel.suspendWrites(); } public void wakeupWrites() { channel.wakeupWrites(); } public boolean isWriteResumed() { return channel.isWriteResumed(); } public void awaitWritable() throws IOException { channel.awaitWritable(); } public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException { channel.awaitWritable(time, timeUnit); } public XnioIoThread getWriteThread() { return channel.getIoThread(); } public void setWriteReadyHandler(final WriteReadyHandler handler) { channel.getWriteSetter().set(new ChannelListener() { public void handleEvent(final StreamSinkChannel channel) { handler.writeReady(); } }); } public void truncateWrites() throws IOException { channel.close(); } public boolean flush() throws IOException { return channel.flush(); } public XnioWorker getWorker() { return channel.getWorker(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/StreamSinkConduit.java000066400000000000000000000115531257016060700266070ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import org.xnio.channels.StreamSourceChannel; /** * A sink (writable) conduit for byte streams. * * @author David M. Lloyd */ public interface StreamSinkConduit extends SinkConduit { /** * Transfer bytes into this conduit from the given file. * * @param src the file to read from * @param position the position within the file from which the transfer is to begin * @param count the number of bytes to be transferred * @return the number of bytes (possibly 0) that were actually transferred * @throws IOException if an I/O error occurs */ long transferFrom(FileChannel src, long position, long count) throws IOException; /** * Transfers bytes from the given channel source. On entry, {@code throughBuffer} will be cleared. On exit, the * buffer will be flipped for emptying, and may be empty or may contain data. If this method returns a value less * than {@code count}, then the remaining data in {@code throughBuffer} may contain data read from {@code source} * which must be written to this channel to complete the operation. * * @param source the source to read from * @param count the number of bytes to be transferred * @param throughBuffer the buffer to copy through. * @return the number of bytes (possibly 0) that were actually transferred, or -1 if the end of input was reached * @throws IOException if an I/O error occurs */ long transferFrom(StreamSourceChannel source, long count, ByteBuffer throughBuffer) throws IOException; /** * Writes a sequence of bytes to this conduit from the given buffer. * * @param src the buffer containing data to write * @return the number of bytes written, possibly 0 * @throws ClosedChannelException if this conduit's {@link #terminateWrites()} method was previously called * @throws IOException if an error occurs */ int write(ByteBuffer src) throws IOException; /** * Writes a sequence of bytes to this conduit from the given buffers. * * @param srcs the buffers containing data to write * @param offs the offset into the buffer array * @param len the number of buffers to write * @return the number of bytes written, possibly 0 * @throws ClosedChannelException if this conduit's {@link #terminateWrites()} method was previously called * @throws IOException if an error occurs */ long write(ByteBuffer[] srcs, int offs, int len) throws IOException; /** * * Writes some data to the conduit, with the same semantics as * {@link #write(java.nio.ByteBuffer)}. If all the data is written * out then the conduit will have its writes terminated. Semantically this * method is equivalent to: * * * int rem = src.remaining(); * int written = conduit.write(src); * if(written == rem) { * conduit.terminateWrites() * } * * * @param src The data to write * @return The amount of data that was actually written. */ public int writeFinal(ByteBuffer src) throws IOException; /** * * Writes some data to the conduit, with the same semantics as * {@link #write(java.nio.ByteBuffer[], int, int)}. If all the data is written * out then the conduit will have its writes terminated. * * * @param srcs * The buffers from which bytes are to be retrieved * * @param offset * The offset within the buffer array of the first buffer from * which bytes are to be retrieved; must be non-negative and no * larger than srcs.length * * @param length * The maximum number of buffers to be accessed; must be * non-negative and no larger than * srcs.length - offset * * @return The amount of data that was actually written */ public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException; } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/StreamSourceChannelWrappingConduit.java000066400000000000000000000051211257016060700321360ustar00rootroot00000000000000package org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import org.xnio.ChannelListener; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; /** * A conduit which wraps a channel, for compatibility. * * @author David M. Lloyd */ public final class StreamSourceChannelWrappingConduit implements StreamSourceConduit { private final StreamSourceChannel channel; /** * Construct a new instance. * * @param channel the channel to wrap */ public StreamSourceChannelWrappingConduit(final StreamSourceChannel channel) { this.channel = channel; } public void terminateReads() throws IOException { channel.shutdownReads(); } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { return channel.transferTo(position, count, target); } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { return channel.transferTo(count, throughBuffer, target); } public int read(final ByteBuffer dst) throws IOException { return channel.read(dst); } public long read(final ByteBuffer[] dsts, final int offs, final int len) throws IOException { return channel.read(dsts, offs, len); } public boolean isReadShutdown() { return ! channel.isOpen(); } public void resumeReads() { channel.resumeReads(); } public void suspendReads() { channel.suspendReads(); } public void wakeupReads() { channel.wakeupReads(); } public boolean isReadResumed() { return channel.isReadResumed(); } public void awaitReadable() throws IOException { channel.awaitReadable(); } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { channel.awaitReadable(time, timeUnit); } public XnioIoThread getReadThread() { return channel.getIoThread(); } public void setReadReadyHandler(final ReadReadyHandler handler) { channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final StreamSourceChannel channel) { handler.readReady(); } }); } public XnioWorker getWorker() { return channel.getWorker(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/StreamSourceConduit.java000066400000000000000000000064761257016060700271530ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import org.xnio.channels.StreamSinkChannel; /** * @author David M. Lloyd */ public interface StreamSourceConduit extends SourceConduit { /** * Transfers bytes into the given file from this channel. * * @param position the position within the file from which the transfer is to begin * @param count the number of bytes to be transferred * @param target the file to write to * @return the number of bytes (possibly 0) that were actually transferred * @throws IOException if an I/O error occurs */ long transferTo(long position, long count, FileChannel target) throws IOException; /** * Transfers bytes into the given channel target. On entry, {@code throughBuffer} will be cleared. On exit, the buffer will be * flipped for emptying, and may possibly be empty or may contain data. If this method returns a value less than * {@code count}, then the remaining data in {@code throughBuffer} may contain data read from this channel which must * be written to {@code target} to complete the operation. * * @param count the number of bytes to be transferred * @param throughBuffer the buffer to copy through. * @param target the destination to write to * @return the number of bytes (possibly 0) that were actually transferred, or -1 if the end of input was reached * @throws IOException if an I/O error occurs */ long transferTo(long count, ByteBuffer throughBuffer, StreamSinkChannel target) throws IOException; /** * Read a sequence of bytes from this conduit to the given buffer. * * @param src the buffer to fill with data from the conduit * @return the number of bytes (possibly 0) that were actually transferred, or -1 if the end of input was reached or * this conduit's {@link #terminateReads()} method was previously called * @throws IOException if an error occurs */ int read(ByteBuffer dst) throws IOException; /** * Read a sequence of bytes from this conduit to the given buffers. * * @param srcs the buffers to fill with data from the conduit * @param offs the offset into the buffer array * @param len the number of buffers to fill * @return the number of bytes (possibly 0) that were actually transferred, or -1 if the end of input was reached or * this conduit's {@link #terminateReads()} method was previously called * @throws IOException if an error occurs */ long read(ByteBuffer[] dsts, int offs, int len) throws IOException; } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/SynchronizedMessageSinkConduit.java000066400000000000000000000044361257016060700313420ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; /** * A synchronized message sink conduit. All conduit operations are wrapped in synchronization blocks for simplified * thread safety. * * @author David M. Lloyd */ public final class SynchronizedMessageSinkConduit extends AbstractSynchronizedSinkConduit implements MessageSinkConduit { /** * Construct a new instance. A new lock object is created. * * @param next the next conduit in the chain */ public SynchronizedMessageSinkConduit(final MessageSinkConduit next) { super(next); } /** * Construct a new instance. * * @param next the next conduit in the chain * @param lock the lock object to use */ public SynchronizedMessageSinkConduit(final MessageSinkConduit next, final Object lock) { super(next, lock); } public boolean send(final ByteBuffer src) throws IOException { synchronized (lock) { return next.send(src); } } public boolean send(final ByteBuffer[] srcs, final int offs, final int len) throws IOException { synchronized (lock) { return next.send(srcs, offs, len); } } public boolean sendFinal(final ByteBuffer src) throws IOException { synchronized (lock) { return next.sendFinal(src); } } public boolean sendFinal(final ByteBuffer[] srcs, final int offs, final int len) throws IOException { synchronized (lock) { return next.sendFinal(srcs, offs, len); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/SynchronizedMessageSourceConduit.java000066400000000000000000000037111257016060700316710ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; /** * A synchronized message source conduit. All conduit operations are wrapped in synchronization blocks for simplified * thread safety. * * @author David M. Lloyd */ public final class SynchronizedMessageSourceConduit extends AbstractSynchronizedSourceConduit implements MessageSourceConduit { /** * Construct a new instance. A new lock object is created. * * @param next the next conduit in the chain */ public SynchronizedMessageSourceConduit(final MessageSourceConduit next) { super(next); } /** * Construct a new instance. * * @param next the next conduit in the chain * @param lock the lock object to use */ public SynchronizedMessageSourceConduit(final MessageSourceConduit next, final Object lock) { super(next, lock); } public int receive(final ByteBuffer dst) throws IOException { synchronized (lock) { return next.receive(dst); } } public long receive(final ByteBuffer[] dsts, final int offs, final int len) throws IOException { synchronized (lock) { return next.receive(dsts, offs, len); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/SynchronizedStreamSinkConduit.java000066400000000000000000000055031257016060700312050ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import org.xnio.channels.StreamSourceChannel; /** * A synchronized stream sink conduit. All conduit operations are wrapped in synchronization blocks for simplified * thread safety. * * @author David M. Lloyd */ public final class SynchronizedStreamSinkConduit extends AbstractSynchronizedSinkConduit implements StreamSinkConduit { /** * Construct a new instance. A new lock object is created. * * @param next the next conduit in the chain */ public SynchronizedStreamSinkConduit(final StreamSinkConduit next) { super(next); } /** * Construct a new instance. * * @param next the next conduit in the chain * @param lock the lock object to use */ public SynchronizedStreamSinkConduit(final StreamSinkConduit next, final Object lock) { super(next, lock); } public long transferFrom(final FileChannel src, final long position, final long count) throws IOException { synchronized (lock) { return next.transferFrom(src, position, count); } } public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { synchronized (lock) { return next.transferFrom(source, count, throughBuffer); } } public int write(final ByteBuffer src) throws IOException { synchronized (lock) { return next.write(src); } } public long write(final ByteBuffer[] srcs, final int offs, final int len) throws IOException { synchronized (lock) { return next.write(srcs, offs, len); } } public int writeFinal(final ByteBuffer src) throws IOException { synchronized (lock) { return next.writeFinal(src); } } public long writeFinal(final ByteBuffer[] srcs, final int offset, final int length) throws IOException { synchronized (lock) { return next.writeFinal(srcs, offset, length); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/SynchronizedStreamSourceConduit.java000066400000000000000000000047301257016060700315420ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import org.xnio.channels.StreamSinkChannel; /** * A synchronized stream source conduit. All conduit operations are wrapped in synchronization blocks for simplified * thread safety. * * @author David M. Lloyd */ public final class SynchronizedStreamSourceConduit extends AbstractSynchronizedSourceConduit implements StreamSourceConduit { /** * Construct a new instance. A new lock object is created. * * @param next the next conduit in the chain */ public SynchronizedStreamSourceConduit(final StreamSourceConduit next) { super(next); } /** * Construct a new instance. * * @param next the next conduit in the chain * @param lock the lock object to use */ public SynchronizedStreamSourceConduit(final StreamSourceConduit next, final Object lock) { super(next, lock); } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { synchronized (lock) { return next.transferTo(position, count, target); } } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { synchronized (lock) { return next.transferTo(count, throughBuffer, target); } } public int read(final ByteBuffer dst) throws IOException { synchronized (lock) { return next.read(dst); } } public long read(final ByteBuffer[] dsts, final int offs, final int len) throws IOException { synchronized (lock) { return next.read(dsts, offs, len); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/TerminateHandler.java000066400000000000000000000050521257016060700264240ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import java.nio.channels.Channel; import org.xnio.ChannelListeners; import org.xnio.IoUtils; import org.xnio.channels.CloseListenerSettable; /** * The base ready handler type, which can forward termination requests as well as notifications of termination * completion. * * @author David M. Lloyd */ public interface TerminateHandler { /** * Force the front-end channel to close, in response to XNIO worker shutdown. */ void forceTermination(); /** * Indicate that a previous shutdown request has successfully resulted in termination. */ void terminated(); /** * A terminate handler which calls a channel listener on termination notification. * * @param the channel type */ class ChannelListenerHandler> implements TerminateHandler { private final C channel; /** * Construct a new instance. * * @param channel the channel to wrap */ public ChannelListenerHandler(final C channel) { this.channel = channel; } public void forceTermination() { IoUtils.safeClose(channel); } public void terminated() { ChannelListeners.invokeChannelListener(channel, channel.getCloseListener()); } } /** * A runnable task which invokes the {@link TerminateHandler#terminated()} method of the given handler. */ class ReadyTask implements Runnable { private final TerminateHandler handler; /** * Construct a new instance. * * @param handler the handler to run */ public ReadyTask(final TerminateHandler handler) { this.handler = handler; } public void run() { handler.terminated(); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/WriteReadyHandler.java000066400000000000000000000053601257016060700265550ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.conduits; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.IoUtils; import org.xnio.channels.CloseListenerSettable; import org.xnio.channels.SuspendableWriteChannel; import org.xnio.channels.WriteListenerSettable; /** * A conduit write-ready handler. * * @author David M. Lloyd */ public interface WriteReadyHandler extends TerminateHandler { /** * Signify that writes are ready. */ void writeReady(); /** * A write ready handler which calls channel listener(s). * * @param the channel type */ class ChannelListenerHandler & CloseListenerSettable> implements WriteReadyHandler { private final C channel; /** * Construct a new instance. * * @param channel the channel */ public ChannelListenerHandler(final C channel) { this.channel = channel; } public void forceTermination() { IoUtils.safeClose(channel); } public void writeReady() { final ChannelListener writeListener = channel.getWriteListener(); if (writeListener == null) { channel.suspendWrites(); } else { ChannelListeners.invokeChannelListener(channel, writeListener); } } public void terminated() { ChannelListeners.invokeChannelListener(channel, channel.getCloseListener()); } } /** * A runnable task which invokes the {@link WriteReadyHandler#writeReady()} method of the given handler. */ class ReadyTask implements Runnable { private final WriteReadyHandler handler; /** * Construct a new instance. * * @param handler the handler to invoke */ public ReadyTask(final WriteReadyHandler handler) { this.handler = handler; } public void run() { handler.writeReady(); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/conduits/package-info.java000066400000000000000000000015301257016060700255170ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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. */ /** * The XNIO conduit SPI. Conduits represent the underlying transport and filtering mechanism of * point-to-point message- and stream-oriented channels. */ package org.xnio.conduits; xnio-3.3.2.Final/api/src/main/java/org/xnio/http/000077500000000000000000000000001257016060700214605ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/java/org/xnio/http/ExtendedHandshakeChecker.java000066400000000000000000000011231257016060700271540ustar00rootroot00000000000000package org.xnio.http; import java.io.IOException; import java.util.List; import java.util.Map; /** * A class that can decide if a HTTP upgrade handshake is valid. If not it should * throw an {@link java.io.IOException} * */ public interface ExtendedHandshakeChecker { /** * Checks a handshake, and throws an exception if it is invalid * * @param headers The response headers, keyed by lowercase name * @throws java.io.IOException If the handshake is not valid */ void checkHandshakeExtended(final Map> headers) throws IOException; } xnio-3.3.2.Final/api/src/main/java/org/xnio/http/HandshakeChecker.java000066400000000000000000000010431257016060700254740ustar00rootroot00000000000000package org.xnio.http; import java.io.IOException; import java.util.Map; /** * A class that can decide if a HTTP upgrade handshake is valid. If not it should * throw an {@link java.io.IOException} */ public interface HandshakeChecker { /** * Checks a handshake, and throws an exception if it is invalid * * @param headers The response headers, keyed by lowercase name * @throws java.io.IOException If the handshake is not valid */ void checkHandshake(final Map headers) throws IOException; } xnio-3.3.2.Final/api/src/main/java/org/xnio/http/HttpUpgrade.java000066400000000000000000000623101257016060700245540ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.http; import static org.xnio.IoUtils.safeClose; import static org.xnio._private.Messages.msg; import java.io.IOException; import java.net.InetSocketAddress; import java.net.URI; import java.nio.ByteBuffer; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Locale; import java.util.Map; import java.util.Set; import org.xnio.ChannelExceptionHandler; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.FutureResult; import org.xnio.IoFuture; import org.xnio.OptionMap; import org.xnio.Pooled; import org.xnio.StreamConnection; import org.xnio.XnioWorker; import org.xnio.channels.BoundChannel; import org.xnio.ssl.SslConnection; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; import org.xnio.conduits.PushBackStreamSourceConduit; import org.xnio.conduits.StreamSourceConduit; import org.xnio.ssl.XnioSsl; /** * Simple HTTP client that can perform a HTTP upgrade. This is not a general purpose HTTP * client, all it can do is upgrade a HTTP * * @author Stuart Douglas */ public class HttpUpgrade { /** * Perform a HTTP upgrade that results in a SSL secured connection. This method should be used if the target endpoint is using https * * @param worker The worker * @param ssl The XnioSsl instance * @param bindAddress The bind address * @param uri The URI to connect to * @param headers Any additional headers to include in the upgrade request. This must include an Upgrade header that specifies the type of upgrade being performed * @param openListener The open listener that is invoked once the HTTP upgrade is done * @param bindListener The bind listener that is invoked when the socket is bound * @param optionMap The option map for the connection * @param handshakeChecker A handshake checker that can be supplied to verify that the server returned a valid response to the upgrade request * @return An IoFuture of the connection */ public static IoFuture performUpgrade(final XnioWorker worker, XnioSsl ssl, InetSocketAddress bindAddress, URI uri, final Map headers, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap, HandshakeChecker handshakeChecker) { return new HttpUpgradeState(worker, ssl, bindAddress, uri, headers, openListener, bindListener, optionMap, handshakeChecker).doUpgrade(); } /** * Perform a HTTP upgrade that results in a SSL secured connection. This method should be used if the target endpoint is using https * * @param worker The worker * @param ssl The XnioSsl instance * @param bindAddress The bind address * @param uri The URI to connect to * @param headers Any additional headers to include in the upgrade request. This must include an Upgrade header that specifies the type of upgrade being performed * @param openListener The open listener that is invoked once the HTTP upgrade is done * @param bindListener The bind listener that is invoked when the socket is bound * @param optionMap The option map for the connection * @param handshakeChecker A handshake checker that can be supplied to verify that the server returned a valid response to the upgrade request * @return An IoFuture of the connection */ public static IoFuture performUpgrade(final XnioWorker worker, XnioSsl ssl, InetSocketAddress bindAddress, URI uri, final Map> headers, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap, ExtendedHandshakeChecker handshakeChecker) { return new HttpUpgradeState(worker, ssl, bindAddress, uri, headers, openListener, bindListener, optionMap, handshakeChecker).doUpgrade(); } /** * Connects to the target server using HTTP upgrade. * * @param worker The worker * @param bindAddress The bind address * @param uri The URI to connect to * @param headers Any additional headers to include in the upgrade request. This must include an Upgrade header that specifies the type of upgrade being performed * @param openListener The open listener that is invoked once the HTTP upgrade is done * @param bindListener The bind listener that is invoked when the socket is bound * @param optionMap The option map for the connection * @param handshakeChecker A handshake checker that can be supplied to verify that the server returned a valid response to the upgrade request * @return An IoFuture of the connection */ public static IoFuture performUpgrade(final XnioWorker worker, InetSocketAddress bindAddress, URI uri, final Map headers, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap, HandshakeChecker handshakeChecker) { return new HttpUpgradeState(worker, null, bindAddress, uri, headers, openListener, bindListener, optionMap, handshakeChecker).doUpgrade(); } /** * Connects to the target server using HTTP upgrade. * * @param worker The worker * @param bindAddress The bind address * @param uri The URI to connect to * @param headers Any additional headers to include in the upgrade request. This must include an Upgrade header that specifies the type of upgrade being performed * @param openListener The open listener that is invoked once the HTTP upgrade is done * @param bindListener The bind listener that is invoked when the socket is bound * @param optionMap The option map for the connection * @param handshakeChecker A handshake checker that can be supplied to verify that the server returned a valid response to the upgrade request * @return An IoFuture of the connection */ public static IoFuture performUpgrade(final XnioWorker worker, InetSocketAddress bindAddress, URI uri, final Map> headers, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap, ExtendedHandshakeChecker handshakeChecker) { return new HttpUpgradeState(worker, null, bindAddress, uri, headers, openListener, bindListener, optionMap, handshakeChecker).doUpgrade(); } /** * Performs a HTTP upgrade on an existing connection. * * @param connection The existing connection to upgrade * @param uri The URI to connect to * @param headers Any additional headers to include in the upgrade request. This must include an Upgrade header that specifies the type of upgrade being performed * @param openListener The open listener that is invoked once the HTTP upgrade is done * @param handshakeChecker A handshake checker that can be supplied to verify that the server returned a valid response to the upgrade request * @return An IoFuture of the connection */ public static IoFuture performUpgrade(final T connection, URI uri, final Map headers, ChannelListener openListener, HandshakeChecker handshakeChecker) { return new HttpUpgradeState(connection, uri, headers, openListener, handshakeChecker).upgradeExistingConnection(); } /** * Performs a HTTP upgrade on an existing connection. * * @param connection The existing connection to upgrade * @param uri The URI to connect to * @param headers Any additional headers to include in the upgrade request. This must include an Upgrade header that specifies the type of upgrade being performed * @param openListener The open listener that is invoked once the HTTP upgrade is done * @param handshakeChecker A handshake checker that can be supplied to verify that the server returned a valid response to the upgrade request * @return An IoFuture of the connection */ public static IoFuture performUpgrade(final T connection, URI uri, final Map> headers, ChannelListener openListener, ExtendedHandshakeChecker handshakeChecker) { return new HttpUpgradeState(connection, uri, headers, openListener, handshakeChecker).upgradeExistingConnection(); } private HttpUpgrade() { } private static class HttpUpgradeState { private final XnioWorker worker; private final XnioSsl ssl; private final InetSocketAddress bindAddress; private final URI uri; private final Map> headers; private final ChannelListener openListener; private final ChannelListener bindListener; private final OptionMap optionMap; private final Object handshakeChecker; private final FutureResult future = new FutureResult(); private T connection; private HttpUpgradeState(final XnioWorker worker, final XnioSsl ssl, final InetSocketAddress bindAddress, final URI uri, final Map headers, final ChannelListener openListener, final ChannelListener bindListener, final OptionMap optionMap, final HandshakeChecker handshakeChecker) { this.worker = worker; this.ssl = ssl; this.bindAddress = bindAddress; this.uri = uri; this.openListener = openListener; this.bindListener = bindListener; this.optionMap = optionMap; this.handshakeChecker = handshakeChecker; Map> newHeaders = new HashMap<>(); for(Map.Entry entry : headers.entrySet()) { newHeaders.put(entry.getKey(), Collections.singletonList(entry.getValue())); } this.headers = newHeaders; } private HttpUpgradeState(final XnioWorker worker, final XnioSsl ssl, final InetSocketAddress bindAddress, final URI uri, final Map> headers, final ChannelListener openListener, final ChannelListener bindListener, final OptionMap optionMap, final ExtendedHandshakeChecker handshakeChecker) { this.worker = worker; this.ssl = ssl; this.bindAddress = bindAddress; this.uri = uri; this.headers = headers; this.openListener = openListener; this.bindListener = bindListener; this.optionMap = optionMap; this.handshakeChecker = handshakeChecker; } public HttpUpgradeState(final T connection, final URI uri, final Map headers, final ChannelListener openListener, final HandshakeChecker handshakeChecker) { this.worker = connection.getWorker(); this.ssl = null; this.bindAddress = null; this.uri = uri; this.openListener = openListener; this.bindListener = null; this.optionMap = OptionMap.EMPTY; this.handshakeChecker = handshakeChecker; this.connection = connection; Map> newHeaders = new HashMap<>(); for(Map.Entry entry : headers.entrySet()) { newHeaders.put(entry.getKey(), Collections.singletonList(entry.getValue())); } this.headers = newHeaders; } public HttpUpgradeState(final T connection, final URI uri, final Map> headers, final ChannelListener openListener, final ExtendedHandshakeChecker handshakeChecker) { this.worker = connection.getWorker(); this.ssl = null; this.bindAddress = null; this.uri = uri; this.headers = headers; this.openListener = openListener; this.bindListener = null; this.optionMap = OptionMap.EMPTY; this.handshakeChecker = handshakeChecker; this.connection = connection; } private IoFuture doUpgrade() { InetSocketAddress address = new InetSocketAddress(uri.getHost(), uri.getPort()); final ChannelListener connectListener = new ConnectionOpenListener(); final String scheme = uri.getScheme(); if (scheme.equals("http")) { if (bindAddress == null) { worker.openStreamConnection(address, connectListener, bindListener, optionMap).addNotifier(new FailureNotifier(), null); } else { worker.openStreamConnection(bindAddress, address, connectListener, bindListener, optionMap).addNotifier(new FailureNotifier(), null); } } else if (scheme.equals("https")) { if (ssl == null) { throw msg.missingSslProvider(); } if (bindAddress == null) { ssl.openSslConnection(worker, address, connectListener, bindListener, optionMap).addNotifier(new FailureNotifier(), null); } else { ssl.openSslConnection(worker, bindAddress, address, connectListener, bindListener, optionMap).addNotifier(new FailureNotifier(), null); } } else { throw msg.invalidURLScheme(scheme); } return future.getIoFuture(); } private String buildHttpRequest() { final StringBuilder builder = new StringBuilder(); builder.append("GET "); builder.append(uri.getPath().isEmpty() ? "/" : uri.getPath()); if(uri.getQuery() != null && !uri.getQuery().isEmpty()) { builder.append('?'); builder.append(uri.getQuery()); } builder.append(" HTTP/1.1\r\n"); final Set seen = new HashSet(); for (Map.Entry> headerEntry : headers.entrySet()) { for(String value : headerEntry.getValue()) { builder.append(headerEntry.getKey()); builder.append(": "); builder.append(value); builder.append("\r\n"); seen.add(headerEntry.getKey().toLowerCase(Locale.ENGLISH)); } } if (!seen.contains("host")) { builder.append("Host: "); builder.append(getHost()); builder.append("\r\n"); } if (!seen.contains("connection")) { builder.append("Connection: upgrade\r\n"); } if (!seen.contains("upgrade")) { throw new IllegalArgumentException("Upgrade: header was not supplied in header arguments"); } builder.append("\r\n"); return builder.toString(); } private String getHost() { String scheme = uri.getScheme(); int port = uri.getPort(); if (port < 0 || "http".equals(scheme) && port == 80 || "https".equals(scheme) && port == 443) { // No port or default port. return uri.getHost(); } return uri.getHost() + ":" + port; } public IoFuture upgradeExistingConnection() { final ChannelListener connectListener = new ConnectionOpenListener(); connectListener.handleEvent(connection); return future.getIoFuture(); } private class ConnectionOpenListener implements ChannelListener { @Override public void handleEvent(final StreamConnection channel) { connection = (T) channel; final ByteBuffer buffer = ByteBuffer.wrap(buildHttpRequest().getBytes()); int r; do { try { r = channel.getSinkChannel().write(buffer); if (r == 0) { channel.getSinkChannel().getWriteSetter().set(new StringWriteListener(buffer)); channel.getSinkChannel().resumeWrites(); return; } } catch (IOException e) { safeClose(channel); future.setException(e); return; } } while (buffer.hasRemaining()); flushUpgradeChannel(); } } private void flushUpgradeChannel() { try { if(!connection.getSinkChannel().flush()) { connection.getSinkChannel().getWriteSetter().set(ChannelListeners.flushingChannelListener(new ChannelListener() { @Override public void handleEvent(StreamSinkChannel channel) { channel.suspendWrites(); new UpgradeResultListener().handleEvent(connection.getSourceChannel()); } }, new ChannelExceptionHandler() { @Override public void handleException(StreamSinkChannel channel, IOException exception) { safeClose(channel); future.setException(exception); } })); connection.getSinkChannel().resumeWrites(); return; } } catch (IOException e) { safeClose(connection); future.setException(e); return; } new UpgradeResultListener().handleEvent(connection.getSourceChannel()); } private final class StringWriteListener implements ChannelListener { final ByteBuffer buffer; private StringWriteListener(final ByteBuffer buffer) { this.buffer = buffer; } @Override public void handleEvent(final StreamSinkChannel channel) { int r; do { try { r = channel.write(buffer); if (r == 0) { return; } } catch (IOException e) { safeClose(channel); future.setException(e); return; } } while (buffer.hasRemaining()); channel.suspendWrites(); flushUpgradeChannel(); } } private final class UpgradeResultListener implements ChannelListener { private final HttpUpgradeParser parser = new HttpUpgradeParser(); private ByteBuffer buffer = ByteBuffer.allocate(1024); @Override public void handleEvent(final StreamSourceChannel channel) { int r; do { try { r = channel.read(buffer); if (r == 0) { channel.getReadSetter().set(this); channel.resumeReads(); return; } else if (r == -1) { throw msg.connectionClosedEarly(); } buffer.flip(); parser.parse(buffer); if(!parser.isComplete()) { buffer.compact(); } } catch (IOException e) { safeClose(channel); future.setException(e); return; } } while (!parser.isComplete()); channel.suspendReads(); if (buffer.hasRemaining()) { StreamSourceConduit orig = connection.getSourceChannel().getConduit(); PushBackStreamSourceConduit pushBack = new PushBackStreamSourceConduit(orig); pushBack.pushBack(new Pooled() { @Override public void discard() { buffer = null; } @Override public void free() { buffer = null; } @Override public ByteBuffer getResource() throws IllegalStateException { return buffer; } @Override public void close() { free(); } }); connection.getSourceChannel().setConduit(pushBack); } //ok, we have a response if (parser.getResponseCode() == 101) { // Switching Protocols handleUpgrade(parser); } else if (parser.getResponseCode() == 301 || // Moved Permanently parser.getResponseCode() == 302 || // Found parser.getResponseCode() == 303 || // See Other parser.getResponseCode() == 307 || // Temporary Redirect parser.getResponseCode() == 308) { // Permanent Redirect safeClose(connection); handleRedirect(parser); } else { safeClose(connection); future.setException(new UpgradeFailedException("Invalid response code " + parser.getResponseCode())); } } } private void handleUpgrade(final HttpUpgradeParser parser) { Map simpleHeaders = new HashMap<>(); for(Map.Entry> e : parser.getHeaders().entrySet()) { simpleHeaders.put(e.getKey(), e.getValue().get(0)); } final String contentLength = simpleHeaders.get("content-length"); if (contentLength != null) { if (!"0".equals(contentLength)) { future.setException(new IOException("Upgrade responses must have a content length of zero.")); return; } } final String transferCoding = simpleHeaders.get("transfer-encoding"); if (transferCoding != null) { future.setException(new IOException("Upgrade responses cannot have a transfer coding")); return; } if (handshakeChecker != null) { try { if(handshakeChecker instanceof ExtendedHandshakeChecker) { ((ExtendedHandshakeChecker) handshakeChecker).checkHandshakeExtended(parser.getHeaders()); } else { ((HandshakeChecker)handshakeChecker).checkHandshake(simpleHeaders); } } catch (IOException e) { safeClose(connection); future.setException(e); return; } } future.setResult(connection); ChannelListeners.invokeChannelListener(connection, openListener); } private void handleRedirect(final HttpUpgradeParser parser) { List location = parser.getHeaders().get("location"); future.setException(new RedirectException(msg.redirect(), parser.getResponseCode(), location == null ? null : location.get(0))); } private class FailureNotifier extends IoFuture.HandlingNotifier { @Override public void handleFailed(IOException exception, Object attachment) { future.setException(exception); } @Override public void handleCancelled(Object attachment) { future.setCancelled(); } } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/http/HttpUpgradeParser.java000066400000000000000000000134331257016060700257330ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.http; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.Map; /** * @author Stuart Douglas */ class HttpUpgradeParser { private static final int VERSION = 0; private static final int STATUS_CODE = 1; private static final int MESSAGE = 2; private static final int HEADER_NAME = 3; private static final int HEADER_VALUE = 4; private static final int COMPLETE = 5; private int parseState = 0; private String httpVersion; private int responseCode; private String message; private final Map> headers = new HashMap>(); private final StringBuilder current = new StringBuilder(); private String headerName; void parse(final ByteBuffer buffer) throws IOException { while (buffer.hasRemaining() && !isComplete()) { switch (parseState) { case VERSION: parseVersion(buffer); break; case STATUS_CODE: parseStatusCode(buffer); break; case MESSAGE: parseMessage(buffer); break; case HEADER_NAME: parseHeaderName(buffer); break; case HEADER_VALUE: parseHeaderValue(buffer); break; case COMPLETE: return; } } } private void parseHeaderValue(final ByteBuffer buffer) { while (buffer.hasRemaining()) { byte b = buffer.get(); if (b == '\r' || b == '\n') { String key = headerName.toLowerCase(Locale.ENGLISH); List list = headers.get(key); if(list == null) { headers.put(key, list = new ArrayList()); } list.add(current.toString().trim()); parseState--; current.setLength(0); return; } else { current.append((char) b); } } } private void parseHeaderName(final ByteBuffer buffer) throws IOException { while (buffer.hasRemaining()) { byte b = buffer.get(); if (b == '\r' || b == '\n') { if (current.length() > 2) { throw new IOException("Invalid response"); } else if (current.length() == 2) { //the first /r was consumed by the previous line if (current.charAt(0) == '\n' && current.charAt(1) == '\r' && b == '\n') { parseState = COMPLETE; return; } throw new IOException("Invalid response"); } current.append((char) b); } else if (b == ':') { headerName = current.toString().trim(); parseState++; current.setLength(0); return; } else { current.append((char) b); } } } private void parseMessage(final ByteBuffer buffer) throws IOException { while (buffer.hasRemaining()) { byte b = buffer.get(); if (b == '\r' || b == '\n') { message = current.toString().trim(); parseState++; current.setLength(0); return; } else { current.append((char) b); } } } private void parseStatusCode(final ByteBuffer buffer) throws IOException { while (buffer.hasRemaining()) { byte b = buffer.get(); if (b == '\r' || b == '\n') { throw new IOException("Invalid response"); } else if (b == ' ' || b == '\t') { responseCode = Integer.parseInt(current.toString().trim()); parseState++; current.setLength(0); return; } else { current.append((char) b); } } } private void parseVersion(final ByteBuffer buffer) throws IOException { while (buffer.hasRemaining()) { byte b = buffer.get(); if (b == '\r' || b == '\n') { throw new IOException("Invalid response"); } else if (b == ' ' || b == '\t') { httpVersion = current.toString().trim(); parseState++; current.setLength(0); return; } else { current.append((char) b); } } } boolean isComplete() { return parseState == COMPLETE; } public String getHttpVersion() { return httpVersion; } public int getResponseCode() { return responseCode; } public String getMessage() { return message; } public Map> getHeaders() { return headers; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/http/RedirectException.java000066400000000000000000000065151257016060700257520ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.http; import java.io.IOException; /** * An extension of {@link IOException} used to convey that a connection has failed as a redirect has been encountered. * * @author Darran Lofthouse */ public class RedirectException extends IOException { private final int statusCode; private final String location; /** * Constructs a new {@code RedirectException} instance. The message is left blank ({@code null}), and no cause is * specified. * * @param statusCode the status code * @param location the redirection location, if any */ public RedirectException(final int statusCode, final String location) { this.statusCode = statusCode; this.location = location; } /** * Constructs a new {@code RedirectException} instance with an initial message. No cause is specified. * * @param msg the message * @param statusCode the status code * @param location the redirection location, if any */ public RedirectException(final String msg, final int statusCode, final String location) { super(msg); this.statusCode = statusCode; this.location = location; } /** * Constructs a new {@code RedirectException} instance with an initial cause. If a non-{@code null} cause is * specified, its message is used to initialize the message of this {@code RedirectException}; otherwise the message * is left blank ({@code null}). * * @param cause the cause * @param statusCode the status code * @param location the redirection location, if any */ public RedirectException(final Throwable cause, final int statusCode, final String location) { super(cause); this.statusCode = statusCode; this.location = location; } /** * Constructs a new {@code RedirectException} instance with an initial message and cause. * * @param msg the message * @param cause the cause * @param statusCode the status code * @param location the redirection location, if any */ public RedirectException(final String msg, final Throwable cause, final int statusCode, final String location) { super(msg, cause); this.statusCode = statusCode; this.location = location; } /** * Get the HTTP status code. This is the reason for the redirect. * * @return the status code */ public int getStatusCode() { return statusCode; } /** * Get the redirection target location. * * @return the redirection target location */ public String getLocation() { return location; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/http/UpgradeFailedException.java000066400000000000000000000041721257016060700267020ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2014 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.http; import java.io.IOException; /** * Exception that is thrown when a valid HTTP response is * received that is not an upgrade or redirect response. * * @author Stuart Douglas */ public class UpgradeFailedException extends IOException { private static final long serialVersionUID = 3835377492285694932L; /** * Constructs a new {@code UpgradeFailedException} instance. The message is left blank ({@code null}), and no cause * is specified. */ public UpgradeFailedException() { } /** * Constructs a new {@code UpgradeFailedException} instance with an initial message. No cause is specified. * * @param msg the message */ public UpgradeFailedException(final String msg) { super(msg); } /** * Constructs a new {@code UpgradeFailedException} instance with an initial cause. If a non-{@code null} cause is * specified, its message is used to initialize the message of this {@code UpgradeFailedException}; otherwise the * message is left blank ({@code null}). * * @param cause the cause */ public UpgradeFailedException(final Throwable cause) { super(cause); } /** * Constructs a new {@code UpgradeFailedException} instance with an initial message and cause. * * @param msg the message * @param cause the cause */ public UpgradeFailedException(final String msg, final Throwable cause) { super(msg, cause); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/management/000077500000000000000000000000001257016060700226155ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/java/org/xnio/management/XnioProviderMXBean.java000066400000000000000000000021171257016060700271440ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.management; /** * The MXBean interface for XNIO providers. * * @author David M. Lloyd */ public interface XnioProviderMXBean { /** * Get the provider name. * * @return the provider name */ String getName(); /** * Get the provider version string. * * @return the provider version string */ String getVersion(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/management/XnioServerMXBean.java000066400000000000000000000037251257016060700266260ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.management; /** * @author David M. Lloyd */ public interface XnioServerMXBean { /** * Get the name of the provider. * * @return the name of the provider */ String getProviderName(); /** * Get the worker's name. * * @return the worker's name */ String getWorkerName(); /** * Get the bind address. The address is converted into a readable string form. * * @return the bind address */ String getBindAddress(); /** * Get an estimate of the current connection count. * * @return an estimate of the current connection count */ int getConnectionCount(); /** * Get the connection limit high-water mark. If the connection count hits this number, no new connections * will be accepted until the count drops below the low-water mark. * * @return the connection limit high-water mark */ int getConnectionLimitHighWater(); /** * Get the connection limit low-water mark. If the connection count has previously hit the high water mark, * once it drops back down below this count, connections will be accepted again. * * @return the connection limit low-water mark */ int getConnectionLimitLowWater(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/management/XnioWorkerMXBean.java000066400000000000000000000034511257016060700266250ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.management; /** * @author David M. Lloyd */ public interface XnioWorkerMXBean { /** * Get the name of the provider. * * @return the name of the provider */ String getProviderName(); /** * Get the worker's name. * * @return the worker's name */ String getName(); /** * Determine whether shutdown has been requested for this worker. * * @return {@code true} if shutdown was requested, {@code false} otherwise */ boolean isShutdownRequested(); /** * Get the core worker thread pool size. * * @return the core worker pool size */ int getCoreWorkerPoolSize(); /** * Get the maximum worker thread pool size. * * @return the maximum worker pool size */ int getMaxWorkerPoolSize(); /** * Get the I/O thread count. * * @return the I/O thread count */ int getIoThreadCount(); /** * Get an estimate of the number of tasks in the worker queue. * * @return the task count estimate */ int getWorkerQueueSize(); } xnio-3.3.2.Final/api/src/main/java/org/xnio/package-info.java000066400000000000000000000005031257016060700236660ustar00rootroot00000000000000 /** * The main API package for XNIO. *

* In addition to interfaces that are used and implemented by users of XNIO, this package contains several utility * classes which, while not required to write an XNIO application, simplify boilerplate tasks associated with low-level * I/O operations. */ package org.xnio; xnio-3.3.2.Final/api/src/main/java/org/xnio/sasl/000077500000000000000000000000001257016060700214435ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/java/org/xnio/sasl/SaslQop.java000066400000000000000000000041341257016060700236720ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2009 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.sasl; import static org.xnio._private.Messages.msg; import javax.security.sasl.Sasl; /** * The SASL quality-of-protection value. * * @see Sasl#QOP */ public enum SaslQop { /** * A QOP value specifying authentication only. */ AUTH("auth"), /** * A QOP value specifying authentication plus integrity protection. */ AUTH_INT("auth-int"), /** * A QOP value specifying authentication plus integrity and confidentiality protection. */ AUTH_CONF("auth-conf"), ; private final String s; SaslQop(String s) { this.s = s; } /** * Get the SASL QOP level for the given string. * * @param name the QOP level * @return the QOP value */ public static SaslQop fromString(String name) { if ("auth".equals(name)) { return AUTH; } else if ("auth-int".equals(name)) { return AUTH_INT; } else if ("auth-conf".equals(name)) { return AUTH_CONF; } else { throw msg.invalidQop(name); } } /** * Get the string representation of this SASL QOP value. * * @return the string representation */ public String getString() { return s; } /** * Get the human-readable string representation of this SASL QOP value. * * @return the string representation */ public String toString() { return s; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/sasl/SaslStrength.java000066400000000000000000000017501257016060700247320ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2009 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.sasl; /** * The SASL cipher strength value. * * @see javax.security.sasl.Sasl#STRENGTH */ public enum SaslStrength { /** * Specify low cipher strength. */ LOW, /** * Specify medium cipher strength. */ MEDIUM, /** * Specify high cipher strength. */ HIGH, } xnio-3.3.2.Final/api/src/main/java/org/xnio/sasl/SaslUnwrappingConduit.java000066400000000000000000000052061257016060700266140ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.sasl; import java.io.IOException; import java.nio.ByteBuffer; import org.xnio.Buffers; import org.xnio.conduits.AbstractMessageSinkConduit; import org.xnio.conduits.Conduits; import org.xnio.conduits.MessageSinkConduit; /** * @author David M. Lloyd */ public final class SaslUnwrappingConduit extends AbstractMessageSinkConduit implements MessageSinkConduit { private final SaslWrapper wrapper; private ByteBuffer buffer; public SaslUnwrappingConduit(final MessageSinkConduit next, final SaslWrapper wrapper) { super(next); this.wrapper = wrapper; } public boolean send(final ByteBuffer src) throws IOException { if (! doSend()) { return false; } ByteBuffer wrapped = ByteBuffer.wrap(wrapper.unwrap(src)); if (! next.send(wrapped)) { buffer = wrapped; } return true; } public boolean send(final ByteBuffer[] srcs, final int offs, final int len) throws IOException { if (! doSend()) { return false; } final byte[] bytes = Buffers.take(srcs, offs, len); final ByteBuffer wrapped = ByteBuffer.wrap(wrapper.unwrap(bytes)); if (! next.send(wrapped)) { this.buffer = wrapped; } return true; } @Override public boolean sendFinal(ByteBuffer src) throws IOException { return Conduits.sendFinalBasic(this, src); } @Override public boolean sendFinal(ByteBuffer[] srcs, int offs, int len) throws IOException { return Conduits.sendFinalBasic(this, srcs, offs, len); } private boolean doSend() throws IOException { final ByteBuffer buffer = this.buffer; if (buffer != null && next.send(buffer)) { this.buffer = null; return true; } return false; } public boolean flush() throws IOException { return doSend() && next.flush(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/sasl/SaslUtils.java000066400000000000000000000561071257016060700242420ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.sasl; import static java.security.AccessController.doPrivileged; import static org.xnio._private.Messages.msg; import java.nio.ByteBuffer; import java.security.PrivilegedAction; import java.security.Provider; import java.security.Security; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Locale; import java.util.Map; import java.util.ServiceLoader; import java.util.Set; import org.xnio.Buffers; import org.xnio.Option; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.Property; import org.xnio.Sequence; import javax.security.sasl.Sasl; import javax.security.sasl.SaslClient; import javax.security.sasl.SaslClientFactory; import javax.security.sasl.SaslServer; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServerFactory; /** * Utility methods for handling SASL authentication using NIO-style programming methods. * * @author David M. Lloyd */ public final class SaslUtils { private SaslUtils() { } /** * A zero-length byte array, useful for sending and receiving empty SASL messages. */ public static final byte[] EMPTY_BYTES = new byte[0]; /** * Returns an iterator of all of the registered {@code SaslServerFactory}s where the order is based on the * order of the Provider registration and/or class path order. Class path providers are listed before * global providers; in the event of a name conflict, the class path provider is preferred. * * @param classLoader the class loader to use * @param includeGlobal {@code true} to include globally registered providers, {@code false} to exclude them * @return the {@code Iterator} of {@code SaslServerFactory}s */ public static Iterator getSaslServerFactories(ClassLoader classLoader, boolean includeGlobal) { return getFactories(SaslServerFactory.class, classLoader, includeGlobal); } /** * Returns an iterator of all of the registered {@code SaslServerFactory}s where the order is based on the * order of the Provider registration and/or class path order. * * @return the {@code Iterator} of {@code SaslServerFactory}s */ public static Iterator getSaslServerFactories() { return getFactories(SaslServerFactory.class, null, true); } /** * Returns an iterator of all of the registered {@code SaslClientFactory}s where the order is based on the * order of the Provider registration and/or class path order. Class path providers are listed before * global providers; in the event of a name conflict, the class path provider is preferred. * * @param classLoader the class loader to use * @param includeGlobal {@code true} to include globally registered providers, {@code false} to exclude them * @return the {@code Iterator} of {@code SaslClientFactory}s */ public static Iterator getSaslClientFactories(ClassLoader classLoader, boolean includeGlobal) { return getFactories(SaslClientFactory.class, classLoader, includeGlobal); } /** * Returns an iterator of all of the registered {@code SaslClientFactory}s where the order is based on the * order of the Provider registration and/or class path order. * * @return the {@code Iterator} of {@code SaslClientFactory}s */ public static Iterator getSaslClientFactories() { return getFactories(SaslClientFactory.class, null, true); } private static Iterator getFactories(Class type, ClassLoader classLoader, boolean includeGlobal) { Set factories = new LinkedHashSet(); final ServiceLoader loader = ServiceLoader.load(type, classLoader); for (T factory : loader) { factories.add(factory); } if (includeGlobal) { Set loadedClasses = new HashSet(); final String filter = type.getSimpleName() + "."; Provider[] providers = Security.getProviders(); final SecurityManager sm = System.getSecurityManager(); for (final Provider currentProvider : providers) { final ClassLoader cl = sm == null ? currentProvider.getClass().getClassLoader() : doPrivileged(new PrivilegedAction() { public ClassLoader run() { return currentProvider.getClass().getClassLoader(); } }); for (Object currentKey : currentProvider.keySet()) { if (currentKey instanceof String && ((String) currentKey).startsWith(filter) && ((String) currentKey).indexOf(' ') < 0) { String className = currentProvider.getProperty((String) currentKey); if (className != null && loadedClasses.add(className)) { try { factories.add(Class.forName(className, true, cl).asSubclass(type).newInstance()); } catch (ClassNotFoundException e) { } catch (ClassCastException e) { } catch (InstantiationException e) { } catch (IllegalAccessException e) { } } } } } } return factories.iterator(); } /** * Evaluate a sasl challenge. If the result is {@code false} then the negotiation is not yet complete and the data * written into the destination buffer needs to be sent to the server as a response. If the result is {@code true} * then negotiation was successful and no response needs to be sent to the server. *

* The {@code source} buffer should have its position and remaining length set to encompass exactly one SASL * message. The SASL message itself does not encode any length information so it is up to the protocol implementer * to ensure that the message is properly framed. * * @param client the SASL client to use to evaluate the challenge message * @param destination the destination buffer into which the response message should be written, if any * @param source the source buffer from which the challenge message should be read * @return {@code true} if negotiation is complete and successful, {@code false} otherwise * @throws SaslException if negotiation failed or another error occurred */ public static boolean evaluateChallenge(SaslClient client, ByteBuffer destination, ByteBuffer source) throws SaslException { final byte[] result; result = evaluateChallenge(client, source); if (result != null) { if (destination == null) { throw msg.extraChallenge(); } destination.put(result); return false; } else { return true; } } /** * Evaluate a sasl challenge. If the result is non-{@code null} then the negotiation is not yet complete and the data * returned needs to be sent to the server as a response. If the result is {@code null} * then negotiation was successful and no response needs to be sent to the server. *

* The {@code source} buffer should have its position and remaining length set to encompass exactly one SASL * message. The SASL message itself does not encode any length information so it is up to the protocol implementer * to ensure that the message is properly framed. * * @param client the SASL client to use to evaluate the challenge message * @param source the source buffer from which the challenge message should be read * @return {@code null} if negotiation is complete and successful, or the response otherwise * @throws SaslException if negotiation failed or another error occurred */ public static byte[] evaluateChallenge(SaslClient client, ByteBuffer source) throws SaslException { return client.evaluateChallenge(Buffers.take(source)); } /** * Evaluate a sasl response. If the result is {@code false} then the negotiation is not yet complete and the data * written into the destination buffer needs to be sent to the server as a response. If the result is {@code true} * then negotiation was successful and no response needs to be sent to the client (other than a successful completion * message, depending on the protocol). *

* The {@code source} buffer should have its position and remaining length set to encompass exactly one SASL * message. The SASL message itself does not encode any length information so it is up to the protocol implementer * to ensure that the message is properly framed. * * @param server the SASL server to use to evaluate the response message * @param destination the destination buffer into which the response message should be written, if any * @param source the source buffer from which the response message should be read * @return {@code true} if negotiation is complete and successful, {@code false} otherwise * @throws SaslException if negotiation failed or another error occurred */ public static boolean evaluateResponse(SaslServer server, ByteBuffer destination, ByteBuffer source) throws SaslException { final byte[] result; result = evaluateResponse(server, source); if (result != null) { if (destination == null) { throw msg.extraResponse(); } destination.put(result); return server.isComplete(); } else { return true; } } /** * Evaluate a sasl response. If the result is non-{@code null} then the negotiation is not yet complete and the data * returned needs to be sent to the server as a response. If the result is {@code null} * then negotiation was successful and no response needs to be sent to the client (other than a successful completion * message, depending on the protocol). *

* The {@code source} buffer should have its position and remaining length set to encompass exactly one SASL * message. The SASL message itself does not encode any length information so it is up to the protocol implementer * to ensure that the message is properly framed. * * @param server the SASL server to use to evaluate the response message * @param source the source buffer from which the response message should be read * @return {@code true} if negotiation is complete and successful, {@code false} otherwise * @throws SaslException if negotiation failed or another error occurred */ public static byte[] evaluateResponse(final SaslServer server, final ByteBuffer source) throws SaslException { return server.evaluateResponse(source.hasRemaining() ? Buffers.take(source) : EMPTY_BYTES); } /** * Wrap a message. Wrapping occurs from the source buffer to the destination idea. *

* The {@code source} buffer should have its position and remaining length set to encompass exactly one SASL * message (without the length field). The SASL message itself does not encode any length information so it is up * to the protocol implementer to ensure that the message is properly framed. * * @param client the SASL client to wrap with * @param destination the buffer into which bytes should be written * @param source the buffers from which bytes should be read * @throws SaslException if a SASL error occurs * @see SaslClient#wrap(byte[], int, int) */ public static void wrap(SaslClient client, ByteBuffer destination, ByteBuffer source) throws SaslException { destination.put(wrap(client, source)); } /** * Wrap a message. Wrapping occurs from the source buffer to the destination idea. *

* The {@code source} buffer should have its position and remaining length set to encompass exactly one SASL * message (without the length field). The SASL message itself does not encode any length information so it is up * to the protocol implementer to ensure that the message is properly framed. * * @param client the SASL client to wrap with * @param source the buffers from which bytes should be read * @return the wrap result * @throws SaslException if a SASL error occurs * @see SaslClient#wrap(byte[], int, int) */ public static byte[] wrap(final SaslClient client, final ByteBuffer source) throws SaslException { final byte[] result; final int len = source.remaining(); if (len == 0) { result = client.wrap(EMPTY_BYTES, 0, len); } else if (source.hasArray()) { final byte[] array = source.array(); final int offs = source.arrayOffset(); source.position(source.position() + len); result = client.wrap(array, offs, len); } else { result = client.wrap(Buffers.take(source, len), 0, len); } return result; } /** * Wrap a message. Wrapping occurs from the source buffer to the destination idea. *

* The {@code source} buffer should have its position and remaining length set to encompass exactly one SASL * message (without the length field). The SASL message itself does not encode any length information so it is up * to the protocol implementer to ensure that the message is properly framed. * * @param server the SASL server to wrap with * @param destination the buffer into which bytes should be written * @param source the buffers from which bytes should be read * @throws SaslException if a SASL error occurs * @see SaslServer#wrap(byte[], int, int) */ public static void wrap(SaslServer server, ByteBuffer destination, ByteBuffer source) throws SaslException { destination.put(wrap(server, source)); } /** * Wrap a message. Wrapping occurs from the source buffer to the destination idea. *

* The {@code source} buffer should have its position and remaining length set to encompass exactly one SASL * message (without the length field). The SASL message itself does not encode any length information so it is up * to the protocol implementer to ensure that the message is properly framed. * * @param server the SASL server to wrap with * @param source the buffers from which bytes should be read * @return the wrap result * @throws SaslException if a SASL error occurs * @see SaslServer#wrap(byte[], int, int) */ public static byte[] wrap(final SaslServer server, final ByteBuffer source) throws SaslException { final byte[] result; final int len = source.remaining(); if (len == 0) { result = server.wrap(EMPTY_BYTES, 0, len); } else if (source.hasArray()) { final byte[] array = source.array(); final int offs = source.arrayOffset(); source.position(source.position() + len); result = server.wrap(array, offs, len); } else { result = server.wrap(Buffers.take(source, len), 0, len); } return result; } /** * Unwrap a message. Unwrapping occurs from the source buffer to the destination idea. *

* The {@code source} buffer should have its position and remaining length set to encompass exactly one SASL * message (without the length field). The SASL message itself does not encode any length information so it is up * to the protocol implementer to ensure that the message is properly framed. * * @param client the SASL client to unwrap with * @param destination the buffer into which bytes should be written * @param source the buffers from which bytes should be read * @throws SaslException if a SASL error occurs * @see SaslClient#unwrap(byte[], int, int) */ public static void unwrap(SaslClient client, ByteBuffer destination, ByteBuffer source) throws SaslException { destination.put(unwrap(client, source)); } /** * Unwrap a message. Unwrapping occurs from the source buffer to the destination idea. *

* The {@code source} buffer should have its position and remaining length set to encompass exactly one SASL * message (without the length field). The SASL message itself does not encode any length information so it is up * to the protocol implementer to ensure that the message is properly framed. * * @param client the SASL client to unwrap with * @param source the buffers from which bytes should be read * @return the wrap result * @throws SaslException if a SASL error occurs * @see SaslClient#unwrap(byte[], int, int) */ public static byte[] unwrap(final SaslClient client, final ByteBuffer source) throws SaslException { final byte[] result; final int len = source.remaining(); if (len == 0) { result = client.unwrap(EMPTY_BYTES, 0, len); } else if (source.hasArray()) { final byte[] array = source.array(); final int offs = source.arrayOffset(); source.position(source.position() + len); result = client.unwrap(array, offs, len); } else { result = client.unwrap(Buffers.take(source, len), 0, len); } return result; } /** * Unwrap a message. Unwrapping occurs from the source buffer to the destination idea. *

* The {@code source} buffer should have its position and remaining length set to encompass exactly one SASL * message (without the length field). The SASL message itself does not encode any length information so it is up * to the protocol implementer to ensure that the message is properly framed. * * @param server the SASL server to unwrap with * @param destination the buffer into which bytes should be written * @param source the buffers from which bytes should be read * @throws SaslException if a SASL error occurs * @see SaslServer#unwrap(byte[], int, int) */ public static void unwrap(SaslServer server, ByteBuffer destination, ByteBuffer source) throws SaslException { destination.put(unwrap(server, source)); } /** * Unwrap a message. Unwrapping occurs from the source buffer to the destination idea. *

* The {@code source} buffer should have its position and remaining length set to encompass exactly one SASL * message (without the length field). The SASL message itself does not encode any length information so it is up * to the protocol implementer to ensure that the message is properly framed. * * @param server the SASL server to unwrap with * @param source the buffers from which bytes should be read * @return the wrap result * @throws SaslException if a SASL error occurs * @see SaslServer#unwrap(byte[], int, int) */ public static byte[] unwrap(final SaslServer server, final ByteBuffer source) throws SaslException { final byte[] result; final int len = source.remaining(); if (len == 0) { result = server.unwrap(EMPTY_BYTES, 0, len); } else if (source.hasArray()) { final byte[] array = source.array(); final int offs = source.arrayOffset(); source.position(source.position() + len); result = server.unwrap(array, offs, len); } else { result = server.unwrap(Buffers.take(source, len), 0, len); } return result; } /** * Create a SASL property map from an XNIO option map. * * @param optionMap the option map * @param secure {@code true} if the channel is secure, {@code false} otherwise * @return the property map */ public static Map createPropertyMap(final OptionMap optionMap, final boolean secure) { final Map propertyMap = new HashMap(); add(optionMap, Options.SASL_POLICY_FORWARD_SECRECY, propertyMap, Sasl.POLICY_FORWARD_SECRECY, null); add(optionMap, Options.SASL_POLICY_NOACTIVE, propertyMap, Sasl.POLICY_NOACTIVE, null); add(optionMap, Options.SASL_POLICY_NOANONYMOUS, propertyMap, Sasl.POLICY_NOANONYMOUS, Boolean.TRUE); add(optionMap, Options.SASL_POLICY_NODICTIONARY, propertyMap, Sasl.POLICY_NODICTIONARY, null); add(optionMap, Options.SASL_POLICY_NOPLAINTEXT, propertyMap, Sasl.POLICY_NOPLAINTEXT, Boolean.valueOf(! secure)); add(optionMap, Options.SASL_POLICY_PASS_CREDENTIALS, propertyMap, Sasl.POLICY_PASS_CREDENTIALS, null); add(optionMap, Options.SASL_REUSE, propertyMap, Sasl.REUSE, null); add(optionMap, Options.SASL_SERVER_AUTH, propertyMap, Sasl.SERVER_AUTH, null); addQopList(optionMap, Options.SASL_QOP, propertyMap, Sasl.QOP); add(optionMap, Options.SASL_STRENGTH, propertyMap, Sasl.STRENGTH, null); addSaslProperties(optionMap, Options.SASL_PROPERTIES, propertyMap); return propertyMap; } private static void add(OptionMap optionMap, Option option, Map map, String propName, T defaultVal) { final Object value = optionMap.get(option, defaultVal); if (value != null) map.put(propName, value.toString().toLowerCase(Locale.US)); } private static void addQopList(OptionMap optionMap, Option> option, Map map, String propName) { final Sequence value = optionMap.get(option); if (value == null) return; final Sequence seq = value; final StringBuilder builder = new StringBuilder(); final Iterator iterator = seq.iterator(); if (!iterator.hasNext()) { return; } else do { builder.append(iterator.next().getString()); if (iterator.hasNext()) { builder.append(','); } } while (iterator.hasNext()); map.put(propName, builder.toString()); } private static void addSaslProperties(OptionMap optionMap, Option> option, Map map) { final Sequence value = optionMap.get(option); if (value == null) return; for (Property current : value) { map.put(current.getKey(), current.getValue()); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/sasl/SaslWrapper.java000066400000000000000000000151161257016060700245550ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.sasl; import java.nio.ByteBuffer; import javax.security.sasl.SaslClient; import javax.security.sasl.SaslException; import javax.security.sasl.SaslServer; /** * A wrapper delegation class for SASL that presents the same wrap/unwrap API regardless of whether it is * dealing with a SASL client or server. * * @author David M. Lloyd */ public abstract class SaslWrapper { /** * Wrap a message. * * @param bytes the incoming message * @param off the offset into the byte array * @param len the length of the byte array to wrap * @return the wrap result * @throws SaslException if a problem occurs */ public abstract byte[] wrap(byte[] bytes, int off, int len) throws SaslException; /** * Wrap a message. * * @param bytes the incoming message * @return the wrap result * @throws SaslException if a problem occurs */ public final byte[] wrap(byte[] bytes) throws SaslException { return unwrap(bytes, 0, bytes.length); } /** * Wrap a message. * * @param source the buffer from which bytes should be read * @return the wrap result * @throws SaslException if a problem occurs */ public abstract byte[] wrap(ByteBuffer source) throws SaslException; /** * Unwrap a message. * * @param bytes the incoming message * @param off the offset into the byte array * @param len the length of the byte array to wrap * @return the unwrap result * @throws SaslException if a problem occurs */ public abstract byte[] unwrap(byte[] bytes, int off, int len) throws SaslException; /** * Unwrap a message. * * @param bytes the incoming message * @return the unwrap result * @throws SaslException if a problem occurs */ public final byte[] unwrap(byte[] bytes) throws SaslException { return unwrap(bytes, 0, bytes.length); } /** * Unwrap a message. * * @param source the buffer from which bytes should be read * @return the unwrap result * @throws SaslException if a problem occurs */ public abstract byte[] unwrap(ByteBuffer source) throws SaslException; /** * Wrap a message. Wrapping occurs from the source buffer to the destination idea. *

* The {@code source} buffer should have its position and remaining length set to encompass exactly one SASL message * (without the length field). The SASL message itself does not encode any length information so it is up to the * protocol implementer to ensure that the message is properly framed. * * @param destination the buffer into which bytes should be written * @param source the buffers from which bytes should be read * * @throws SaslException if a SASL error occurs * @see SaslClient#wrap(byte[], int, int) * @see SaslServer#wrap(byte[], int, int) */ public final void wrap(ByteBuffer destination, ByteBuffer source) throws SaslException { destination.put(wrap(source)); } /** * Unwrap a message. Unwrapping occurs from the source buffer to the destination idea. *

* The {@code source} buffer should have its position and remaining length set to encompass exactly one SASL * message (without the length field). The SASL message itself does not encode any length information so it is up * to the protocol implementer to ensure that the message is properly framed. * * @param destination the buffer into which bytes should be written * @param source the buffers from which bytes should be read * @throws SaslException if a SASL error occurs * @see SaslClient#unwrap(byte[], int, int) */ public final void unwrap(ByteBuffer destination, ByteBuffer source) throws SaslException { destination.put(wrap(source)); } /** * Create a SASL wrapper for a SASL client. * * @param saslClient the SASL client * @return the wrapper */ public static SaslWrapper create(SaslClient saslClient) { return new SaslClientWrapper(saslClient); } /** * Create a SASL wrapper for a SASL server. * * @param saslServer the SASL server * @return the wrapper */ public static SaslWrapper create(SaslServer saslServer) { return new SaslServerWrapper(saslServer); } } final class SaslClientWrapper extends SaslWrapper { private final SaslClient saslClient; SaslClientWrapper(final SaslClient saslClient) { this.saslClient = saslClient; } public byte[] wrap(final byte[] bytes, final int off, final int len) throws SaslException { return saslClient.wrap(bytes, off, len); } public byte[] unwrap(final byte[] bytes, final int off, final int len) throws SaslException { return saslClient.unwrap(bytes, off, len); } public byte[] wrap(final ByteBuffer source) throws SaslException { return SaslUtils.wrap(saslClient, source); } public byte[] unwrap(final ByteBuffer source) throws SaslException { return SaslUtils.unwrap(saslClient, source); } } final class SaslServerWrapper extends SaslWrapper { private final SaslServer saslServer; SaslServerWrapper(final SaslServer saslServer) { this.saslServer = saslServer; } public byte[] wrap(final byte[] bytes, final int off, final int len) throws SaslException { return saslServer.wrap(bytes, off, len); } public byte[] unwrap(final byte[] bytes, final int off, final int len) throws SaslException { return saslServer.unwrap(bytes, off, len); } public byte[] wrap(final ByteBuffer source) throws SaslException { return SaslUtils.wrap(saslServer, source); } public byte[] unwrap(final ByteBuffer source) throws SaslException { return SaslUtils.unwrap(saslServer, source); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/sasl/SaslWrappingConduit.java000066400000000000000000000051321257016060700262470ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.sasl; import java.io.IOException; import java.nio.ByteBuffer; import org.xnio.Buffers; import org.xnio.conduits.AbstractMessageSinkConduit; import org.xnio.conduits.Conduits; import org.xnio.conduits.MessageSinkConduit; /** * @author David M. Lloyd */ public final class SaslWrappingConduit extends AbstractMessageSinkConduit implements MessageSinkConduit { private final SaslWrapper wrapper; private ByteBuffer buffer; public SaslWrappingConduit(final MessageSinkConduit next, final SaslWrapper wrapper) { super(next); this.wrapper = wrapper; } public boolean send(final ByteBuffer src) throws IOException { if (! doSend()) { return false; } ByteBuffer wrapped = ByteBuffer.wrap(wrapper.wrap(src)); if (! next.send(wrapped)) { buffer = wrapped; } return true; } public boolean send(final ByteBuffer[] srcs, final int offs, final int len) throws IOException { if (! doSend()) { return false; } final ByteBuffer wrapped = ByteBuffer.wrap(wrapper.wrap(Buffers.take(srcs, offs, len))); if (! next.send(wrapped)) { this.buffer = wrapped; } return true; } @Override public boolean sendFinal(ByteBuffer src) throws IOException { return Conduits.sendFinalBasic(this, src); } @Override public boolean sendFinal(ByteBuffer[] srcs, int offs, int len) throws IOException { return Conduits.sendFinalBasic(this, srcs, offs, len); } private boolean doSend() throws IOException { final ByteBuffer buffer = this.buffer; if (buffer != null && next.send(buffer)) { this.buffer = null; return true; } return false; } public boolean flush() throws IOException { return doSend() && next.flush(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/sasl/package-info.java000066400000000000000000000001431257016060700246300ustar00rootroot00000000000000/** * Utility classes for using SASL mechanisms atop NIO or XNIO APIs. */ package org.xnio.sasl; xnio-3.3.2.Final/api/src/main/java/org/xnio/ssl/000077500000000000000000000000001257016060700213025ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/java/org/xnio/ssl/AbstractAcceptingSslChannel.java000066400000000000000000000300531257016060700275020ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.ssl; import static org.xnio._private.Messages.msg; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.Option; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.Pool; import org.xnio.Sequence; import org.xnio.SslClientAuthMode; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.ConnectedChannel; /** * Abstract Accepting SSL channel. * * @author David M. Lloyd * @author Flavia Rainone */ abstract class AbstractAcceptingSslChannel implements AcceptingChannel { private final SSLContext sslContext; private final AcceptingChannel tcpServer; private volatile SslClientAuthMode clientAuthMode; private volatile int useClientMode; private volatile int enableSessionCreation; private volatile String[] cipherSuites; private volatile String[] protocols; @SuppressWarnings("rawtypes") private static final AtomicReferenceFieldUpdater clientAuthModeUpdater = AtomicReferenceFieldUpdater.newUpdater(AbstractAcceptingSslChannel.class, SslClientAuthMode.class, "clientAuthMode"); @SuppressWarnings("rawtypes") private static final AtomicIntegerFieldUpdater useClientModeUpdater = AtomicIntegerFieldUpdater.newUpdater(AbstractAcceptingSslChannel.class, "useClientMode"); @SuppressWarnings("rawtypes") private static final AtomicIntegerFieldUpdater enableSessionCreationUpdater = AtomicIntegerFieldUpdater.newUpdater(AbstractAcceptingSslChannel.class, "enableSessionCreation"); @SuppressWarnings("rawtypes") private static final AtomicReferenceFieldUpdater cipherSuitesUpdater = AtomicReferenceFieldUpdater.newUpdater(AbstractAcceptingSslChannel.class, String[].class, "cipherSuites"); @SuppressWarnings("rawtypes") private static final AtomicReferenceFieldUpdater protocolsUpdater = AtomicReferenceFieldUpdater.newUpdater(AbstractAcceptingSslChannel.class, String[].class, "protocols"); private final ChannelListener.Setter> closeSetter; private final ChannelListener.Setter> acceptSetter; protected final boolean startTls; protected final Pool socketBufferPool; protected final Pool applicationBufferPool; AbstractAcceptingSslChannel(final SSLContext sslContext, final AcceptingChannel tcpServer, final OptionMap optionMap, final Pool socketBufferPool, final Pool applicationBufferPool, final boolean startTls) { this.tcpServer = tcpServer; this.sslContext = sslContext; this.socketBufferPool = socketBufferPool; this.applicationBufferPool = applicationBufferPool; this.startTls = startTls; clientAuthMode = optionMap.get(Options.SSL_CLIENT_AUTH_MODE); useClientMode = optionMap.get(Options.SSL_USE_CLIENT_MODE, false) ? 1 : 0; enableSessionCreation = optionMap.get(Options.SSL_ENABLE_SESSION_CREATION, true) ? 1 : 0; final Sequence enabledCipherSuites = optionMap.get(Options.SSL_ENABLED_CIPHER_SUITES); cipherSuites = enabledCipherSuites != null ? enabledCipherSuites.toArray(new String[enabledCipherSuites.size()]) : null; final Sequence enabledProtocols = optionMap.get(Options.SSL_ENABLED_PROTOCOLS); protocols = enabledProtocols != null ? enabledProtocols.toArray(new String[enabledProtocols.size()]) : null; //noinspection ThisEscapedInObjectConstruction closeSetter = ChannelListeners.>getDelegatingSetter(tcpServer.getCloseSetter(), this); //noinspection ThisEscapedInObjectConstruction acceptSetter = ChannelListeners.>getDelegatingSetter(tcpServer.getAcceptSetter(), this); } private static final Set> SUPPORTED_OPTIONS = Option.setBuilder() .add(Options.SSL_CLIENT_AUTH_MODE) .add(Options.SSL_USE_CLIENT_MODE) .add(Options.SSL_ENABLE_SESSION_CREATION) .add(Options.SSL_ENABLED_CIPHER_SUITES) .add(Options.SSL_ENABLED_PROTOCOLS) .create(); public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { if (option == Options.SSL_CLIENT_AUTH_MODE) { return option.cast(clientAuthModeUpdater.getAndSet(this, Options.SSL_CLIENT_AUTH_MODE.cast(value))); } else if (option == Options.SSL_USE_CLIENT_MODE) { final Boolean valueObject = Options.SSL_USE_CLIENT_MODE.cast(value); if (valueObject != null) return option.cast(Boolean.valueOf(useClientModeUpdater.getAndSet(this, valueObject.booleanValue() ? 1 : 0) != 0)); } else if (option == Options.SSL_ENABLE_SESSION_CREATION) { final Boolean valueObject = Options.SSL_ENABLE_SESSION_CREATION.cast(value); if (valueObject != null) return option.cast(Boolean.valueOf(enableSessionCreationUpdater.getAndSet(this, valueObject.booleanValue() ? 1 : 0) != 0)); } else if (option == Options.SSL_ENABLED_CIPHER_SUITES) { final Sequence seq = Options.SSL_ENABLED_CIPHER_SUITES.cast(value); return option.cast(cipherSuitesUpdater.getAndSet(this, seq == null ? null : seq.toArray(new String[seq.size()]))); } else if (option == Options.SSL_ENABLED_PROTOCOLS) { final Sequence seq = Options.SSL_ENABLED_PROTOCOLS.cast(value); return option.cast(protocolsUpdater.getAndSet(this, seq == null ? null : seq.toArray(new String[seq.size()]))); } else { return tcpServer.setOption(option, value); } throw msg.nullParameter("value"); } public XnioWorker getWorker() { return tcpServer.getWorker(); } public C accept() throws IOException { final S tcpConnection = tcpServer.accept(); if (tcpConnection == null) { return null; } final InetSocketAddress peerAddress = tcpConnection.getPeerAddress(InetSocketAddress.class); final SSLEngine engine = sslContext.createSSLEngine(JsseSslUtils.getHostNameNoResolve(peerAddress), peerAddress.getPort()); final boolean clientMode = useClientMode != 0; engine.setUseClientMode(clientMode); if (! clientMode) { final SslClientAuthMode clientAuthMode = AbstractAcceptingSslChannel.this.clientAuthMode; if (clientAuthMode != null) switch (clientAuthMode) { case NOT_REQUESTED: engine.setNeedClientAuth(false); engine.setWantClientAuth(false); break; case REQUESTED: engine.setWantClientAuth(true); break; case REQUIRED: engine.setNeedClientAuth(true); break; default: throw new IllegalStateException(); } } engine.setEnableSessionCreation(enableSessionCreation != 0); final String[] cipherSuites = AbstractAcceptingSslChannel.this.cipherSuites; if (cipherSuites != null) { final Set supported = new HashSet(Arrays.asList(engine.getSupportedCipherSuites())); final List finalList = new ArrayList(); for (String name : cipherSuites) { if (supported.contains(name)) { finalList.add(name); } } engine.setEnabledCipherSuites(finalList.toArray(new String[finalList.size()])); } final String[] protocols = AbstractAcceptingSslChannel.this.protocols; if (protocols != null) { final Set supported = new HashSet(Arrays.asList(engine.getSupportedProtocols())); final List finalList = new ArrayList(); for (String name : protocols) { if (supported.contains(name)) { finalList.add(name); } } engine.setEnabledProtocols(finalList.toArray(new String[finalList.size()])); } return accept(tcpConnection, engine); } protected abstract C accept(S tcpServer, SSLEngine sslEngine); public ChannelListener.Setter> getCloseSetter() { return closeSetter; } public boolean isOpen() { return tcpServer.isOpen(); } public void close() throws IOException { tcpServer.close(); } public boolean supportsOption(final Option option) { return SUPPORTED_OPTIONS.contains(option) || tcpServer.supportsOption(option); } public T getOption(final Option option) throws IOException { if (option == Options.SSL_CLIENT_AUTH_MODE) { return option.cast(clientAuthMode); } else if (option == Options.SSL_USE_CLIENT_MODE) { return option.cast(Boolean.valueOf(useClientMode != 0)); } else if (option == Options.SSL_ENABLE_SESSION_CREATION) { return option.cast(Boolean.valueOf(enableSessionCreation != 0)); } else if (option == Options.SSL_ENABLED_CIPHER_SUITES) { final String[] cipherSuites = this.cipherSuites; return cipherSuites == null ? null : option.cast(Sequence.of(cipherSuites)); } else if (option == Options.SSL_ENABLED_PROTOCOLS) { final String[] protocols = this.protocols; return protocols == null ? null : option.cast(Sequence.of(protocols)); } else { return tcpServer.getOption(option); } } public ChannelListener.Setter> getAcceptSetter() { return acceptSetter; } public SocketAddress getLocalAddress() { return tcpServer.getLocalAddress(); } public A getLocalAddress(final Class type) { return tcpServer.getLocalAddress(type); } public void suspendAccepts() { tcpServer.suspendAccepts(); } public void resumeAccepts() { tcpServer.resumeAccepts(); } @Override public boolean isAcceptResumed() { return tcpServer.isAcceptResumed(); } public void wakeupAccepts() { tcpServer.wakeupAccepts(); } public void awaitAcceptable() throws IOException { tcpServer.awaitAcceptable(); } public void awaitAcceptable(final long time, final TimeUnit timeUnit) throws IOException { tcpServer.awaitAcceptable(time, timeUnit); } @Deprecated public XnioExecutor getAcceptThread() { return tcpServer.getAcceptThread(); } public XnioIoThread getIoThread() { return tcpServer.getIoThread(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/ssl/JsseAcceptingSslStreamConnection.java000066400000000000000000000033431257016060700305500ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.ssl; import java.nio.ByteBuffer; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import org.xnio.OptionMap; import org.xnio.Pool; import org.xnio.StreamConnection; import org.xnio.channels.AcceptingChannel; /** * Accepting channel for StreamConnections with SSL. * * @author Flavia Rainone * */ final class JsseAcceptingSslStreamConnection extends AbstractAcceptingSslChannel { JsseAcceptingSslStreamConnection(final SSLContext sslContext, final AcceptingChannel tcpServer, final OptionMap optionMap, final Pool socketBufferPool, final Pool applicationBufferPool, final boolean startTls) { super(sslContext, tcpServer, optionMap, socketBufferPool, applicationBufferPool, startTls); } @Override public SslConnection accept(StreamConnection tcpConnection, SSLEngine engine) { return new JsseSslStreamConnection(tcpConnection, engine, socketBufferPool, applicationBufferPool, startTls); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/ssl/JsseSslConduitEngine.java000066400000000000000000001333451257016060700262200ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import static java.lang.Thread.currentThread; import static java.util.concurrent.locks.LockSupport.park; import static java.util.concurrent.locks.LockSupport.parkNanos; import static java.util.concurrent.locks.LockSupport.unpark; import static org.xnio.Bits.allAreClear; import static org.xnio.Bits.allAreSet; import static org.xnio.Bits.anyAreSet; import static org.xnio.Bits.intBitMask; import static org.xnio._private.Messages.msg; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.net.ssl.SSLException; import javax.net.ssl.SSLHandshakeException; import javax.net.ssl.SSLSession; import org.jboss.logging.Logger; import org.xnio.Buffers; import org.xnio.Pool; import org.xnio.Pooled; import org.xnio.conduits.StreamSinkConduit; import org.xnio.conduits.StreamSourceConduit; /** * {@link SSLEngine} wrapper, used by Jsse SSL conduits. * * @author Flavia Rainone */ final class JsseSslConduitEngine { private static final Logger log = Logger.getLogger("org.xnio.conduits"); private static final String FQCN = JsseSslConduitEngine.class.getName(); // read-side private static final int NEED_WRAP = 1 << 0x00; // conduit cannot be read due to pending wrap private static final int READ_SHUT_DOWN = 1 << 0x01; // user shut down reads private static final int BUFFER_UNDERFLOW = 1 << 0x02; // even though there is data in the buffer there is not enough to form a complete packet @SuppressWarnings("unused") private static final int READ_FLAGS = intBitMask(0x00, 0x0F); // write-side private static final int NEED_UNWRAP = 1 << 0x10; // conduit cannot be written to due to pending unwrap private static final int WRITE_SHUT_DOWN = 1 << 0x11; // user requested shut down of writes private static final int WRITE_COMPLETE = 1 << 0x12; // flush acknowledged full write shutdown private static final int FIRST_HANDSHAKE = 1 << 0x16; // first handshake has not been performed private static final int ENGINE_CLOSED = 1 << 0x17; // engine is fully closed // engine is fully closed @SuppressWarnings("unused") private static final int WRITE_FLAGS = intBitMask(0x10, 0x1F); // empty buffer private static final ByteBuffer EMPTY_BUFFER = ByteBuffer.allocate(0); // final fields /** The SSL engine. */ private final SSLEngine engine; /** The buffer into which incoming SSL data is written. */ private final Pooled receiveBuffer; /** The buffer from which outbound SSL data is sent. */ private final Pooled sendBuffer; /** The buffer into which inbound clear data is written. */ private final Pooled readBuffer; // the next conduits private final StreamSinkConduit sinkConduit; private final StreamSourceConduit sourceConduit; // the connection private final JsseSslStreamConnection connection; // state private volatile int state; private static final AtomicIntegerFieldUpdater stateUpdater = AtomicIntegerFieldUpdater.newUpdater(JsseSslConduitEngine.class, "state"); // waiters @SuppressWarnings("unused") private volatile Thread readWaiter; @SuppressWarnings("unused") private volatile Thread writeWaiter; private static final AtomicReferenceFieldUpdater readWaiterUpdater = AtomicReferenceFieldUpdater.newUpdater(JsseSslConduitEngine.class, Thread.class, "readWaiter"); private static final AtomicReferenceFieldUpdater writeWaiterUpdater = AtomicReferenceFieldUpdater.newUpdater(JsseSslConduitEngine.class, Thread.class, "writeWaiter"); /** * Construct a new instance. * * @param connection the ssl connection associated with this engine * @param sinkConduit the sink channel to use for write operations * @param sourceConduit the source channel to use for read operations * @param engine the SSL engine to use * @param socketBufferPool the socket buffer pool * @param applicationBufferPool the application buffer pool */ JsseSslConduitEngine(final JsseSslStreamConnection connection, final StreamSinkConduit sinkConduit, final StreamSourceConduit sourceConduit, final SSLEngine engine, final Pool socketBufferPool, final Pool applicationBufferPool) { if (connection == null) { throw msg.nullParameter("connection"); } if (sinkConduit == null) { throw msg.nullParameter("sinkConduit"); } if (sourceConduit == null) { throw msg.nullParameter("sourceConduit"); } if (engine == null) { throw msg.nullParameter("engine"); } if (socketBufferPool == null) { throw msg.nullParameter("socketBufferPool"); } if (applicationBufferPool == null) { throw msg.nullParameter("applicationBufferPool"); } this.connection = connection; this.sinkConduit = sinkConduit; this.sourceConduit = sourceConduit; this.engine = engine; this.state = FIRST_HANDSHAKE; final SSLSession session = engine.getSession(); final int packetBufferSize = session.getPacketBufferSize(); boolean ok = false; receiveBuffer = socketBufferPool.allocate(); try { receiveBuffer.getResource().flip(); sendBuffer = socketBufferPool.allocate(); try { if (receiveBuffer.getResource().capacity() < packetBufferSize || sendBuffer.getResource().capacity() < packetBufferSize) { throw msg.socketBufferTooSmall(); } final int applicationBufferSize = session.getApplicationBufferSize(); readBuffer = applicationBufferPool.allocate(); try { if (readBuffer.getResource().capacity() < applicationBufferSize) { throw msg.appBufferTooSmall(); } ok = true; } finally { if (! ok) readBuffer.free(); } } finally { if (! ok) sendBuffer.free(); } } finally { if (! ok) receiveBuffer.free(); } } /** * Begins handshake. * * @throws IOException if an I/O error occurs */ public void beginHandshake() throws IOException { engine.beginHandshake(); } /** * Returns the engine's session. */ public SSLSession getSession() { return engine.getSession(); } /** * Attempt to wrap the bytes in {@code src}. The wrapped bytes can be later retrieved by calling * {@link #getWrappedBuffer()}. *

* If the engine is performing handshake during this request, not all bytes could be wrapped. In this case, a later * call can be performed to attempt to wrap more bytes. *

* This method must not be invoked inside the {@link #getWrapLock() wrap lock}, or else unexpected behavior * could occur. * @param src the bytes to be wrapped * @return the amount of wrapped bytes. * * @throws IOException if an IO exception occurs during wrapping */ public int wrap(final ByteBuffer src) throws IOException { return wrap(src, false); } /** * Attempt to wrap the bytes in {@code srcs}. The wrapped bytes can be later retrieved by calling * {@link #getWrappedBuffer()}. *

* If the engine is performing handshake during this request, not all bytes could be wrapped. In this case, a later * call can be performed to attempt to wrap more bytes. *

* This method must not be invoked inside the {@link #getWrapLock() wrap lock}, or else unexpected behavior * could occur. * * @param srcs contains the bytes to be wrapped * @param offset offset * @param length length * @return the amount of wrapped bytes. * * @throws IOException if an IO exception occurs during wrapping */ public long wrap(final ByteBuffer[] srcs, final int offset, final int length) throws IOException { assert ! Thread.holdsLock(getWrapLock()); assert ! Thread.holdsLock(getUnwrapLock()); if (length < 1) { return 0L; } if (allAreSet(state, WRITE_COMPLETE)) { // atempted write after shutdown, this is // a workaround for a bug found in SSLEngine throw new ClosedChannelException(); } final ByteBuffer buffer = sendBuffer.getResource(); long bytesConsumed = 0; boolean run; try { do { final SSLEngineResult result; synchronized (getWrapLock()) { run = handleWrapResult(result = engineWrap(srcs, offset, length, buffer), false); bytesConsumed += (long) result.bytesConsumed(); } // handshake will tell us whether to keep the loop run = run && (handleHandshake(result, true) || (!isUnwrapNeeded() && Buffers.hasRemaining(srcs, offset, length))); } while (run); } catch (SSLHandshakeException e) { try { synchronized (getWrapLock()) { engine.wrap(EMPTY_BUFFER, sendBuffer.getResource()); doFlush(); } } catch (IOException ignore) {} throw e; } return bytesConsumed; } /** * Returns the buffer that contains the wrapped data. *

* Retrieval and manipulation of this buffer should always be protected by the {@link #getWrapLock() wrap lock}. * * @return the buffer containing wrapped bytes */ public ByteBuffer getWrappedBuffer() { assert Thread.holdsLock(getWrapLock()); assert ! Thread.holdsLock(getUnwrapLock()); return allAreSet(stateUpdater.get(this), ENGINE_CLOSED)? Buffers.EMPTY_BYTE_BUFFER: sendBuffer.getResource(); } /** * Returns the wrap lock, that must be used whenever the {@link #getWrappedBuffer() wrapped buffer} is being * accessed. *

* This lock is also used internally by wrapping operations, thus guaranteeing safe concurrent execution of * both wrap and unwrap operations, specially during handshake handling. * * @return lock for protecting access to the unwrapped buffer */ public Object getWrapLock() { return sendBuffer; } /** * Wrap operation used internally. * * @param src contains the bytes to be wrapped * @param isCloseExpected indicates if close is expected, information that is used to perform special handling * when closing the engine * @return the amount of resulting wrapped bytes * * @throws IOException if an IO exception occurs during wrapping */ private int wrap(final ByteBuffer src, boolean isCloseExpected) throws IOException { assert ! Thread.holdsLock(getWrapLock()); assert ! Thread.holdsLock(getUnwrapLock()); if (allAreSet(state, WRITE_COMPLETE)) { // attempted write after shutdown, this is // a workaround for a bug found in SSLEngine throw new ClosedChannelException(); } clearFlags(FIRST_HANDSHAKE); final ByteBuffer buffer = sendBuffer.getResource(); int bytesConsumed = 0; boolean run; try { do { final SSLEngineResult result; synchronized (getWrapLock()) { run = handleWrapResult(result = engineWrap(src, buffer), isCloseExpected); bytesConsumed += result.bytesConsumed(); } // handshake will tell us whether to keep the loop run = run && bytesConsumed == 0 && (handleHandshake(result, true) || (!isUnwrapNeeded() && src.hasRemaining())); } while (run); } catch (SSLHandshakeException e) { try { synchronized (getWrapLock()) { engine.wrap(EMPTY_BUFFER, sendBuffer.getResource()); doFlush(); } } catch (IOException ignore) {} throw e; } return bytesConsumed; } /** * Invoke inner SSL engine to wrap. */ private SSLEngineResult engineWrap(final ByteBuffer[] srcs, final int offset, final int length, final ByteBuffer dest) throws SSLException { assert Thread.holdsLock(getWrapLock()); assert ! Thread.holdsLock(getUnwrapLock()); log.logf(FQCN, Logger.Level.TRACE, null, "Wrapping %s into %s", srcs, dest); try { return engine.wrap(srcs, offset, length, dest); } catch (SSLHandshakeException e) { try { engine.wrap(srcs, offset, length, dest); doFlush(); } catch (IOException ignore) {} throw e; } } /** * Invoke inner SSL engine to wrap. */ private SSLEngineResult engineWrap(final ByteBuffer src, final ByteBuffer dest) throws SSLException { assert Thread.holdsLock(getWrapLock()); assert ! Thread.holdsLock(getUnwrapLock()); log.logf(FQCN, Logger.Level.TRACE, null, "Wrapping %s into %s", src, dest); return engine.wrap(src, dest); } /** * Handles the wrap result, indicating if caller should perform a new attempt to wrap. * * @param result the wrap result * @param closeExpected is a closed engine result expected * @return {@code true} if a new attempt to wrap should be made * * @throws IOException if an IO exception occurs */ private boolean handleWrapResult(SSLEngineResult result, boolean closeExpected) throws IOException { assert Thread.holdsLock(getWrapLock()); assert ! Thread.holdsLock(getUnwrapLock()); log.logf(FQCN, Logger.Level.TRACE, null, "Wrap result is %s", result); switch (result.getStatus()) { case BUFFER_UNDERFLOW: { assert result.bytesConsumed() == 0; assert result.bytesProduced() == 0; // should not be possible but just to be safe... break; } case BUFFER_OVERFLOW: { assert result.bytesConsumed() == 0; assert result.bytesProduced() == 0; final ByteBuffer buffer = sendBuffer.getResource(); if (buffer.position() == 0) { throw msg.wrongBufferExpansion(); } else { // there's some data in there, so send it first buffer.flip(); try { while (buffer.hasRemaining()) { final int res = sinkConduit.write(buffer); if (res == 0) { return false; } } } finally { buffer.compact(); } } break; } case CLOSED: { if (! closeExpected) { // attempted write after shutdown throw new ClosedChannelException(); } // else treat as OK // fall thru!!! } case OK: { if (result.bytesConsumed() == 0) { if (result.bytesProduced() > 0) { if (! doFlush()) { return false; } } } break; } default: { throw msg.unexpectedWrapResult(result.getStatus()); } } return true; } /** * Handle handshake process, after a wrap or an unwrap operation. * * @param result the wrap/unwrap result * @param write if {@code true}, indicates caller executed a {@code wrap} operation; if {@code false}, indicates * caller executed an {@code unwrap} operation * @return {@code true} to indicate that caller should rerun the previous wrap or unwrap operation, hence * producing a new result; {@code false} to indicate otherwise * * @throws IOException if an IO error occurs during handshake handling */ private boolean handleHandshake(SSLEngineResult result, boolean write) throws IOException { assert ! Thread.holdsLock(getUnwrapLock()); // if read needs wrap, the only possible reason is that something went wrong with flushing, try to flush now if (isWrapNeeded()) { synchronized(getWrapLock()) { if (doFlush()) { clearNeedWrap(); } } } boolean newResult = false; for (;;) { switch (result.getHandshakeStatus()) { case FINISHED: { clearNeedUnwrap(); connection.handleHandshakeFinished(); // Operation can continue immediately return true; } case NOT_HANDSHAKING: { // Operation can continue immediately clearNeedUnwrap(); return false; } case NEED_WRAP: { // clear writeRequiresRead clearNeedUnwrap(); // if write, let caller do the wrap if (write) { return true; } final ByteBuffer buffer = sendBuffer.getResource(); // else, trigger a write call // Needs wrap, so we wrap (if possible)... synchronized (getWrapLock()) { // given caller is reading, tell it to continue only if we can move away from NEED_WRAP // and flush any wrapped data we may have left if (doFlush()) { if (!handleWrapResult(result = engineWrap(Buffers.EMPTY_BYTE_BUFFER, buffer), true) || !doFlush()) { needWrap(); return false; } // success, clear need wrap and handle the new handshake status newResult = true; clearNeedWrap(); continue; } assert !isUnwrapNeeded(); // else... oops, there is unflushed data, and handshake status is NEED_WRAP needWrap(); // tell read caller to break read loop return false; } } case NEED_UNWRAP: { // if read, let caller do the unwrap if (! write) { return newResult; } synchronized(getWrapLock()) { // there could be unflushed data from a previous wrap, make sure everything is flushed at this point doFlush(); } final ByteBuffer buffer = receiveBuffer.getResource(); final ByteBuffer unwrappedBuffer = readBuffer.getResource(); // FIXME this if block is a workaround for a bug in SSLEngine if (result.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP && engine.isOutboundDone()) { synchronized (getUnwrapLock()) { buffer.compact(); sourceConduit.read(buffer); buffer.flip(); if (buffer.hasRemaining() && sourceConduit.isReadResumed()) { sourceConduit.wakeupReads(); } return false; } } synchronized (getUnwrapLock()) { // attempt to unwrap int unwrapResult = handleUnwrapResult(result = engineUnwrap(buffer, unwrappedBuffer)); if (buffer.hasRemaining() && sourceConduit.isReadResumed()) { sourceConduit.wakeupReads(); } if (unwrapResult >= 0) { // have we made some progress? if(result.getHandshakeStatus() != HandshakeStatus.NEED_UNWRAP || result.bytesConsumed() > 0) { clearNeedUnwrap(); continue; } assert !isWrapNeeded(); // no point in proceeding, we're stuck until the user reads anyway needUnwrap(); return false; } else if (unwrapResult == -1 && result.getHandshakeStatus() == HandshakeStatus.NEED_UNWRAP) { if (!allAreSet(state, READ_SHUT_DOWN)) { // connection has been closed by peer prior to handshake finished throw new ClosedChannelException(); } return false; } } continue; } case NEED_TASK: { Runnable task; synchronized (engine) { // run the tasks needed for handshaking while ((task = engine.getDelegatedTask()) != null) { try { task.run(); } catch (Exception e) { throw new IOException(e); } } } // caller should try to wrap/unwrap again return true; } default: throw msg.unexpectedHandshakeStatus(result.getHandshakeStatus()); } } } /** * Unwraps the bytes contained in {@link #getUnwrapBuffer()}, copying the resulting unwrapped bytes into * {@code dst}. *

* If the engine is performing handshake during this request, not all bytes could be unwrapped. In this case, a * later call can be performed to attempt to unwrap more bytes. *

* This method must not be invoked inside the {@link #getUnwrapLock() unwrap lock}, or else unexpected behavior * could occur. * * @param dst where the resulting unwrapped bytes will be copied to * @return the amount of resulting unwrapped bytes * * @throws IOException if an IO exception occurs during unwrapping */ public int unwrap(final ByteBuffer dst) throws IOException { return (int) unwrap(new ByteBuffer[]{dst}, 0, 1); } /** * Unwraps the bytes contained in {@link #getUnwrapBuffer()}, copying the resulting unwrapped bytes into * {@code dsts}. *

* If the engine is performing handshake during this request, not all bytes could be unwrapped. In this case, a * later call can be performed to attempt to unwrap more bytes. *

* This method must not be invoked inside the {@link #getUnwrapLock() unwrap lock}, or else unexpected behavior * could occur. * * @param dsts where the resulting unwrapped bytes will be copied to * @param offset offset * @param length length * @return the amount of resulting unwrapped bytes * * @throws IOException if an IO exception occurs during unwrapping */ public long unwrap(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { assert ! Thread.holdsLock(getUnwrapLock()); assert ! Thread.holdsLock(getWrapLock()); if (dsts.length == 0 || length == 0) { return 0L; } clearFlags(FIRST_HANDSHAKE | BUFFER_UNDERFLOW); final ByteBuffer buffer = receiveBuffer.getResource(); final ByteBuffer unwrappedBuffer = readBuffer.getResource(); long total = 0; SSLEngineResult result; synchronized(getUnwrapLock()) { if (unwrappedBuffer.position() > 0) { total += (long) copyUnwrappedData(dsts, offset, length, unwrappedBuffer); } } int res = 0; try { do { synchronized (getUnwrapLock()) { if (! Buffers.hasRemaining(dsts, offset, length)) { if (unwrappedBuffer.hasRemaining() && sourceConduit.isReadResumed()) { sourceConduit.wakeupReads(); } return total; } res = handleUnwrapResult(result = engineUnwrap(buffer, unwrappedBuffer)); if (unwrappedBuffer.position() > 0) { // test the position of the buffer instead of the // the amount of produced bytes, because in a concurrent scenario, during this loop, // another thread could read more bytes as a side effect of a need unwrap total += (long) copyUnwrappedData(dsts, offset, length, unwrappedBuffer); } } } while ((handleHandshake(result, false) || res > 0)); } catch (SSLHandshakeException e) { try { synchronized (getWrapLock()) { engine.wrap(EMPTY_BUFFER, sendBuffer.getResource()); doFlush(); } } catch (IOException ignore) {} throw e; } if (total == 0L) { if (res == -1) { return -1L; } } if(res == 0 && result.getStatus() == SSLEngineResult.Status.BUFFER_UNDERFLOW) { int old; do { old = state; } while(!stateUpdater.compareAndSet(this, old, old | BUFFER_UNDERFLOW)); } return total; } /** * Returns the buffer that contains the data to be unwrapped. *

* Retrieval and manipulation of this buffer should always be protected by the {@link #getUnwrapLock() unwrap lock}. * * @return the buffer containing bytes to be unwrapped */ public ByteBuffer getUnwrapBuffer() { assert Thread.holdsLock(getUnwrapLock()); assert ! Thread.holdsLock(getWrapLock()); return receiveBuffer.getResource(); } /** * Returns the unwrap lock, that must be used whenever the {@link #getUnwrapBuffer() unwrap buffer} is being * accessed. *

* This lock is also used internally by unwrapping operations, thus guaranteeing safe concurrent execution of * both wrap and unwrap operations, specially during handshake handling. * * @return lock for protecting access to the unwrap buffer */ public Object getUnwrapLock() { return receiveBuffer; } /** * Invoke inner SSL engine to unwrap. */ private SSLEngineResult engineUnwrap(final ByteBuffer buffer, final ByteBuffer unwrappedBuffer) throws IOException { assert Thread.holdsLock(getUnwrapLock()); if (!buffer.hasRemaining()) { buffer.compact(); sourceConduit.read(buffer); buffer.flip(); } log.logf(FQCN, Logger.Level.TRACE, null, "Unwrapping %s into %s", buffer, unwrappedBuffer); return engine.unwrap(buffer, unwrappedBuffer); } /** * Copy unwrapped data from {@code unwrappedBuffer} into {@code dsts}. * * @param dsts destine of copy * @param offset offset * @param length length * @param unwrappedBuffer source from where byte will be copied * @return the amount of copied bytes */ private int copyUnwrappedData(final ByteBuffer[] dsts, final int offset, final int length, ByteBuffer unwrappedBuffer) { assert Thread.holdsLock(getUnwrapLock()); unwrappedBuffer.flip(); try { return Buffers.copy(dsts, offset, length, unwrappedBuffer); } finally { unwrappedBuffer.compact(); } } /** * Handles the unwrap result, indicating how many bytes have been consumed. * * @param result the unwrap result * @return the amount of bytes consumed by unwrap. If the engine is closed and no bytes were consumed, * returns {@code -1}. * * @throws IOException if an IO exception occurs */ private int handleUnwrapResult(final SSLEngineResult result) throws IOException { assert Thread.holdsLock(getUnwrapLock()); log.logf(FQCN, Logger.Level.TRACE, null, "Unwrap result is %s", result); switch (result.getStatus()) { case BUFFER_OVERFLOW: { assert result.bytesConsumed() == 0; assert result.bytesProduced() == 0; // not enough space in destination buffer; caller should flush & retry return 0; } case BUFFER_UNDERFLOW: { assert result.bytesConsumed() == 0; assert result.bytesProduced() == 0; // fill the rest of the buffer, then retry! final ByteBuffer buffer = receiveBuffer.getResource(); synchronized (getUnwrapLock()) { buffer.compact(); try { return sourceConduit.read(buffer); } finally { buffer.flip(); } } } case CLOSED: { // if unwrap processed any data, it should return bytes produced instead of -1 if (result.bytesConsumed() > 0) { return result.bytesConsumed(); } return -1; } case OK: { // continue return result.bytesConsumed(); } default: { throw msg.unexpectedUnwrapResult(result.getStatus()); } } } /** * Flush any data needed for handshaking into the {@link #getWrappedBuffer() wrapped buffer}. *

* The flushed data can later be retrieved by reading the buffer. If the engine is closed, this method can be used * to flush all data associated to engine close messages. * * @return {@code true} if there is no left data to be flushed; {@code false} if for some reason the engine was * unable to flush all data * * @throws IOException if an IO exception occurs during attempt to flush */ public boolean flush() throws IOException { int oldState, newState; oldState = stateUpdater.get(this); if (allAreSet(oldState, WRITE_COMPLETE)) { return true; } synchronized (getWrapLock()) { if (allAreSet(oldState, WRITE_SHUT_DOWN)) { if (!wrapCloseMessage()) { return false; } } else { return true; } } // conclude write newState = oldState | WRITE_COMPLETE; while (! stateUpdater.compareAndSet(this, oldState, newState)) { oldState = stateUpdater.get(this); if (allAreSet(oldState, WRITE_COMPLETE)) { return true;//sinkConduit.flush(); } newState = oldState | WRITE_COMPLETE; } // close the engine if read is shut down if (allAreSet(oldState, READ_SHUT_DOWN)) { closeEngine(true, true); } return true; } /** * Attempt to finish wrapping close handshake bytes. * * @return {@code true} only if all bytes concerning close handshake messages have been wrapped. * @throws IOException if an unexpected IO exception occurs */ private boolean wrapCloseMessage() throws IOException { assert ! Thread.holdsLock(getUnwrapLock()); assert Thread.holdsLock(getWrapLock()); if (sinkConduit.isWriteShutdown()) { return true; } final ByteBuffer buffer = sendBuffer.getResource(); if (!engine.isOutboundDone() || !engine.isInboundDone()) { SSLEngineResult result; do { if (!handleWrapResult(result = engineWrap(Buffers.EMPTY_BYTE_BUFFER, buffer), true)) { return false; } } while (handleHandshake(result, true) && (result.getHandshakeStatus() != HandshakeStatus.NEED_UNWRAP || !engine.isOutboundDone())); handleWrapResult(result = engineWrap(Buffers.EMPTY_BYTE_BUFFER, buffer), true); if (!engine.isOutboundDone() || (result.getHandshakeStatus() != HandshakeStatus.NOT_HANDSHAKING && result.getHandshakeStatus() != HandshakeStatus.NEED_UNWRAP)) { return false; } } return true; } /** * Flushes all data in the wrapped bytes buffer. * * @return {@code true} if all data available has been flushed * * @throws IOException if an unexpected IO exception occurs */ private boolean doFlush() throws IOException { assert Thread.holdsLock(getWrapLock()); assert ! Thread.holdsLock(getUnwrapLock()); final ByteBuffer buffer = sendBuffer.getResource(); buffer.flip(); try { while (buffer.hasRemaining()) { final int res = sinkConduit.write(buffer); if (res == 0) { return false; } } } finally { buffer.compact(); } return sinkConduit.flush(); } /** * Closes this engine for both inbound and outbound, clearing the buffers. * * @param unwrapShutDown {@code true} if unwrap is shutdown * @param wrapShutDown {@code true} if wrap is shutdown * @throws IOException */ private void closeEngine(final boolean unwrapShutDown, final boolean wrapShutDown) throws IOException { int old = setFlags(ENGINE_CLOSED); // idempotent if (allAreSet(old, ENGINE_CLOSED)) { return; } try { if (!unwrapShutDown && !engine.isInboundDone()) { engine.closeInbound(); } if (! wrapShutDown) { engine.closeOutbound(); } synchronized(getWrapLock()) { if (! doFlush()) { throw msg.unflushedData(); } } } finally { readBuffer.free(); receiveBuffer.free(); sendBuffer.free(); } } /** * Signals that no outbound data will be sent. * * @throws IOException if an IO exception occurs */ public void closeOutbound() throws IOException { int old = setFlags(WRITE_SHUT_DOWN); try { if (allAreClear(old, WRITE_SHUT_DOWN)) { engine.closeOutbound(); synchronized (getWrapLock()) { wrapCloseMessage(); flush(); } } if (!allAreClear(old, READ_SHUT_DOWN)) { closeEngine(true, true); } } catch (Exception e) { //if there is an exception on close we immediately close the engine to make sure buffers are freed closeEngine(true, true); if(e instanceof IOException) { throw (IOException)e; } else if(e instanceof RuntimeException) { throw (RuntimeException)e; } else { throw new RuntimeException(e); //should not happen } } } /** * Indicates if outbound is closed. * * @throws IOException if an IO exception occurs */ public boolean isOutboundClosed() { return allAreSet(stateUpdater.get(this), WRITE_SHUT_DOWN); } /** * Block until this engine can wrap messages. *

* The engine may be unable to wrap if a handshake message needs to be unwrapped first. In this case, this thread * will be awakened as soon as the message is made available for reading by the internal source conduit. * * @throws IOException if an IO exception occurs during await */ public void awaitCanWrap() throws IOException { int oldState = state; if (anyAreSet(oldState, WRITE_SHUT_DOWN) || !allAreSet(oldState, NEED_UNWRAP)) { return; } final Thread thread = currentThread(); final Thread next = writeWaiterUpdater.getAndSet(this, thread); try { if (anyAreSet(oldState = state, WRITE_SHUT_DOWN)) { return; } if (allAreSet(oldState, NEED_UNWRAP)) { unwrap(Buffers.EMPTY_BYTE_BUFFER); } park(this); if (thread.isInterrupted()) { throw msg.interruptedIO(); } } finally { // always unpark because we cannot know if our awaken was spurious if (next != null) unpark(next); } } /** * Block until this engine can wrap messages. *

* The engine may be unable to wrap if a handshake message needs to be unwrapped first. In this case, this thread * will be awakened as soon as the message is made available for reading by the internal source conduit. * * @param time timeout for blocking * @param timeUnit timeout unit * @throws IOException if an IO exception occurs during await */ public void awaitCanWrap(long time, TimeUnit timeUnit) throws IOException { int oldState = state; if (anyAreSet(oldState, WRITE_SHUT_DOWN) || !allAreSet(oldState, NEED_UNWRAP)) { return; } final Thread thread = currentThread(); final Thread next = writeWaiterUpdater.getAndSet(this, thread); long duration = timeUnit.toNanos(time); try { if (anyAreSet(oldState = state, WRITE_SHUT_DOWN)) { return; } if (allAreSet(oldState, NEED_UNWRAP)) { unwrap(Buffers.EMPTY_BYTE_BUFFER); } parkNanos(this, duration); if (thread.isInterrupted()) { throw msg.interruptedIO(); } } finally { // always unpark because we cannot know if our awaken was spurious if (next != null) unpark(next); } } /** * Signals that no inbound data will be read * * @throws IOException if an IO exception occurs */ public void closeInbound() throws IOException { int old = setFlags(READ_SHUT_DOWN); try { if (allAreClear(old, READ_SHUT_DOWN)) { sourceConduit.terminateReads(); } if (allAreSet(old, WRITE_SHUT_DOWN) && !allAreSet(old, WRITE_COMPLETE)) { synchronized (getWrapLock()) { wrapCloseMessage(); flush(); } } if (allAreSet(old, WRITE_COMPLETE)) { closeEngine(true, true); } } catch (Exception e) { //if there is an exception on close we immediately close the engine to make sure buffers are freed closeEngine(true, true); if(e instanceof IOException) { throw (IOException)e; } else if(e instanceof RuntimeException) { throw (RuntimeException)e; } else { throw new RuntimeException(e); //should not happen } } } /** * Indicates if inbound is closed. * * @throws IOException if an IO exception occurs */ public boolean isInboundClosed() { return allAreSet(state, READ_SHUT_DOWN); } /** * Indicates if engine is closed. * */ public boolean isClosed() { return allAreSet(state, ENGINE_CLOSED); } /** * Block until this engine can unwrap messages. * * @throws IOException if an IO exception occurs during await */ public void awaitCanUnwrap() throws IOException { int oldState = state; if (anyAreSet(oldState, READ_SHUT_DOWN) || ! anyAreSet(oldState, NEED_WRAP)) { return; } final Thread thread = currentThread(); final Thread next = readWaiterUpdater.getAndSet(this, thread); try { if (anyAreSet(oldState = state, READ_SHUT_DOWN)) { return; } if (allAreSet(oldState, NEED_WRAP)) { wrap(Buffers.EMPTY_BYTE_BUFFER); } park(this); if (thread.isInterrupted()) { throw msg.interruptedIO(); } } finally { // always unpark because we cannot know if our awaken was spurious if (next != null) unpark(next); } } /** * Block until this engine can unwrap messages. * * @param time timeout for blocking * @param timeUnit timeout unit * @throws IOException if an IO exception occurs during await */ public void awaitCanUnwrap(long time, TimeUnit timeUnit) throws IOException { int oldState = state; if (anyAreSet(oldState, READ_SHUT_DOWN) || ! anyAreSet(oldState, NEED_WRAP)) { return; } final Thread thread = currentThread(); final Thread next = readWaiterUpdater.getAndSet(this, thread); long duration = timeUnit.toNanos(time); try { if (anyAreSet(oldState = state, READ_SHUT_DOWN)) { return; } if (allAreSet(oldState, NEED_WRAP)) { wrap(Buffers.EMPTY_BYTE_BUFFER); } parkNanos(this, duration); if (thread.isInterrupted()) { throw msg.interruptedIO(); } } finally { // always unpark because we cannot know if our awaken was spurious if (next != null) unpark(next); } } public boolean isFirstHandshake() { return allAreSet(state, FIRST_HANDSHAKE); } SSLEngine getEngine() { return engine; } /** * Indicate that the engine will not be able unwrap before a successful wrap is performed. */ private void needWrap() { setFlags(NEED_WRAP); } /** * Indicate if the engine can unwrap. */ private boolean isWrapNeeded() { return allAreSet(state, NEED_WRAP); } /** * Indicate that the engine no longer requires a successful wrap to proceed with unwrap operations. */ private void clearNeedWrap() { clearFlags(NEED_WRAP); } /** * Indicate that the engine will not be able wrap before a successful unwrap is performed. */ private void needUnwrap() { setFlags(NEED_UNWRAP); } /** * Indicate if the engine can wrap. */ private boolean isUnwrapNeeded() { return allAreSet(state, NEED_UNWRAP); } /** * Indicates that even though there is data available there is not enough to form a complete packet */ private boolean isUnderflow() { return allAreSet(state, BUFFER_UNDERFLOW); } /** * Indicate that the engine no longer requires a successful unwrap to proceed with wrap operations. */ private void clearNeedUnwrap() { clearFlags(NEED_UNWRAP); } private int setFlags(int flags) { int oldState; do { oldState = state; if ((oldState & flags) == flags) { return oldState; } } while (! stateUpdater.compareAndSet(this, oldState, oldState | flags)); return oldState; } private int clearFlags(int flags) { int oldState; do { oldState = state; if ((oldState & flags) == 0) { return oldState; } } while (! stateUpdater.compareAndSet(this, oldState, oldState & ~flags)); return oldState; } public boolean isDataAvailable() { synchronized (getUnwrapLock()) { return readBuffer.getResource().hasRemaining() || (receiveBuffer.getResource().hasRemaining() && !isUnderflow()); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/ssl/JsseSslStreamConnection.java000066400000000000000000000150031257016060700267260ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.ssl; import static org.xnio.IoUtils.safeClose; import java.io.IOException; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.util.Set; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLSession; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.Option; import org.xnio.Options; import org.xnio.Pool; import org.xnio.SslClientAuthMode; import org.xnio.StreamConnection; import org.xnio.conduits.StreamSinkConduit; import org.xnio.conduits.StreamSourceConduit; /** * StreamConnection with SSL support. * * @author Flavia Rainone * */ final class JsseSslStreamConnection extends SslConnection { /** * Delegate connection. */ private final StreamConnection connection; /** * The conduit SSl engine. */ private final JsseSslConduitEngine sslConduitEngine; /** * Indicates if tls is enabled. */ private volatile boolean tls; /** * Callback for notification of a handshake being finished. */ private final ChannelListener.SimpleSetter handshakeSetter = new ChannelListener.SimpleSetter(); JsseSslStreamConnection(StreamConnection connection, SSLEngine sslEngine, final Pool socketBufferPool, final Pool applicationBufferPool, final boolean startTls) { super(connection.getIoThread()); this.connection = connection; final StreamSinkConduit sinkConduit = connection.getSinkChannel().getConduit(); final StreamSourceConduit sourceConduit = connection.getSourceChannel().getConduit(); sslConduitEngine = new JsseSslConduitEngine(this, sinkConduit, sourceConduit, sslEngine, socketBufferPool, applicationBufferPool); tls = ! startTls; setSinkConduit(new JsseSslStreamSinkConduit(sinkConduit, sslConduitEngine, tls)); setSourceConduit(new JsseSslStreamSourceConduit(sourceConduit, sslConduitEngine, tls)); } /** {@inheritDoc} */ @Override public synchronized void startHandshake() throws IOException { if (! tls) { tls = true; ((JsseSslStreamSourceConduit) getSourceChannel().getConduit()).enableTls(); ((JsseSslStreamSinkConduit) getSinkChannel().getConduit()).enableTls(); } sslConduitEngine.beginHandshake(); } /** {@inheritDoc} */ @Override public SocketAddress getPeerAddress() { return connection.getPeerAddress(); } /** {@inheritDoc} */ @Override public SocketAddress getLocalAddress() { return connection.getLocalAddress(); } /** {@inheritDoc} */ @Override protected void closeAction() throws IOException { if (tls) { try { sslConduitEngine.closeOutbound(); } catch (IOException e) { try { sslConduitEngine.closeInbound(); } catch (IOException ignored) { } safeClose(connection); throw e; } try { sslConduitEngine.closeInbound(); } catch (IOException e) { safeClose(connection); throw e; } } connection.close(); } /** {@inheritDoc} */ @Override protected void notifyWriteClosed() {} /** {@inheritDoc} */ @Override protected void notifyReadClosed() {} /** {@inheritDoc} */ @Override public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { if (option == Options.SSL_CLIENT_AUTH_MODE) { final SSLEngine engine = sslConduitEngine.getEngine(); try { return option.cast(engine.getNeedClientAuth() ? SslClientAuthMode.REQUIRED : engine.getWantClientAuth() ? SslClientAuthMode.REQUESTED : SslClientAuthMode.NOT_REQUESTED); } finally { engine.setNeedClientAuth(value == SslClientAuthMode.REQUIRED); engine.setWantClientAuth(value == SslClientAuthMode.REQUESTED); } } else if (option == Options.SECURE) { throw new IllegalArgumentException(); } else { return connection.setOption(option, value); } } /** {@inheritDoc} */ @Override public T getOption(final Option option) throws IOException { if (option == Options.SSL_CLIENT_AUTH_MODE) { final SSLEngine engine = sslConduitEngine.getEngine(); return option.cast(engine.getNeedClientAuth() ? SslClientAuthMode.REQUIRED : engine.getWantClientAuth() ? SslClientAuthMode.REQUESTED : SslClientAuthMode.NOT_REQUESTED); } else { return option == Options.SECURE ? option.cast(Boolean.valueOf(tls)) : connection.getOption(option); } } private static final Set> SUPPORTED_OPTIONS = Option.setBuilder().add(Options.SECURE, Options.SSL_CLIENT_AUTH_MODE).create(); /** {@inheritDoc} */ @Override public boolean supportsOption(final Option option) { return SUPPORTED_OPTIONS.contains(option) || connection.supportsOption(option); } /** {@inheritDoc} */ @Override public SSLSession getSslSession() { return tls ? sslConduitEngine.getSession() : null; } @Override public org.xnio.ChannelListener.Setter getHandshakeSetter() { return handshakeSetter; } SSLEngine getEngine() { return sslConduitEngine.getEngine(); } /** * Callback method for notification of handshake finished. */ protected void handleHandshakeFinished() { final ChannelListener listener = handshakeSetter.get(); if (listener == null) { return; } ChannelListeners.invokeChannelListener(this, listener); } }xnio-3.3.2.Final/api/src/main/java/org/xnio/ssl/JsseSslStreamSinkConduit.java000066400000000000000000000151041257016060700270630ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.ssl; import static org.xnio._private.Messages.msg; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import org.xnio.channels.StreamSourceChannel; import org.xnio.conduits.AbstractStreamSinkConduit; import org.xnio.conduits.ConduitWritableByteChannel; import org.xnio.conduits.Conduits; import org.xnio.conduits.StreamSinkConduit; /** * Jsse SSL source conduit implementation based on {@link JsseSslConduitEngine}. * * @author Flavia Rainone * */ final class JsseSslStreamSinkConduit extends AbstractStreamSinkConduit { private final JsseSslConduitEngine sslEngine; private volatile boolean tls; protected JsseSslStreamSinkConduit(StreamSinkConduit next, JsseSslConduitEngine sslEngine, boolean tls) { super(next); if (sslEngine == null) { throw msg.nullParameter("sslEngine"); } this.sslEngine = sslEngine; this.tls = tls; } public void enableTls() { tls = true; if (isWriteResumed()) { wakeupWrites(); } } @Override public long transferFrom(final FileChannel src, final long position, final long count) throws IOException { return src.transferTo(position, count, new ConduitWritableByteChannel(this)); } @Override public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { return Conduits.transfer(source, count, throughBuffer, this); } @Override public int write(ByteBuffer src) throws IOException { return write(src, false); } @Override public long write(ByteBuffer[] srcs, int offs, int len) throws IOException { return write(srcs, offs, len, false); } @Override public int writeFinal(ByteBuffer src) throws IOException { return write(src, true); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { return write(srcs, offset, length, true); } private int write(ByteBuffer src, boolean writeFinal) throws IOException { if (!tls) { if(writeFinal) { return next.writeFinal(src); } else { return next.write(src); } } final int wrappedBytes = sslEngine.wrap(src); if (wrappedBytes > 0) { writeWrappedBuffer(writeFinal); } return wrappedBytes; } private long write(ByteBuffer[] srcs, int offs, int len, boolean writeFinal) throws IOException { if (!tls) { if(writeFinal) { return super.writeFinal(srcs, offs, len); } else { return super.write(srcs, offs, len); } } final long wrappedBytes = sslEngine.wrap(srcs, offs, len); if (wrappedBytes > 0) { writeWrappedBuffer(writeFinal); } return wrappedBytes; } @Override public void resumeWrites() { if (tls && sslEngine.isFirstHandshake()) { super.wakeupWrites(); } else { super.resumeWrites(); } } @Override public void terminateWrites() throws IOException { if (!tls) { super.terminateWrites(); return; } try { sslEngine.closeOutbound(); flush(); } catch (IOException e) { try { super.truncateWrites(); } catch (IOException ignored) { } throw e; } } @Override public void awaitWritable() throws IOException { if (tls) { sslEngine.awaitCanWrap(); } super.awaitWritable(); } @Override public void awaitWritable(long time, TimeUnit timeUnit) throws IOException { if (!tls) { super.awaitWritable(time, timeUnit); return; } long duration = timeUnit.toNanos(time); long awaited = System.nanoTime(); sslEngine.awaitCanWrap(time, timeUnit); awaited = System.nanoTime() - awaited; if (awaited > duration) { return; } super.awaitWritable(duration - awaited, TimeUnit.NANOSECONDS); } @Override public void truncateWrites() throws IOException { if (tls) try { sslEngine.closeOutbound(); } finally { try { super.truncateWrites(); } catch (IOException ignored) { } } super.truncateWrites(); } @Override public boolean flush() throws IOException { if (!tls) { return super.flush(); } if (sslEngine.isOutboundClosed()) { if (sslEngine.flush() && writeWrappedBuffer(false) && super.flush()) { super.terminateWrites(); return true; } else { return false; } } return sslEngine.flush() && writeWrappedBuffer(false) && super.flush(); } private boolean writeWrappedBuffer(boolean writeFinal) throws IOException { synchronized (sslEngine.getWrapLock()) { final ByteBuffer wrapBuffer = sslEngine.getWrappedBuffer(); for (;;) { try { if (!wrapBuffer.flip().hasRemaining()) { return true; } if(writeFinal) { if (super.writeFinal(wrapBuffer) == 0) { return false; } } else { if (super.write(wrapBuffer) == 0) { return false; } } } finally { wrapBuffer.compact(); } } } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/ssl/JsseSslStreamSourceConduit.java000066400000000000000000000127541257016060700274270ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.ssl; import static org.xnio._private.Messages.msg; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import org.xnio.Buffers; import org.xnio.channels.StreamSinkChannel; import org.xnio.conduits.AbstractStreamSourceConduit; import org.xnio.conduits.ConduitReadableByteChannel; import org.xnio.conduits.Conduits; import org.xnio.conduits.StreamSourceConduit; /** * Jsse SSL source conduit implementation based on {@link JsseSslConduitEngine}. * * @author Flavia Rainone * */ final class JsseSslStreamSourceConduit extends AbstractStreamSourceConduit { private final JsseSslConduitEngine sslEngine; private volatile boolean tls; protected JsseSslStreamSourceConduit(StreamSourceConduit next, JsseSslConduitEngine sslEngine, boolean tls) { super(next); if (sslEngine == null) { throw msg.nullParameter("sslEngine"); } this.sslEngine = sslEngine; this.tls = tls; } void enableTls() { tls = true; if (isReadResumed()) { wakeupReads(); } } @Override public long transferTo(final long position, final long count, final FileChannel target) throws IOException { return target.transferFrom(new ConduitReadableByteChannel(this), position, count); } @Override public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { return Conduits.transfer(this, count, throughBuffer, target); } @Override public int read(ByteBuffer dst) throws IOException { if (!tls) { return super.read(dst); } if ((!sslEngine.isDataAvailable() && sslEngine.isInboundClosed()) || sslEngine.isClosed()) { return -1; } final int readResult; final int unwrapResult; synchronized(sslEngine.getUnwrapLock()) { final ByteBuffer unwrapBuffer = sslEngine.getUnwrapBuffer().compact(); try { readResult = super.read(unwrapBuffer); } finally { unwrapBuffer.flip(); } } unwrapResult = sslEngine.unwrap(dst); if (unwrapResult == 0 && readResult == -1) { return -1; } return unwrapResult; } @Override public long read(ByteBuffer[] dsts, int offs, int len) throws IOException { if (!tls) { return super.read(dsts, offs, len); } if (offs < 0 || offs > len || len < 0 || offs + len > dsts.length) { throw new ArrayIndexOutOfBoundsException(); } if ((!sslEngine.isDataAvailable() && sslEngine.isInboundClosed()) || sslEngine.isClosed()) { return -1; } final int readResult; final long unwrapResult; synchronized (sslEngine.getUnwrapLock()) { // retrieve buffer from sslEngine, to save some memory space final ByteBuffer unwrapBuffer = sslEngine.getUnwrapBuffer().compact(); try { readResult = super.read(unwrapBuffer); } finally { unwrapBuffer.flip(); } } unwrapResult = sslEngine.unwrap(dsts, offs, len); if (unwrapResult == 0 && readResult == -1) { return -1; } return unwrapResult; } @Override public void resumeReads() { if (tls && sslEngine.isFirstHandshake()) { super.wakeupReads(); } else { super.resumeReads(); } } @Override public void terminateReads() throws IOException { if (tls) { // do not close inbound, this will have the effect of closing outbound too sslEngine.closeInbound(); super.suspendReads(); return; } super.terminateReads(); } @Override public void awaitReadable() throws IOException { if (tls) { sslEngine.awaitCanUnwrap(); } if(sslEngine.isDataAvailable()) { return; } super.awaitReadable(); } @Override public void awaitReadable(long time, TimeUnit timeUnit) throws IOException { if (!tls) { super.awaitReadable(time, timeUnit); return; } synchronized (sslEngine.getUnwrapLock()) { if(sslEngine.getUnwrapBuffer().hasRemaining()) { return; } } long duration = timeUnit.toNanos(time); long awaited = System.nanoTime(); sslEngine.awaitCanUnwrap(time, timeUnit); awaited = System.nanoTime() - awaited; if (awaited > duration) { return; } super.awaitReadable(duration - awaited, TimeUnit.NANOSECONDS); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/ssl/JsseSslUtils.java000066400000000000000000000210301257016060700245500ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import static org.xnio._private.Messages.msg; import java.lang.reflect.InvocationTargetException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.security.SecureRandom; import java.util.ArrayList; import java.util.Arrays; import java.util.HashSet; import java.util.List; import java.util.Set; import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import javax.net.ssl.TrustManager; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.Sequence; import org.xnio.Xnio; /** * Utility methods for creating JSSE constructs and configuring them via XNIO option maps. * * @author David M. Lloyd */ public final class JsseSslUtils { private JsseSslUtils() { } /** * Create a new SSL context, configured from an option map. * * @param optionMap the SSL context options * @return a new context * @throws NoSuchProviderException if there is no matching provider * @throws NoSuchAlgorithmException if there is no matching algorithm * @throws KeyManagementException if the context initialization fails */ public static SSLContext createSSLContext(OptionMap optionMap) throws NoSuchProviderException, NoSuchAlgorithmException, KeyManagementException { return createSSLContext(null, null, null, optionMap); } /** * Create a new SSL context, configured from an option map and the given parameters. * * @param keyManagers the key managers to use, or {@code null} to configure from the option map * @param trustManagers the trust managers to use, or {@code null} to configure from the option map * @param secureRandom the secure RNG to use, or {@code null} to choose a system default * @param optionMap the SSL context options * @return a new context * @throws NoSuchProviderException if there is no matching provider * @throws NoSuchAlgorithmException if there is no matching algorithm * @throws KeyManagementException if the context initialization fails */ public static SSLContext createSSLContext(KeyManager[] keyManagers, TrustManager[] trustManagers, SecureRandom secureRandom, OptionMap optionMap) throws NoSuchAlgorithmException, NoSuchProviderException, KeyManagementException { final String provider = optionMap.get(Options.SSL_PROVIDER); final String protocol = optionMap.get(Options.SSL_PROTOCOL); final SSLContext sslContext; if (protocol == null) { // Default context is initialized automatically return SSLContext.getDefault(); } else if (provider == null) { sslContext = SSLContext.getInstance(protocol); } else { sslContext = SSLContext.getInstance(protocol, provider); } if (keyManagers == null) { final Sequence> keyManagerClasses = optionMap.get(Options.SSL_JSSE_KEY_MANAGER_CLASSES); if (keyManagerClasses != null) { final int size = keyManagerClasses.size(); keyManagers = new KeyManager[size]; for (int i = 0; i < size; i ++) { keyManagers[i] = instantiate(keyManagerClasses.get(i)); } } } if (trustManagers == null) { final Sequence> trustManagerClasses = optionMap.get(Options.SSL_JSSE_TRUST_MANAGER_CLASSES); if (trustManagerClasses != null) { final int size = trustManagerClasses.size(); trustManagers = new TrustManager[size]; for (int i = 0; i < size; i ++) { trustManagers[i] = instantiate(trustManagerClasses.get(i)); } } } sslContext.init(keyManagers, trustManagers, secureRandom); sslContext.getClientSessionContext().setSessionCacheSize(optionMap.get(Options.SSL_CLIENT_SESSION_CACHE_SIZE, 0)); sslContext.getClientSessionContext().setSessionTimeout(optionMap.get(Options.SSL_CLIENT_SESSION_TIMEOUT, 0)); sslContext.getServerSessionContext().setSessionCacheSize(optionMap.get(Options.SSL_SERVER_SESSION_CACHE_SIZE, 0)); sslContext.getServerSessionContext().setSessionTimeout(optionMap.get(Options.SSL_SERVER_SESSION_TIMEOUT, 0)); return sslContext; } @SuppressWarnings("TryWithIdenticalCatches") private static T instantiate(Class clazz) { try { return clazz.getConstructor().newInstance(); } catch (InstantiationException e) { throw msg.cantInstantiate(clazz, e); } catch (IllegalAccessException e) { throw msg.cantInstantiate(clazz, e); } catch (NoSuchMethodException e) { throw msg.cantInstantiate(clazz, e); } catch (InvocationTargetException e) { throw msg.cantInstantiate(clazz, e.getCause()); } } /** * Create a new client mode SSL engine, configured from an option map. * * @param sslContext the SSL context * @param optionMap the SSL options * @param peerAddress the peer address of the connection * @return the configured SSL engine */ public static SSLEngine createSSLEngine(SSLContext sslContext, OptionMap optionMap, InetSocketAddress peerAddress) { final SSLEngine engine = sslContext.createSSLEngine( optionMap.get(Options.SSL_PEER_HOST_NAME, getHostNameNoResolve(peerAddress)), optionMap.get(Options.SSL_PEER_PORT, peerAddress.getPort()) ); engine.setUseClientMode(true); engine.setEnableSessionCreation(optionMap.get(Options.SSL_ENABLE_SESSION_CREATION, true)); final Sequence cipherSuites = optionMap.get(Options.SSL_ENABLED_CIPHER_SUITES); if (cipherSuites != null) { final Set supported = new HashSet(Arrays.asList(engine.getSupportedCipherSuites())); final List finalList = new ArrayList(); for (String name : cipherSuites) { if (supported.contains(name)) { finalList.add(name); } } engine.setEnabledCipherSuites(finalList.toArray(new String[finalList.size()])); } final Sequence protocols = optionMap.get(Options.SSL_ENABLED_PROTOCOLS); if (protocols != null) { final Set supported = new HashSet(Arrays.asList(engine.getSupportedProtocols())); final List finalList = new ArrayList(); for (String name : protocols) { if (supported.contains(name)) { finalList.add(name); } } engine.setEnabledProtocols(finalList.toArray(new String[finalList.size()])); } return engine; } static String getHostNameNoResolve(InetSocketAddress socketAddress) { if (Xnio.NIO2) { return socketAddress.getHostString(); } else { String hostName; if (socketAddress.isUnresolved()) { hostName = socketAddress.getHostName(); } else { final InetAddress address = socketAddress.getAddress(); final String string = address.toString(); final int slash = string.indexOf('/'); if (slash == -1 || slash == 0) { // unresolved both ways hostName = string.substring(slash + 1); } else { // has a cached host name hostName = string.substring(0, slash); } } return hostName; } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/ssl/JsseXnioSsl.java000066400000000000000000000324231257016060700243750ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import static org.xnio.IoUtils.safeClose; import static org.xnio._private.Messages.msg; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.NoSuchProviderException; import java.util.concurrent.TimeUnit; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import org.xnio.BufferAllocator; import org.xnio.ByteBufferSlicePool; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.FutureResult; import org.xnio.IoFuture; import org.xnio.IoUtils; import org.xnio.Option; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.Pool; import org.xnio.StreamConnection; import org.xnio.Xnio; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.AssembledConnectedSslStreamChannel; import org.xnio.channels.BoundChannel; import org.xnio.channels.ConnectedSslStreamChannel; import org.xnio.channels.ConnectedStreamChannel; /** * An XNIO SSL provider based on JSSE. Works with any XNIO provider. * * @author David M. Lloyd * @author Flavia Rainone */ public final class JsseXnioSsl extends XnioSsl { private static final Pool bufferPool = new ByteBufferSlicePool(BufferAllocator.DIRECT_BYTE_BUFFER_ALLOCATOR, 17 * 1024, 17 * 1024 * 128); private final SSLContext sslContext; /** * Construct a new instance. * * @param xnio the XNIO instance to associate with * @param optionMap the options for this provider * @throws NoSuchProviderException if the given SSL provider is not found * @throws NoSuchAlgorithmException if the given SSL algorithm is not supported * @throws KeyManagementException if the SSL context could not be initialized */ public JsseXnioSsl(final Xnio xnio, final OptionMap optionMap) throws NoSuchProviderException, NoSuchAlgorithmException, KeyManagementException { this(xnio, optionMap, JsseSslUtils.createSSLContext(optionMap)); } /** * Construct a new instance. * * @param xnio the XNIO instance to associate with * @param optionMap the options for this provider * @param sslContext the SSL context to use for this instance */ public JsseXnioSsl(final Xnio xnio, final OptionMap optionMap, final SSLContext sslContext) { super(xnio, sslContext, optionMap); this.sslContext = sslContext; } /** * Get the JSSE SSL context for this provider instance. * * @return the SSL context */ @SuppressWarnings("unused") public SSLContext getSslContext() { return sslContext; } /** * Get the SSL engine for a given connection. * * @return the SSL engine */ public static SSLEngine getSslEngine(SslConnection connection) { if (connection instanceof JsseSslStreamConnection) { return ((JsseSslStreamConnection) connection).getEngine(); } else { throw msg.notFromThisProvider(); } } @SuppressWarnings("deprecation") public IoFuture connectSsl(final XnioWorker worker, final InetSocketAddress bindAddress, final InetSocketAddress destination, final ChannelListener openListener, final ChannelListener bindListener, final OptionMap optionMap) { final FutureResult futureResult = new FutureResult(IoUtils.directExecutor()); final IoFuture futureSslConnection = openSslConnection(worker, bindAddress, destination, new ChannelListener() { public void handleEvent(final SslConnection sslConnection) { final ConnectedSslStreamChannel assembledChannel = new AssembledConnectedSslStreamChannel(sslConnection, sslConnection.getSourceChannel(), sslConnection.getSinkChannel()); if (!futureResult.setResult(assembledChannel)) { safeClose(assembledChannel); } else { ChannelListeners.invokeChannelListener(assembledChannel, openListener); } } }, bindListener, optionMap).addNotifier(new IoFuture.HandlingNotifier>() { public void handleCancelled(final FutureResult result) { result.setCancelled(); } public void handleFailed(final IOException exception, final FutureResult result) { result.setException(exception); } }, futureResult); futureResult.getIoFuture().addNotifier(new IoFuture.HandlingNotifier>() { public void handleCancelled(final IoFuture result) { result.cancel(); } }, futureSslConnection); futureResult.addCancelHandler(futureSslConnection); return futureResult.getIoFuture(); } public IoFuture openSslConnection(final XnioWorker worker, final InetSocketAddress bindAddress, final InetSocketAddress destination, final ChannelListener openListener, final ChannelListener bindListener, final OptionMap optionMap) { final FutureResult futureResult = new FutureResult(worker); final IoFuture connection = worker.openStreamConnection(bindAddress, destination, new StreamConnectionChannelListener(optionMap, destination, futureResult, openListener), bindListener, optionMap); return setupSslConnection(futureResult, connection); } @Override public IoFuture openSslConnection(final XnioIoThread ioThread, final InetSocketAddress bindAddress, final InetSocketAddress destination, final ChannelListener openListener, final ChannelListener bindListener, final OptionMap optionMap) { final FutureResult futureResult = new FutureResult(ioThread); final IoFuture connection = ioThread.openStreamConnection(bindAddress, destination, new StreamConnectionChannelListener(optionMap, destination, futureResult, openListener), bindListener, optionMap); return setupSslConnection(futureResult, connection); } private IoFuture setupSslConnection(FutureResult futureResult, IoFuture connection) { connection.addNotifier(new IoFuture.HandlingNotifier>() { public void handleCancelled(final FutureResult attachment) { attachment.setCancelled(); } public void handleFailed(final IOException exception, final FutureResult attachment) { attachment.setException(exception); } }, futureResult); futureResult.addCancelHandler(connection); return futureResult.getIoFuture(); } @SuppressWarnings("deprecation") public AcceptingChannel createSslTcpServer(final XnioWorker worker, final InetSocketAddress bindAddress, final ChannelListener> acceptListener, final OptionMap optionMap) throws IOException { final AcceptingChannel server = createSslConnectionServer(worker, bindAddress, null, optionMap); final AcceptingChannel acceptingChannel = new AcceptingChannel() { public ConnectedSslStreamChannel accept() throws IOException { final SslConnection connection = server.accept(); return connection == null ? null : new AssembledConnectedSslStreamChannel(connection, connection.getSourceChannel(), connection.getSinkChannel()); } public ChannelListener.Setter> getAcceptSetter() { return ChannelListeners.getDelegatingSetter(server.getAcceptSetter(), this); } public ChannelListener.Setter> getCloseSetter() { return ChannelListeners.getDelegatingSetter(server.getCloseSetter(), this); } public SocketAddress getLocalAddress() { return server.getLocalAddress(); } public A getLocalAddress(final Class type) { return server.getLocalAddress(type); } public void suspendAccepts() { server.suspendAccepts(); } public void resumeAccepts() { server.resumeAccepts(); } public boolean isAcceptResumed() { return server.isAcceptResumed(); } public void wakeupAccepts() { server.wakeupAccepts(); } public void awaitAcceptable() throws IOException { server.awaitAcceptable(); } public void awaitAcceptable(final long time, final TimeUnit timeUnit) throws IOException { server.awaitAcceptable(time, timeUnit); } public XnioWorker getWorker() { return server.getWorker(); } @Deprecated public XnioExecutor getAcceptThread() { return server.getAcceptThread(); } public XnioIoThread getIoThread() { return server.getIoThread(); } public void close() throws IOException { server.close(); } public boolean isOpen() { return server.isOpen(); } public boolean supportsOption(final Option option) { return server.supportsOption(option); } public T getOption(final Option option) throws IOException { return server.getOption(option); } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return server.setOption(option, value); } }; acceptingChannel.getAcceptSetter().set(acceptListener); return acceptingChannel; } public AcceptingChannel createSslConnectionServer(final XnioWorker worker, final InetSocketAddress bindAddress, final ChannelListener> acceptListener, final OptionMap optionMap) throws IOException { final JsseAcceptingSslStreamConnection server = new JsseAcceptingSslStreamConnection(sslContext, worker.createStreamConnectionServer(bindAddress, null, optionMap), optionMap, bufferPool, bufferPool, optionMap.get(Options.SSL_STARTTLS, false)); if (acceptListener != null) server.getAcceptSetter().set(acceptListener); return server; } private class StreamConnectionChannelListener implements ChannelListener { private final OptionMap optionMap; private final InetSocketAddress destination; private final FutureResult futureResult; private final ChannelListener openListener; public StreamConnectionChannelListener(OptionMap optionMap, InetSocketAddress destination, FutureResult futureResult, ChannelListener openListener) { this.optionMap = optionMap; this.destination = destination; this.futureResult = futureResult; this.openListener = openListener; } public void handleEvent(final StreamConnection connection) { final SslConnection wrappedConnection = new JsseSslStreamConnection(connection, JsseSslUtils.createSSLEngine(sslContext, optionMap, destination), bufferPool, bufferPool, optionMap.get(Options.SSL_STARTTLS, false)); if (! futureResult.setResult(wrappedConnection)) { IoUtils.safeClose(connection); } else { ChannelListeners.invokeChannelListener(wrappedConnection, openListener); } } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/ssl/SslConnection.java000066400000000000000000000050401257016060700247250ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.ssl; import java.io.IOException; import javax.net.ssl.SSLSession; import org.xnio.ChannelListener; import org.xnio.Options; import org.xnio.StreamConnection; import org.xnio.XnioIoThread; import org.xnio.channels.SslChannel; /** * A stream connection which can use SSL/TLS to negotiate a security layer. * * @author Flavia Rainone * */ public abstract class SslConnection extends StreamConnection implements SslChannel { /** * Construct a new instance. * * @param thread the I/O thread of this connection */ protected SslConnection(XnioIoThread thread) { super(thread); } /** * Start or restart the SSL/TLS handshake. To force a complete SSL/TLS session renegotiation, the current session * should be invalidated prior to calling this method. This method is not needed for the initial handshake unless * the {@link Options#SSL_STARTTLS} option is set as sending or receiving over the channel will automatically * initiate it. This method must not be called while a read or write operation is taking place. * * @throws IOException if an I/O error occurs */ public abstract void startHandshake() throws IOException; /** * Get the current {@code SSLSession} for this channel. * * @return the current {@code SSLSession} */ public abstract SSLSession getSslSession(); /** * Get the setter which can be used to change the handshake listener for this channel. * * @return the setter */ public abstract ChannelListener.Setter getHandshakeSetter(); /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public ChannelListener.Setter getCloseSetter() { return (ChannelListener.Setter) super.getCloseSetter(); } }xnio-3.3.2.Final/api/src/main/java/org/xnio/ssl/XnioSsl.java000066400000000000000000000265771257016060700235650ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import java.io.IOException; import java.net.InetSocketAddress; import javax.net.ssl.SSLContext; import org.xnio.ChannelListener; import org.xnio.IoFuture; import org.xnio.OptionMap; import org.xnio.Xnio; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.BoundChannel; import org.xnio.channels.ConnectedSslStreamChannel; /** * An SSL provider for XNIO. * * @author David M. Lloyd * @author Flavia Rainone */ @SuppressWarnings("unused") public abstract class XnioSsl { private static final InetSocketAddress ANY_INET_ADDRESS = new InetSocketAddress(0); /** * The corresponding XNIO instance. */ protected final Xnio xnio; /** * The SSL context for this instance. */ protected final SSLContext sslContext; /** * Construct a new instance. * * @param xnio the XNIO instance * @param sslContext * @param optionMap the option map to configure this provider */ @SuppressWarnings("unused") protected XnioSsl(final Xnio xnio, final SSLContext sslContext, final OptionMap optionMap) { this.xnio = xnio; this.sslContext = sslContext; } /** * Create an SSL connection to a remote host. * * @param worker the worker to use * @param destination the destination connection address * @param openListener the initial open-connection listener * @param optionMap the option map * * @return the SSL connection */ @Deprecated public IoFuture connectSsl(XnioWorker worker, InetSocketAddress destination, ChannelListener openListener, OptionMap optionMap) { return connectSsl(worker, ANY_INET_ADDRESS, destination, openListener, null, optionMap); } /** * Create an SSL connection to a remote host. * * @param worker the worker to use * @param destination the destination connection address * @param openListener the initial open-connection listener * @param bindListener the bind listener * @param optionMap the option map * @return the SSL connection */ @Deprecated public IoFuture connectSsl(final XnioWorker worker, final InetSocketAddress destination, final ChannelListener openListener, final ChannelListener bindListener, final OptionMap optionMap) { return connectSsl(worker, ANY_INET_ADDRESS, destination, openListener, bindListener, optionMap); } /** * Create an SSL connection to a remote host. * * @param worker the worker to use * @param bindAddress the local bind address * @param destination the destination connection address * @param openListener the initial open-connection listener * @param optionMap the option map * @return the SSL connection */ @Deprecated public IoFuture connectSsl(final XnioWorker worker, final InetSocketAddress bindAddress, final InetSocketAddress destination, final ChannelListener openListener, final OptionMap optionMap) { return connectSsl(worker, bindAddress, destination, openListener, null, optionMap); } /** * Create an SSL connection to a remote host. * * @param worker the worker to use * @param bindAddress the local bind address * @param destination the destination connection address * @param openListener the initial open-connection listener * @param bindListener the bind listener * @param optionMap the option map * @return the SSL connection */ @Deprecated public abstract IoFuture connectSsl(XnioWorker worker, InetSocketAddress bindAddress, InetSocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap); /** * Create an SSL connection to a remote host. * * @param worker the worker to use * @param destination the destination connection address * @param openListener the initial open-connection listener * @param optionMap the option map * * @return the SSL connection */ public IoFuture openSslConnection(XnioWorker worker, InetSocketAddress destination, ChannelListener openListener, OptionMap optionMap) { return openSslConnection(worker, ANY_INET_ADDRESS, destination, openListener, null, optionMap); } /** * Create an SSL connection to a remote host. * * @param ioThread the IO thread to use * @param destination the destination connection address * @param openListener the initial open-connection listener * @param optionMap the option map * * @return the SSL connection */ public IoFuture openSslConnection(XnioIoThread ioThread, InetSocketAddress destination, ChannelListener openListener, OptionMap optionMap) { return openSslConnection(ioThread, ANY_INET_ADDRESS, destination, openListener, null, optionMap); } /** * Create an SSL connection to a remote host. * * @param worker the worker to use * @param destination the destination connection address * @param openListener the initial open-connection listener * @param bindListener the bind listener * @param optionMap the option map * @return the SSL connection */ public IoFuture openSslConnection(final XnioWorker worker, final InetSocketAddress destination, final ChannelListener openListener, final ChannelListener bindListener, final OptionMap optionMap) { return openSslConnection(worker, ANY_INET_ADDRESS, destination, openListener, bindListener, optionMap); } /** * Create an SSL connection to a remote host. * * @param ioThread the IO Thread to use * @param destination the destination connection address * @param openListener the initial open-connection listener * @param bindListener the bind listener * @param optionMap the option map * @return the SSL connection */ public IoFuture openSslConnection(final XnioIoThread ioThread, final InetSocketAddress destination, final ChannelListener openListener, final ChannelListener bindListener, final OptionMap optionMap) { return openSslConnection(ioThread, ANY_INET_ADDRESS, destination, openListener, bindListener, optionMap); } /** * Create an SSL connection to a remote host. * * @param worker the worker to use * @param bindAddress the local bind address * @param destination the destination connection address * @param openListener the initial open-connection listener * @param optionMap the option map * @return the SSL connection */ public IoFuture openSslConnection(final XnioWorker worker, final InetSocketAddress bindAddress, final InetSocketAddress destination, final ChannelListener openListener, final OptionMap optionMap) { return openSslConnection(worker, bindAddress, destination, openListener, null, optionMap); } /** * Create an SSL connection to a remote host. * * @param ioThread the IO Thread to use * @param bindAddress the local bind address * @param destination the destination connection address * @param openListener the initial open-connection listener * @param optionMap the option map * @return the SSL connection */ public IoFuture openSslConnection(final XnioIoThread ioThread, final InetSocketAddress bindAddress, final InetSocketAddress destination, final ChannelListener openListener, final OptionMap optionMap) { return openSslConnection(ioThread, bindAddress, destination, openListener, null, optionMap); } /** * Create an SSL connection to a remote host. * * @param worker the worker to use * @param bindAddress the local bind address * @param destination the destination connection address * @param openListener the initial open-connection listener * @param bindListener the bind listener * @param optionMap the option map * @return the SSL connection */ public abstract IoFuture openSslConnection(XnioWorker worker, InetSocketAddress bindAddress, InetSocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap); /** * Create an SSL connection to a remote host. * * @param ioThread the IO Thread to use * @param bindAddress the local bind address * @param destination the destination connection address * @param openListener the initial open-connection listener * @param bindListener the bind listener * @param optionMap the option map * @return the SSL connection */ public abstract IoFuture openSslConnection(XnioIoThread ioThread, InetSocketAddress bindAddress, InetSocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap); /** * Create a bound TCP SSL server. * * @param worker the worker to use * @param bindAddress the address to bind to * @param acceptListener the initial accept listener * @param optionMap the initial configuration for the server * @return the unbound TCP SSL server * @throws IOException if the server could not be created */ @Deprecated public abstract AcceptingChannel createSslTcpServer(XnioWorker worker, InetSocketAddress bindAddress, ChannelListener> acceptListener, OptionMap optionMap) throws IOException; /** * Create a bound TCP SSL server. * * @param worker the worker to use * @param bindAddress the address to bind to * @param acceptListener the initial accept listener * @param optionMap the initial configuration for the server * @return the unbound TCP SSL server * @throws IOException if the server could not be created */ public abstract AcceptingChannel createSslConnectionServer(XnioWorker worker, InetSocketAddress bindAddress, ChannelListener> acceptListener, OptionMap optionMap) throws IOException; } xnio-3.3.2.Final/api/src/main/java/org/xnio/ssl/package-info.java000066400000000000000000000001471257016060700244730ustar00rootroot00000000000000/** * Utility classes for using and implementing SSL within XNIO providers. */ package org.xnio.ssl; xnio-3.3.2.Final/api/src/main/java/org/xnio/streams/000077500000000000000000000000001257016060700221575ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/java/org/xnio/streams/BufferPipeInputStream.java000066400000000000000000000240321257016060700272460ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2010 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.streams; import static org.xnio._private.Messages.msg; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; import java.nio.ByteBuffer; import java.util.ArrayDeque; import java.util.Queue; import java.util.concurrent.Semaphore; import org.xnio.Buffers; import org.xnio.Pooled; import org.xnio.Xnio; /** * An {@code InputStream} implementation which is populated asynchronously with {@link ByteBuffer} instances. */ public class BufferPipeInputStream extends InputStream { private final Queue> queue; private final InputHandler inputHandler; // protected by "this" private boolean eof; private IOException failure; /** * Construct a new instance. The given {@code inputHandler} will * be invoked after each buffer is fully read and when the stream is closed. * * @param inputHandler the input events handler */ public BufferPipeInputStream(final InputHandler inputHandler) { this.inputHandler = inputHandler; queue = new ArrayDeque>(); } /** * Push a buffer into the queue. There is no mechanism to limit the number of pushed buffers; if such a mechanism * is desired, it must be implemented externally, for example maybe using a {@link Semaphore}. * * @param buffer the buffer from which more data should be read */ public void push(final ByteBuffer buffer) { synchronized (this) { if (buffer.hasRemaining() && !eof && failure == null) { queue.add(Buffers.pooledWrapper(buffer)); notifyAll(); } } } /** * Push a buffer into the queue. There is no mechanism to limit the number of pushed buffers; if such a mechanism * is desired, it must be implemented externally, for example maybe using a {@link Semaphore}. * * @param pooledBuffer the buffer from which more data should be read */ public void push(final Pooled pooledBuffer) { synchronized (this) { if (pooledBuffer.getResource().hasRemaining() && !eof && failure == null) { queue.add(pooledBuffer); notifyAll(); } else { pooledBuffer.free(); } } } /** * Push an exception condition into the queue. After this method is called, no further buffers may be pushed into this * instance. * * @param e the exception to push */ public void pushException(IOException e) { synchronized (this) { if (! eof) { failure = e; notifyAll(); } } } /** * Push the EOF condition into the queue. After this method is called, no further buffers may be pushed into this * instance. */ public void pushEof() { synchronized (this) { eof = true; notifyAll(); } } /** {@inheritDoc} */ public int read() throws IOException { final Queue> queue = this.queue; synchronized (this) { while (queue.isEmpty()) { if (eof) { return -1; } checkFailure(); Xnio.checkBlockingAllowed(); try { wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw msg.interruptedIO(); } } final Pooled entry = queue.peek(); final ByteBuffer buf = entry.getResource(); final int v = buf.get() & 0xff; if (buf.remaining() == 0) { queue.poll(); try { inputHandler.acknowledge(entry); } catch (IOException e) { // no operation! } finally { entry.free(); } } return v; } } private void clearQueue() { synchronized (this) { Pooled entry; while ((entry = queue.poll()) != null) { entry.free(); } } } /** {@inheritDoc} */ public int read(final byte[] b, int off, int len) throws IOException { if (len == 0) { return 0; } final Queue> queue = this.queue; synchronized (this) { while (queue.isEmpty()) { if (eof) { return -1; } checkFailure(); Xnio.checkBlockingAllowed(); try { wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw msg.interruptedIO(); } } int total = 0; while (len > 0) { final Pooled entry = queue.peek(); if (entry == null) { break; } final ByteBuffer buffer = entry.getResource(); final int byteCnt = Math.min(buffer.remaining(), len); buffer.get(b, off, byteCnt); off += byteCnt; total += byteCnt; len -= byteCnt; if (buffer.remaining() == 0) { queue.poll(); try { inputHandler.acknowledge(entry); } catch (IOException e) { // no operation! } finally { entry.free(); } } } return total; } } /** {@inheritDoc} */ public int available() throws IOException { synchronized (this) { int total = 0; for (Pooled entry : queue) { total += entry.getResource().remaining(); if (total < 0) { return Integer.MAX_VALUE; } } return total; } } public long skip(long qty) throws IOException { final Queue> queue = this.queue; synchronized (this) { while (queue.isEmpty()) { if (eof) { return 0L; } checkFailure(); Xnio.checkBlockingAllowed(); try { wait(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw msg.interruptedIO(); } } long skipped = 0L; while (qty > 0L) { final Pooled entry = queue.peek(); if (entry == null) { break; } final ByteBuffer buffer = entry.getResource(); final int byteCnt = Math.min(buffer.remaining(), (int) Math.max((long)Integer.MAX_VALUE, qty)); buffer.position(buffer.position() + byteCnt); skipped += byteCnt; qty -= byteCnt; if (buffer.remaining() == 0) { queue.poll(); try { inputHandler.acknowledge(entry); } catch (IOException e) { // no operation! } finally { entry.free(); } } } return skipped; } } /** {@inheritDoc} */ public void close() throws IOException { synchronized (this) { if (! eof) { clearQueue(); eof = true; failure = null; notifyAll(); inputHandler.close(); } } } private void checkFailure() throws IOException { assert Thread.holdsLock(this); final IOException failure = this.failure; if (failure != null) { failure.fillInStackTrace(); try { throw failure; } finally { clearQueue(); notifyAll(); } } } /** * A handler for events relating to the consumption of data from a {@link BufferPipeInputStream} instance. */ public interface InputHandler extends Closeable { /** * Acknowledges the successful processing of an input buffer. Though this method may throw an exception, * it is not acted upon. The acknowledged resource is passed in, with its position set to the number of * bytes consumed. * * @param pooled the pooled resource which was consumed * @throws IOException if an I/O error occurs sending the acknowledgement */ void acknowledge(Pooled pooled) throws IOException; /** * Signifies that the user of the enclosing {@link BufferPipeInputStream} has called the {@code close()} method * explicitly. Any thrown exception is propagated up to the caller of {@link BufferPipeInputStream#close() NioByteInput.close()}. * * @throws IOException if an I/O error occurs */ void close() throws IOException; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/streams/BufferPipeOutputStream.java000066400000000000000000000162441257016060700274550ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2010 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.streams; import java.io.Flushable; import java.io.IOException; import java.io.OutputStream; import java.nio.ByteBuffer; import org.xnio.BrokenPipeException; import org.xnio.Buffers; import org.xnio.Pooled; /** * An {@code OutputStream} implementation which writes out {@code ByteBuffer}s to a consumer. */ public class BufferPipeOutputStream extends OutputStream { // internal buffer private Pooled buffer; // indicates this stream is closed private boolean closed; private final BufferWriter bufferWriterTask; /** * Construct a new instance. The internal buffers will have a capacity of {@code bufferSize}. The * given {@code bufferWriterTask} will be called to send buffers, flush the output stream, and handle the * end-of-file condition. * * @param bufferWriterTask the writer task * @throws IOException if an error occurs while initializing the stream */ public BufferPipeOutputStream(final BufferWriter bufferWriterTask) throws IOException { this.bufferWriterTask = bufferWriterTask; synchronized (this) { buffer = bufferWriterTask.getBuffer(true); } } private static IOException closed() { return new IOException("Stream is closed"); } private void checkClosed() throws IOException { assert Thread.holdsLock(this); if (closed) { throw closed(); } } private Pooled getBuffer() throws IOException { assert Thread.holdsLock(this); final Pooled buffer = this.buffer; if (buffer != null && buffer.getResource().hasRemaining()) { return buffer; } else { if (buffer != null) send(false); return this.buffer = bufferWriterTask.getBuffer(false); } } /** {@inheritDoc} */ public void write(final int b) throws IOException { synchronized (this) { checkClosed(); getBuffer().getResource().put((byte) b); } } /** {@inheritDoc} */ public void write(final byte[] b, int off, int len) throws IOException { synchronized (this) { checkClosed(); while (len > 0) { final ByteBuffer buffer = getBuffer().getResource(); final int cnt = Math.min(len, buffer.remaining()); buffer.put(b, off, cnt); len -= cnt; off += cnt; } } } // call with lock held private void send(boolean eof) throws IOException { assert Thread.holdsLock(this); assert !closed; final Pooled pooledBuffer = buffer; final ByteBuffer buffer = pooledBuffer == null ? null : pooledBuffer.getResource(); this.buffer = null; if (buffer != null && buffer.position() > 0) { buffer.flip(); send(pooledBuffer, eof); } else if (eof) { Pooled pooledBuffer1 = getBuffer(); final ByteBuffer buffer1 = pooledBuffer1.getResource(); buffer1.flip(); send(pooledBuffer1, eof); } } private void send(Pooled buffer, boolean eof) throws IOException { assert Thread.holdsLock(this); try { bufferWriterTask.accept(buffer, eof); } catch (IOException e) { this.closed = true; throw e; } } /** {@inheritDoc} */ public void flush() throws IOException { flush(false); } private void flush(boolean eof) throws IOException { synchronized (this) { if (closed) { return; } send(eof); try { bufferWriterTask.flush(); } catch (IOException e) { closed = true; buffer = null; throw e; } } } /** {@inheritDoc} */ public void close() throws IOException { synchronized (this) { if (closed) { return; } try { flush(true); } finally { closed = true; } } } /** * Break the pipe and return any filling pooled buffer. Sets the stream to an EOF condition. Callers to this * method should ensure that any threads blocked on {@link BufferWriter#accept(org.xnio.Pooled, boolean)} are * unblocked, preferably with a {@link BrokenPipeException}. * * @return the current pooled buffer, or {@code null} if none was pending */ public Pooled breakPipe() { synchronized (this) { if (closed) { return null; } closed = true; try { return buffer; } finally { buffer = null; } } } /** * A buffer writer for an {@link BufferPipeOutputStream}. */ public interface BufferWriter extends Flushable { /** * Get a new buffer to be filled. The new buffer may, for example, include a prepended header. This method * may block until a buffer is available or until some other condition, such as flow control, is met. * * @param firstBuffer {@code true} if this is the first buffer in the stream, {@code false} otherwise * @return the new buffer * @throws IOException if an I/O error occurs */ Pooled getBuffer(boolean firstBuffer) throws IOException; /** * Accept a buffer. If this is the last buffer that will be sent, the {@code eof} flag will be set to {@code true}. * This method should block until the entire buffer is consumed, or an error occurs. This method may also block * until some other condition, such as flow control, is met. * * @param pooledBuffer the buffer to send * @param eof {@code true} if this is the last buffer which will be sent * @throws IOException if an I/O error occurs */ void accept(Pooled pooledBuffer, boolean eof) throws IOException; /** * Flushes this stream by writing any buffered output to the underlying stream. This method should block until * the data is fully flushed. This method may also block until some other condition, such as flow control, is * met. * * @throws IOException If an I/O error occurs */ void flush() throws IOException; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/streams/BufferedChannelInputStream.java000066400000000000000000000307101257016060700302320ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2010 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.streams; import java.io.InputStream; import java.io.IOException; import java.io.InterruptedIOException; import java.nio.ByteBuffer; import static java.lang.Math.min; import static org.xnio._private.Messages.msg; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import org.xnio.Bits; import org.xnio.Buffers; import org.xnio.channels.Channels; import org.xnio.channels.StreamSourceChannel; /** * An input stream which reads from a stream source channel with a buffer. In addition, the * {@link #available()} method can be used to determine whether the next read will or will not block. * * @apiviz.exclude * * @since 2.1 */ public class BufferedChannelInputStream extends InputStream { private final StreamSourceChannel channel; private final ByteBuffer buffer; @SuppressWarnings("unused") private volatile int flags; private volatile long timeout; private static final AtomicIntegerFieldUpdater flagsUpdater = AtomicIntegerFieldUpdater.newUpdater(BufferedChannelInputStream.class, "flags"); private static final int FLAG_EOF = 2; private static final int FLAG_ENTERED = 1; /** * Construct a new instance. * * @param channel the channel to wrap * @param bufferSize the size of the internal buffer */ public BufferedChannelInputStream(final StreamSourceChannel channel, final int bufferSize) { if (channel == null) { throw msg.nullParameter("channel"); } if (bufferSize < 1) { throw msg.parameterOutOfRange("bufferSize"); } this.channel = channel; buffer = ByteBuffer.allocate(bufferSize); buffer.limit(0); } /** * Construct a new instance. * * @param channel the channel to wrap * @param bufferSize the size of the internal buffer * @param timeout the initial read timeout, or O for none * @param unit the time unit for the read timeout */ public BufferedChannelInputStream(final StreamSourceChannel channel, final int bufferSize, final long timeout, final TimeUnit unit) { if (channel == null) { throw msg.nullParameter("channel"); } if (unit == null) { throw msg.nullParameter("unit"); } if (bufferSize < 1) { throw msg.parameterOutOfRange("bufferSize"); } if (timeout < 0L) { throw msg.parameterOutOfRange("timeout"); } this.channel = channel; buffer = ByteBuffer.allocate(bufferSize); buffer.limit(0); final long calcTimeout = unit.toNanos(timeout); this.timeout = timeout == 0L ? 0L : calcTimeout < 1L ? 1L : calcTimeout; } private boolean enter() { int old = flags; do { if (Bits.allAreSet(old, FLAG_ENTERED)) { throw msg.concurrentAccess(); } } while (! flagsUpdater.compareAndSet(this, old, old | FLAG_ENTERED)); return Bits.allAreSet(old, FLAG_EOF); } private void exit(boolean setEof) { int oldFlags, newFlags; do { oldFlags = flags; newFlags = oldFlags &~ FLAG_ENTERED; if (setEof) { newFlags |= FLAG_EOF; } } while (! flagsUpdater.compareAndSet(this, oldFlags, newFlags)); } /** * Get the read timeout. * * @param unit the time unit * @return the timeout in the given unit */ public long getReadTimeout(TimeUnit unit) { if (unit == null) { throw msg.nullParameter("unit"); } return unit.convert(timeout, TimeUnit.NANOSECONDS); } /** * Set the read timeout. Does not affect read operations in progress. * * @param timeout the read timeout, or 0 for none * @param unit the time unit */ public void setReadTimeout(long timeout, TimeUnit unit) { if (timeout < 0L) { throw msg.parameterOutOfRange("timeout"); } if (unit == null) { throw msg.nullParameter("unit"); } final long calcTimeout = unit.toNanos(timeout); this.timeout = timeout == 0L ? 0L : calcTimeout < 1L ? 1L : calcTimeout; } /** * Read a byte, blocking if necessary. * * @return the byte read, or -1 if the end of the stream has been reached * @throws IOException if an I/O error occurs */ public int read() throws IOException { boolean eof = enter(); try { final StreamSourceChannel channel = this.channel; final ByteBuffer buffer = this.buffer; // try buffer first if (buffer.hasRemaining()) { return buffer.get() & 0xff; } if (eof) { return -1; } // fill buffer int res; long timeout; long start = System.nanoTime(); long elapsed = 0L; for (;;) { buffer.clear(); try { res = channel.read(buffer); } finally { buffer.flip(); } if (res == -1) { eof = true; return -1; } if (res > 0) { return buffer.get() & 0xff; } timeout = this.timeout; if (timeout == 0L) { channel.awaitReadable(); } else if (timeout < elapsed) { throw msg.readTimeout(); } else { channel.awaitReadable(timeout - elapsed, TimeUnit.NANOSECONDS); } elapsed = System.nanoTime() - start; } } finally { exit(eof); } } /** * Read bytes into an array. * * @param b the destination array * @param off the offset into the array at which bytes should be filled * @param len the number of bytes to fill * @return the number of bytes read, or -1 if the end of the stream has been reached * @throws IOException if an I/O error occurs */ public int read(final byte[] b, int off, int len) throws IOException { if (len < 1) { return 0; } boolean eof = enter(); try { int total = 0; // empty buffer final ByteBuffer buffer = this.buffer; final ByteBuffer userBuffer = ByteBuffer.wrap(b, off, len); if (buffer.hasRemaining()) { total += Buffers.copy(userBuffer, buffer); // either the user buffer is full, or the source buffer is empty if (! userBuffer.hasRemaining()) { return total; } } // at this point the buffer is guaranteed to be empty assert ! buffer.hasRemaining(); assert userBuffer.hasRemaining(); if (eof) return total == 0 ? -1 : total; // read the rest directly into the user buffer final StreamSourceChannel channel = this.channel; long timeout; long start = System.nanoTime(); long elapsed = 0L; int res; for (;;) { res = channel.read(userBuffer); if (res == -1) { eof = true; return total == 0 ? -1 : total; } total += res; if (total > 0) { return total; } timeout = this.timeout; try { if (timeout == 0L) { channel.awaitReadable(); } else if (timeout < elapsed) { throw msg.readTimeout(); } else { channel.awaitReadable(timeout - elapsed, TimeUnit.NANOSECONDS); } } catch (InterruptedIOException e) { e.bytesTransferred = total; throw e; } elapsed = System.nanoTime() - start; } } finally { exit(eof); } } /** * Skip bytes in the stream. * * @param n the number of bytes to skip * @return the number of bytes skipped (0 if the end of stream has been reached) * @throws IOException if an I/O error occurs */ public long skip(long n) throws IOException { if (n < 1L) { return 0L; } boolean eof = enter(); try { // if we don't do this, InterruptedIOException might not be able to report a correct result n = Math.min(n, (long)Integer.MAX_VALUE); long total = 0L; final ByteBuffer buffer = this.buffer; if (buffer.hasRemaining()) { final int cnt = (int) min(buffer.remaining(), n); Buffers.skip(buffer, cnt); total += cnt; n -= cnt; assert n == 0L || ! buffer.hasRemaining(); if (n == 0L) { return total; } } assert ! buffer.hasRemaining(); if (eof) { return total; } long timeout; long start = System.nanoTime(); long elapsed = 0L; long res; for (;;) { if (n == 0L) return total; res = Channels.drain(channel, n); if (res == -1) { return total; } else if (res == 0) { timeout = this.timeout; try { if (timeout == 0L) { channel.awaitReadable(); } else if (timeout < elapsed) { throw msg.readTimeout(); } else { channel.awaitReadable(timeout - elapsed, TimeUnit.NANOSECONDS); } } catch (InterruptedIOException e) { assert total < (long) Integer.MAX_VALUE; e.bytesTransferred = (int) total; throw e; } elapsed = System.nanoTime() - start; } else { total += res; n -= res; } } } finally { exit(eof); } } /** * Return the number of bytes available to read, or 0 if a subsequent {@code read()} operation would block. If * a 0 is returned, the channel's {@link org.xnio.channels.SuspendableReadChannel#resumeReads() resumeReads()} method may be used * to register for read-readiness. * * @return the number of ready bytes, or 0 for none * @throws IOException if an I/O error occurs */ public int available() throws IOException { boolean eof = enter(); try { final ByteBuffer buffer = this.buffer; final int rem = buffer.remaining(); if (rem > 0 || eof) { return rem; } buffer.clear(); try { channel.read(buffer); } catch (IOException e) { throw e; } finally { buffer.flip(); } return buffer.remaining(); } finally { exit(eof); } } /** * Close the stream. Shuts down the channel's read side. * * @throws IOException if an I/O error occurs */ public void close() throws IOException { enter(); try { buffer.clear().flip(); channel.shutdownReads(); } finally { exit(true); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/streams/ChannelInputStream.java000066400000000000000000000213261257016060700265720ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.streams; import static org.xnio._private.Messages.msg; import java.io.InputStream; import java.io.IOException; import java.io.InterruptedIOException; import java.nio.ByteBuffer; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import org.xnio.Bits; import org.xnio.channels.Channels; import org.xnio.channels.StreamSourceChannel; /** * An input stream which reads from a stream source channel. All read operations are directly * performed upon the channel, so for optimal performance, a buffering input stream should be * used to wrap this class. * * @apiviz.exclude * * @since 1.2 */ public class ChannelInputStream extends InputStream { protected final StreamSourceChannel channel; @SuppressWarnings("unused") private volatile int flags; private volatile long timeout; private static final AtomicIntegerFieldUpdater flagsUpdater = AtomicIntegerFieldUpdater.newUpdater(ChannelInputStream.class, "flags"); private static final int FLAG_EOF = 2; private static final int FLAG_ENTERED = 1; /** * Construct a new instance. The stream will have no read timeout. * * @param channel the channel to wrap */ public ChannelInputStream(final StreamSourceChannel channel) { if (channel == null) { throw msg.nullParameter("channel"); } this.channel = channel; } /** * Construct a new instance. * * @param channel the channel to wrap * @param timeout the read timeout, or O for none * @param timeoutUnit the time unit for read timeouts */ public ChannelInputStream(final StreamSourceChannel channel, final long timeout, final TimeUnit timeoutUnit) { if (channel == null) { throw msg.nullParameter("channel"); } if (timeoutUnit == null) { throw msg.nullParameter("timeoutUnit"); } if (timeout < 0L) { throw msg.parameterOutOfRange("timeout"); } this.channel = channel; final long calcTimeout = timeoutUnit.toNanos(timeout); this.timeout = timeout == 0L ? 0L : calcTimeout < 1L ? 1L : calcTimeout; } private boolean enter() { int old = flags; do { if (Bits.allAreSet(old, FLAG_ENTERED)) { throw msg.concurrentAccess(); } } while (! flagsUpdater.compareAndSet(this, old, old | FLAG_ENTERED)); return Bits.allAreSet(old, FLAG_EOF); } private void exit(boolean setEof) { int oldFlags, newFlags; do { oldFlags = flags; newFlags = oldFlags &~ FLAG_ENTERED; if (setEof) { newFlags |= FLAG_EOF; } } while (! flagsUpdater.compareAndSet(this, oldFlags, newFlags)); } /** * Get the read timeout. * * @param unit the time unit * @return the timeout in the given unit */ public long getReadTimeout(TimeUnit unit) { if (unit == null) { throw msg.nullParameter("unit"); } return unit.convert(timeout, TimeUnit.NANOSECONDS); } /** * Set the read timeout. Does not affect read operations in progress. * * @param timeout the read timeout, or 0 for none * @param unit the time unit */ public void setReadTimeout(long timeout, TimeUnit unit) { if (timeout < 0L) { throw msg.parameterOutOfRange("timeout"); } if (unit == null) { throw msg.nullParameter("unit"); } final long calcTimeout = unit.toNanos(timeout); this.timeout = timeout == 0L ? 0L : calcTimeout < 1L ? 1L : calcTimeout; } /** {@inheritDoc} */ public int read() throws IOException { boolean eof = enter(); try { if (eof) return -1; final byte[] array = new byte[1]; final ByteBuffer buffer = ByteBuffer.wrap(array); int res = channel.read(buffer); if (res == 0) { long timeout; long start = System.nanoTime(); long elapsed = 0L; do { timeout = this.timeout; if (timeout == 0L) { channel.awaitReadable(); } else if (timeout < elapsed) { throw msg.readTimeout(); } else { channel.awaitReadable(timeout - elapsed, TimeUnit.NANOSECONDS); } elapsed = System.nanoTime() - start; res = channel.read(buffer); } while (res == 0); } return (eof = res == -1) ? -1 : array[0] & 0xff; } finally { exit(eof); } } /** {@inheritDoc} */ public int read(final byte[] b) throws IOException { return read(b, 0, b.length); } /** {@inheritDoc} */ public int read(final byte[] b, final int off, final int len) throws IOException { if (len < 1 || off+len > b.length) { return 0; } boolean eof = enter(); try { if (eof) return -1; final ByteBuffer buffer = ByteBuffer.wrap(b, off, len); int res = channel.read(buffer); if (res == 0) { long timeout; long start = System.nanoTime(); long elapsed = 0L; do { timeout = this.timeout; if (timeout == 0L) { channel.awaitReadable(); } else if (timeout < elapsed) { throw msg.readTimeout(); } else { channel.awaitReadable(timeout - elapsed, TimeUnit.NANOSECONDS); } elapsed = System.nanoTime() - start; res = channel.read(buffer); } while (res == 0); } return (eof = res == -1) ? -1 : buffer.position() - off; } finally { exit(eof); } } /** * Skip bytes in the stream. * * @param n the number of bytes to skip * @return the number of bytes skipped (0 if the end of stream has been reached) * @throws IOException if an I/O error occurs */ public long skip(long n) throws IOException { if (n < 1L) { return 0L; } boolean eof = enter(); try { if (eof) return 0L; // if we don't do this, InterruptedIOException might not be able to report a correct result n = Math.min(n, (long)Integer.MAX_VALUE); long total = 0L; long timeout; long start = System.nanoTime(); long elapsed = 0L; long res; for (;;) { if (n == 0L) return total; res = Channels.drain(channel, n); if (res == -1) { return total; } else if (res == 0) { timeout = this.timeout; try { if (timeout == 0L) { channel.awaitReadable(); } else if (timeout < elapsed) { throw msg.readTimeout(); } else { channel.awaitReadable(timeout - elapsed, TimeUnit.NANOSECONDS); } } catch (InterruptedIOException e) { assert total < (long) Integer.MAX_VALUE; e.bytesTransferred = (int) total; throw e; } elapsed = System.nanoTime() - start; } else { total += res; n -= res; } } } finally { exit(eof); } } /** {@inheritDoc} */ public void close() throws IOException { enter(); try { channel.shutdownReads(); } finally { exit(true); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/streams/ChannelOutputStream.java000066400000000000000000000215661257016060700270010ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2008 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.streams; import static org.xnio._private.Messages.msg; import java.io.OutputStream; import java.io.IOException; import java.io.InterruptedIOException; import java.nio.ByteBuffer; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import org.xnio.Bits; import org.xnio.channels.StreamSinkChannel; /** * An output stream which writes to a stream sink channel. All write operations are directly * performed upon the channel, so for optimal performance, a buffering output stream should be * used to wrap this class. * * @apiviz.exclude * * @since 1.2 */ public class ChannelOutputStream extends OutputStream { protected final StreamSinkChannel channel; @SuppressWarnings("unused") private volatile int flags; private volatile long timeout; private static final AtomicIntegerFieldUpdater flagsUpdater = AtomicIntegerFieldUpdater.newUpdater(ChannelOutputStream.class, "flags"); private static final int FLAG_CLOSED = 2; private static final int FLAG_ENTERED = 1; /** * Construct a new instance. No write timeout is configured. * * @param channel the channel to wrap */ public ChannelOutputStream(final StreamSinkChannel channel) { if (channel == null) { throw msg.nullParameter("channel"); } this.channel = channel; } /** * Construct a new instance. * * @param channel the channel to wrap * @param timeout the write timeout * @param unit the write timeout units */ public ChannelOutputStream(final StreamSinkChannel channel, final long timeout, final TimeUnit unit) { if (channel == null) { throw msg.nullParameter("channel"); } if (unit == null) { throw msg.nullParameter("unit"); } if (timeout < 0L) { throw msg.parameterOutOfRange("timeout"); } this.channel = channel; final long calcTimeout = unit.toNanos(timeout); this.timeout = timeout == 0L ? 0L : calcTimeout < 1L ? 1L : calcTimeout; } private boolean enter() { int old = flags; do { if (Bits.allAreSet(old, FLAG_ENTERED)) { throw msg.concurrentAccess(); } } while (! flagsUpdater.compareAndSet(this, old, old | FLAG_ENTERED)); return Bits.allAreSet(old, FLAG_CLOSED); } private void exit(boolean setEof) { int oldFlags, newFlags; do { oldFlags = flags; newFlags = oldFlags &~ FLAG_ENTERED; if (setEof) { newFlags |= FLAG_CLOSED; } } while (! flagsUpdater.compareAndSet(this, oldFlags, newFlags)); } /** * Get the write timeout. * * @param unit the time unit * @return the timeout in the given unit */ public long getWriteTimeout(TimeUnit unit) { if (unit == null) { throw msg.nullParameter("unit"); } return unit.convert(timeout, TimeUnit.NANOSECONDS); } /** * Set the write timeout. Does not affect write operations in progress. * * @param timeout the write timeout, or 0 for none * @param unit the time unit */ public void setWriteTimeout(long timeout, TimeUnit unit) { if (timeout < 0L) { throw msg.parameterOutOfRange("timeout"); } if (unit == null) { throw msg.nullParameter("unit"); } final long calcTimeout = unit.toNanos(timeout); this.timeout = timeout == 0L ? 0L : calcTimeout < 1L ? 1L : calcTimeout; } /** {@inheritDoc} */ public void write(final int b) throws IOException { boolean closed = enter(); try { if (closed) throw msg.streamClosed(); final StreamSinkChannel channel = this.channel; final ByteBuffer buffer = ByteBuffer.wrap(new byte[] { (byte) b }); int res = channel.write(buffer); if (res == 0) { long timeout; long start = System.nanoTime(); long elapsed = 0L; do { timeout = this.timeout; if (timeout == 0L) { channel.awaitWritable(); } else if (timeout < elapsed) { throw msg.writeTimeout(); } else { channel.awaitWritable(timeout - elapsed, TimeUnit.NANOSECONDS); } elapsed = System.nanoTime() - start; res = channel.write(buffer); } while (res == 0); } } finally { exit(closed); } } /** {@inheritDoc} */ public void write(final byte[] b) throws IOException { write(b, 0, b.length); } /** {@inheritDoc} */ public void write(final byte[] b, final int off, final int len) throws IOException { if (len < 1) { return; } boolean closed = enter(); try { if (closed) throw msg.streamClosed(); final StreamSinkChannel channel = this.channel; final ByteBuffer buffer = ByteBuffer.wrap(b, off, len); int res; while (buffer.hasRemaining()) { res = channel.write(buffer); if (res == 0) { long timeout; long start = System.nanoTime(); long elapsed = 0L; do { timeout = this.timeout; try { if (timeout == 0L) { channel.awaitWritable(); } else if (timeout < elapsed) { throw msg.writeTimeout(); } else { channel.awaitWritable(timeout - elapsed, TimeUnit.NANOSECONDS); } } catch (InterruptedIOException e) { e.bytesTransferred = buffer.position() - off; throw e; } elapsed = System.nanoTime() - start; res = channel.write(buffer); } while (res == 0); } } } finally { exit(closed); } } /** {@inheritDoc} */ public void flush() throws IOException { final boolean closed = enter(); try { final StreamSinkChannel channel = this.channel; if (! channel.flush()) { long timeout; long start = System.nanoTime(); long elapsed = 0L; do { timeout = this.timeout; if (timeout == 0L) { channel.awaitWritable(); } else if (timeout < elapsed) { throw msg.writeTimeout(); } else { channel.awaitWritable(timeout - elapsed, TimeUnit.NANOSECONDS); } elapsed = System.nanoTime() - start; } while (! channel.flush()); } } finally { exit(closed); } } /** {@inheritDoc} */ public void close() throws IOException { final boolean closed = enter(); try { if (closed) return; final StreamSinkChannel channel = this.channel; channel.shutdownWrites(); if (! channel.flush()) { long timeout; long start = System.nanoTime(); long elapsed = 0L; do { timeout = this.timeout; if (timeout == 0L) { channel.awaitWritable(); } else if (timeout < elapsed) { throw msg.writeTimeout(); } else { channel.awaitWritable(timeout - elapsed, TimeUnit.NANOSECONDS); } elapsed = System.nanoTime() - start; } while (! channel.flush()); } } finally { exit(true); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/streams/LimitedInputStream.java000066400000000000000000000065451257016060700266170ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2010 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.streams; import static org.xnio._private.Messages.msg; import java.io.IOException; import java.io.InputStream; /** * An input stream which truncates the underlying stream to the given length. * * @author David M. Lloyd */ public final class LimitedInputStream extends InputStream { private final InputStream delegate; private long remaining; private long mark = -1L; /** * Construct a new instance. * * @param delegate the delegate stream * @param size the maximum size to pass */ public LimitedInputStream(final InputStream delegate, final long size) { this.delegate = delegate; remaining = size; } /** {@inheritDoc} */ public int read() throws IOException { final long remaining = this.remaining; if (remaining > 0) { final int b = delegate.read(); if (b > 0) this.remaining = remaining - 1; return b; } else { return -1; } } /** {@inheritDoc} */ public int read(final byte[] b, final int off, final int len) throws IOException { final long remaining = this.remaining; if (remaining == 0L) { return -1; } final int cnt = delegate.read(b, off, (int) Math.min((long)len, remaining)); if (cnt == -1) { return -1; } this.remaining = remaining - cnt; return cnt; } /** {@inheritDoc} */ public long skip(final long n) throws IOException { final long remaining = this.remaining; if (remaining == 0L || n <= 0L) { return 0L; } final long cnt = delegate.skip(Math.min(n, remaining)); if (cnt > 0L) { this.remaining = remaining - cnt; } return cnt; } /** {@inheritDoc} */ public int available() throws IOException { return Math.min(delegate.available(), (int) Math.min((long)Integer.MAX_VALUE, remaining)); } /** {@inheritDoc} */ public void close() throws IOException { remaining = 0; delegate.close(); } /** {@inheritDoc} */ public void mark(final int limit) { if (markSupported()) { delegate.mark(limit); mark = remaining; } } /** {@inheritDoc} */ public void reset() throws IOException { final long mark = this.mark; if (mark == -1L) { throw msg.markNotSet(); } delegate.reset(); remaining = mark; } /** {@inheritDoc} */ public boolean markSupported() { return delegate.markSupported(); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/streams/LimitedOutputStream.java000066400000000000000000000051011257016060700270030ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2010 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.streams; import java.io.IOException; import java.io.InterruptedIOException; import java.io.OutputStream; /** * An output stream which truncates the writable output to the given length. Attempting to exceed the * fixed limit will result in an exception. * * @author David M. Lloyd */ public final class LimitedOutputStream extends OutputStream { private final OutputStream delegate; private long remaining; /** * Construct a new instance. * * @param delegate the delegate output stream * @param size the number of bytes to allow */ public LimitedOutputStream(final OutputStream delegate, final long size) { this.delegate = delegate; remaining = size; } /** {@inheritDoc} */ public void write(final int b) throws IOException { final long remaining = this.remaining; if (remaining < 1) { throw notEnoughSpace(); } delegate.write(b); this.remaining = remaining - 1; } /** {@inheritDoc} */ public void write(final byte[] b, final int off, final int len) throws IOException { final long remaining = this.remaining; if (remaining < len) { throw notEnoughSpace(); } try { delegate.write(b, off, len); this.remaining = remaining - len; } catch (InterruptedIOException e) { this.remaining = remaining - (e.bytesTransferred & 0xFFFFFFFFL); throw e; } } /** {@inheritDoc} */ public void flush() throws IOException { delegate.flush(); } /** {@inheritDoc} */ public void close() throws IOException { delegate.close(); } private static IOException notEnoughSpace() { return new IOException("Not enough space in output stream"); } } xnio-3.3.2.Final/api/src/main/java/org/xnio/streams/Pipe.java000066400000000000000000000237631257016060700237320ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2010 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.streams; import static org.xnio._private.Messages.msg; import java.io.IOException; import java.io.InputStream; import java.io.InterruptedIOException; import java.io.OutputStream; import java.io.PipedInputStream; /** * An in-VM pipe between an input stream and an output stream, which does not suffer from the * bugs in {@link PipedInputStream}. * * @author David M. Lloyd */ public final class Pipe { private final Object lock = new Object(); /** the point at which a read shall occur **/ private int tail; /** the size of the buffer content **/ private int size; private final byte[] buffer; private boolean writeClosed; private boolean readClosed; /** * Construct a new instance. * * @param bufferSize the buffer size to use */ public Pipe(int bufferSize) { buffer = new byte[bufferSize]; } /** * Wait for the read side to close. Used when the writer needs to know when * the reader finishes consuming a message. */ public void await() { boolean intr = false; final Object lock = this.lock; try { synchronized (lock) { while (! readClosed) { try { lock.wait(); } catch (InterruptedException e) { intr = true; } } } } finally { if (intr) { Thread.currentThread().interrupt(); } } } private final InputStream in = new InputStream() { public int read() throws IOException { final Object lock = Pipe.this.lock; synchronized (lock) { if (writeClosed && size == 0) { return -1; } while (size == 0) { try { lock.wait(); if (writeClosed && size == 0) { return -1; } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw msg.interruptedIO(); } } lock.notifyAll(); int tail= Pipe.this.tail; try { return buffer[tail++] & 0xff; } finally { Pipe.this.tail = tail == buffer.length ? 0 : tail; size--; } } } public int read(final byte[] b, final int off, final int len) throws IOException { final Object lock = Pipe.this.lock; synchronized (lock) { if (writeClosed && size == 0) { return -1; } if (len == 0) { return 0; } int size; while ((size = Pipe.this.size) == 0) { try { lock.wait(); if (writeClosed && (size = Pipe.this.size) == 0) { return -1; } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw msg.interruptedIO(); } } final byte[] buffer = Pipe.this.buffer; final int bufLen = buffer.length; int cnt; int tail = Pipe.this.tail; if (size + tail > bufLen) { // wrapped final int lastLen = bufLen - tail; if (lastLen < len) { final int firstLen = tail + size - bufLen; System.arraycopy(buffer, tail, b, off, lastLen); int rem = Math.min(len - lastLen, firstLen); System.arraycopy(buffer, 0, b, off + lastLen, rem); cnt = rem + lastLen; } else { System.arraycopy(buffer, tail, b, off, len); cnt = len; } } else { // not wrapped cnt = Math.min(len, size); System.arraycopy(buffer, tail, b, off, cnt); } tail += cnt; size -= cnt; Pipe.this.tail = tail >= bufLen ? tail - bufLen : tail; Pipe.this.size = size; lock.notifyAll(); return cnt; } } public void close() throws IOException { final Object lock = Pipe.this.lock; synchronized (lock) { writeClosed = true; readClosed = true; // closing the read side drops the remaining bytes size = 0; lock.notifyAll(); return; } } public String toString() { return "Pipe read half"; } }; private final OutputStream out = new OutputStream() { public void write(final int b) throws IOException { final Object lock = Pipe.this.lock; synchronized (lock) { if (writeClosed) { throw msg.streamClosed(); } final byte[] buffer = Pipe.this.buffer; final int bufLen = buffer.length; while (size == bufLen) { try { lock.wait(); if (writeClosed) { throw msg.streamClosed(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw msg.interruptedIO(); } } final int tail = Pipe.this.tail; int startPos = tail + size; if (startPos >= bufLen) { buffer[startPos - bufLen] = (byte) b; } else { buffer[startPos] = (byte) b; } size ++; lock.notifyAll(); } } public void write(final byte[] b, int off, final int len) throws IOException { int remaining = len; final Object lock = Pipe.this.lock; synchronized (lock) { if (writeClosed) { throw msg.streamClosed(); } final byte[] buffer = Pipe.this.buffer; final int bufLen = buffer.length; int size; int tail; int cnt; while (remaining > 0) { while ((size = Pipe.this.size) == bufLen) { try { lock.wait(); if (writeClosed) { throw msg.streamClosed(); } } catch (InterruptedException e) { Thread.currentThread().interrupt(); throw msg.interruptedIO(len - remaining); } } tail = Pipe.this.tail; int startPos = tail + size; if (startPos >= bufLen) { // read wraps, write doesn't startPos -= bufLen; cnt = Math.min(remaining, bufLen - size); System.arraycopy(b, off, buffer, startPos, cnt); remaining -= cnt; off += cnt; } else { // write wraps, read doesn't final int firstPart = Math.min(remaining, bufLen - (tail + size)); System.arraycopy(b, off, buffer, startPos, firstPart); off += firstPart; remaining -= firstPart; if (remaining > 0) { final int latter = Math.min(remaining, tail); System.arraycopy(b, off, buffer, 0, latter); cnt = firstPart + latter; off += latter; remaining -= latter; } else { cnt = firstPart; } } Pipe.this.size += cnt; lock.notifyAll(); } } } public void close() throws IOException { final Object lock = Pipe.this.lock; synchronized (lock) { writeClosed = true; lock.notifyAll(); return; } } public String toString() { return "Pipe write half"; } }; /** * Get the input (read) side of the pipe. * * @return the input side */ public InputStream getIn() { return in; } /** * Get the output (write) side of the pipe. * * @return the output side */ public OutputStream getOut() { return out; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/streams/ReaderInputStream.java000066400000000000000000000160151257016060700264230ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2010 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.streams; import static org.xnio._private.Messages.msg; import java.io.IOException; import java.io.InputStream; import java.io.Reader; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import java.nio.charset.CoderResult; import java.nio.charset.CodingErrorAction; import org.xnio.Buffers; /** * An input stream which encodes characters into bytes. */ public final class ReaderInputStream extends InputStream { private final Reader reader; private final CharsetEncoder encoder; private final CharBuffer charBuffer; private final ByteBuffer byteBuffer; /** * Construct a new instance. * * @param reader the reader to encode from */ public ReaderInputStream(final Reader reader) { this(reader, Charset.defaultCharset()); } /** * Construct a new instance. * * @param reader the reader to encode from * @param charsetName the character set name * @throws UnsupportedEncodingException if the character set is not supported */ public ReaderInputStream(final Reader reader, final String charsetName) throws UnsupportedEncodingException { this(reader, Streams.getCharset(charsetName)); } /** * Construct a new instance. * * @param reader the reader to encode from * @param charset the character set */ public ReaderInputStream(final Reader reader, final Charset charset) { this(reader, getEncoder(charset)); } /** * Construct a new instance. * * @param reader the reader to encode from * @param encoder the character set encoder */ public ReaderInputStream(final Reader reader, final CharsetEncoder encoder) { this(reader, encoder, 1024); } /** * Construct a new instance. * * @param reader the reader to encode from * @param encoder the character set encoder * @param bufferSize the buffer size to use */ public ReaderInputStream(final Reader reader, final CharsetEncoder encoder, final int bufferSize) { if (reader == null) { throw msg.nullParameter("writer"); } if (encoder == null) { throw msg.nullParameter("decoder"); } if (bufferSize < 1) { throw msg.parameterOutOfRange("bufferSize"); } this.reader = reader; this.encoder = encoder; charBuffer = CharBuffer.wrap(new char[bufferSize]); byteBuffer = ByteBuffer.wrap(new byte[(int) ((float)bufferSize * encoder.averageBytesPerChar() + 0.5f)]); charBuffer.flip(); byteBuffer.flip(); } private static CharsetEncoder getEncoder(final Charset charset) { final CharsetEncoder encoder = charset.newEncoder(); encoder.onMalformedInput(CodingErrorAction.REPLACE); encoder.onUnmappableCharacter(CodingErrorAction.REPLACE); return encoder; } /** {@inheritDoc} */ public int read() throws IOException { final ByteBuffer byteBuffer = this.byteBuffer; if (! byteBuffer.hasRemaining()) { if (! fill()) { return -1; } } return byteBuffer.get() & 0xff; } /** {@inheritDoc} */ public int read(final byte[] b, int off, int len) throws IOException { final ByteBuffer byteBuffer = this.byteBuffer; int cnt = 0; while (len > 0) { final int r = byteBuffer.remaining(); if (r == 0) { if (! fill()) return cnt == 0 ? -1 : cnt; continue; } final int c = Math.min(r, len); byteBuffer.get(b, off, c); cnt += c; off += c; len -= c; } return cnt; } private boolean fill() throws IOException { final CharBuffer charBuffer = this.charBuffer; final ByteBuffer byteBuffer = this.byteBuffer; byteBuffer.compact(); boolean filled = false; try { while (byteBuffer.hasRemaining()) { while (charBuffer.hasRemaining()) { final CoderResult result = encoder.encode(charBuffer, byteBuffer, false); if (result.isOverflow()) { return true; } if (result.isUnderflow()) { filled = true; break; } if (result.isError()) { if (result.isMalformed()) { throw msg.malformedInput(); } if (result.isUnmappable()) { throw msg.unmappableCharacter(); } throw msg.characterDecodingProblem(); } } charBuffer.compact(); try { final int cnt = reader.read(charBuffer); if (cnt == -1) { return filled; } else if (cnt > 0) { filled = true; } } finally { charBuffer.flip(); } } return true; } finally { byteBuffer.flip(); } } /** {@inheritDoc} */ public long skip(long n) throws IOException { final ByteBuffer byteBuffer = this.byteBuffer; int cnt = 0; while (n > 0) { final int r = byteBuffer.remaining(); if (r == 0) { if (! fill()) return cnt; continue; } final int c = Math.min(r, n > (long) Integer.MAX_VALUE ? Integer.MAX_VALUE : (int) n); Buffers.skip(byteBuffer, c); cnt += c; n -= c; } return cnt; } /** {@inheritDoc} */ public int available() throws IOException { return byteBuffer.remaining(); } /** {@inheritDoc} */ public void close() throws IOException { byteBuffer.clear().flip(); charBuffer.clear().flip(); reader.close(); } /** * Get a string representation of this object. * * @return the string */ public String toString() { return "ReaderInputStream over " + reader; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/streams/Streams.java000066400000000000000000000064721257016060700244510ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.streams; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.nio.charset.Charset; import java.nio.charset.UnsupportedCharsetException; import org.xnio.IoUtils; /** * Stream utility class. * * @author David M. Lloyd */ public final class Streams { private Streams() { } /** * Copy from one stream to another. * * @param input the source stream * @param output the destination stream * @param close {@code true} if the input and output streams should be closed * @param bufferSize the buffer size * @throws IOException if an I/O error occurs */ public static void copyStream(InputStream input, OutputStream output, boolean close, int bufferSize) throws IOException { final byte[] buffer = new byte[bufferSize]; int res; try { for (;;) { res = input.read(buffer); if (res == -1) { if (close) { input.close(); output.close(); } return; } output.write(buffer, 0, res); } } finally { if (close) { IoUtils.safeClose(input); IoUtils.safeClose(output); } } } /** * Copy from one stream to another. A default buffer size is assumed. * * @param input the source stream * @param output the destination stream * @param close {@code true} if the input and output streams should be closed * @throws IOException if an I/O error occurs */ public static void copyStream(InputStream input, OutputStream output, boolean close) throws IOException { copyStream(input, output, close, 8192); } /** * Copy from one stream to another. A default buffer size is assumed, and both streams are closed on completion. * * @param input the source stream * @param output the destination stream * @throws IOException if an I/O error occurs */ public static void copyStream(InputStream input, OutputStream output) throws IOException { copyStream(input, output, true, 8192); } static Charset getCharset(final String charsetName) throws UnsupportedEncodingException { try { return Charset.forName(charsetName); } catch (UnsupportedCharsetException e) { throw new UnsupportedEncodingException(e.getMessage()); } } } xnio-3.3.2.Final/api/src/main/java/org/xnio/streams/WriterOutputStream.java000066400000000000000000000144071257016060700267010ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2010 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.streams; import static org.xnio._private.Messages.msg; import java.io.IOException; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import java.io.Writer; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import java.nio.charset.CoderResult; import java.nio.charset.CodingErrorAction; /** * An output stream which decodes bytes into a character writer. */ public final class WriterOutputStream extends OutputStream { private final Writer writer; private final CharsetDecoder decoder; private final ByteBuffer byteBuffer; private final char[] chars; private volatile boolean closed; /** * Construct a new instance. * * @param writer the writer to decode into */ public WriterOutputStream(final Writer writer) { this(writer, Charset.defaultCharset()); } /** * Construct a new instance. * * @param writer the writer to decode into * @param decoder the charset decoder to use */ public WriterOutputStream(final Writer writer, final CharsetDecoder decoder) { this(writer, decoder, 1024); } /** * Construct a new instance. * * @param writer the writer to decode into * @param decoder the charset decoder to use * @param bufferSize the buffer size to use */ public WriterOutputStream(final Writer writer, final CharsetDecoder decoder, int bufferSize) { if (writer == null) { throw msg.nullParameter("writer"); } if (decoder == null) { throw msg.nullParameter("decoder"); } if (bufferSize < 1) { throw msg.parameterOutOfRange("bufferSize"); } this.writer = writer; this.decoder = decoder; byteBuffer = ByteBuffer.allocate(bufferSize); chars = new char[(int) ((float)bufferSize * decoder.maxCharsPerByte() + 0.5f)]; } /** * Construct a new instance. * * @param writer the writer to decode into * @param charset the character set to use */ public WriterOutputStream(final Writer writer, final Charset charset) { this(writer, getDecoder(charset)); } /** * Construct a new instance. * * @param writer the writer to decode into * @param charsetName the character set name to use * @throws UnsupportedEncodingException if the character set name is unknown */ public WriterOutputStream(final Writer writer, final String charsetName) throws UnsupportedEncodingException { this(writer, Streams.getCharset(charsetName)); } private static CharsetDecoder getDecoder(final Charset charset) { final CharsetDecoder decoder = charset.newDecoder(); decoder.onMalformedInput(CodingErrorAction.REPLACE); decoder.onUnmappableCharacter(CodingErrorAction.REPLACE); decoder.replaceWith("?"); return decoder; } /** {@inheritDoc} */ public void write(final int b) throws IOException { if (closed) throw msg.streamClosed(); final ByteBuffer byteBuffer = this.byteBuffer; if (! byteBuffer.hasRemaining()) { doFlush(false); } byteBuffer.put((byte) b); } /** {@inheritDoc} */ public void write(final byte[] b, int off, int len) throws IOException { if (closed) throw msg.streamClosed(); final ByteBuffer byteBuffer = this.byteBuffer; // todo Correct first, fast later while (len > 0) { final int r = byteBuffer.remaining(); if (r == 0) { doFlush(false); continue; } final int c = Math.min(len, r); byteBuffer.put(b, off, c); len -= c; off += c; } } private void doFlush(final boolean eof) throws IOException { final CharBuffer charBuffer = CharBuffer.wrap(chars); final ByteBuffer byteBuffer = this.byteBuffer; final CharsetDecoder decoder = this.decoder; byteBuffer.flip(); try { while (byteBuffer.hasRemaining()) { final CoderResult result = decoder.decode(byteBuffer, charBuffer, eof); if (result.isOverflow()) { writer.write(chars, 0, charBuffer.position()); charBuffer.clear(); continue; } if (result.isUnderflow()) { final int p = charBuffer.position(); if (p > 0) { writer.write(chars, 0, p); } return; } if (result.isError()) { if (result.isMalformed()) { throw msg.malformedInput(); } if (result.isUnmappable()) { throw msg.unmappableCharacter(); } throw msg.characterDecodingProblem(); } } } finally { byteBuffer.compact(); } } /** {@inheritDoc} */ public void flush() throws IOException { if (closed) throw msg.streamClosed(); doFlush(false); writer.flush(); } /** {@inheritDoc} */ public void close() throws IOException { closed = true; doFlush(true); byteBuffer.clear(); writer.close(); } /** * Get the string representation of this object. * * @return the string */ public String toString() { return "Output stream writing to " + writer; } } xnio-3.3.2.Final/api/src/main/java/org/xnio/streams/package-info.java000066400000000000000000000001431257016060700253440ustar00rootroot00000000000000/** * Utility classes for creating streams which use XNIO channels. */ package org.xnio.streams; xnio-3.3.2.Final/api/src/main/java/overview.html000066400000000000000000000004671257016060700215000ustar00rootroot00000000000000An advanced non-blocking I/O API designed for utility and scalability. XNIO is based on the NIO concept of channels and buffers, and adds a channel-ready callback layer. In addition there are many utility classes and methods for performing zero-copy operations, buffer management, blocking I/O, SSL, and more.xnio-3.3.2.Final/api/src/main/resources/000077500000000000000000000000001257016060700200265ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/resources/org/000077500000000000000000000000001257016060700206155ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/resources/org/xnio/000077500000000000000000000000001257016060700215725ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/main/resources/org/xnio/Version.properties000066400000000000000000000000711257016060700253330ustar00rootroot00000000000000version=${project.version} jarName=${project.artifactId} xnio-3.3.2.Final/api/src/test/000077500000000000000000000000001257016060700160475ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/000077500000000000000000000000001257016060700167705ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/java/000077500000000000000000000000001257016060700177115ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/java/nio/000077500000000000000000000000001257016060700204765ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/java/nio/channels/000077500000000000000000000000001257016060700222715ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/java/nio/channels/FileChannel.java000066400000000000000000000055341257016060700253130ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 java.nio.channels; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.spi.AbstractInterruptibleChannel; /** * Compatibility stub. */ public abstract class FileChannel extends AbstractInterruptibleChannel implements GatheringByteChannel, ScatteringByteChannel { protected FileChannel() {} public abstract int read(ByteBuffer dst) throws IOException; public abstract long read(ByteBuffer[] dsts, int offset, int length) throws IOException; public final long read(ByteBuffer[] dsts) throws IOException { return 0L; } public abstract int write(ByteBuffer src) throws IOException; public abstract long write(ByteBuffer[] srcs, int offset, int length) throws IOException; public final long write(ByteBuffer[] srcs) throws IOException { return 0L; } public abstract long position() throws IOException; public abstract FileChannel position(long newPosition) throws IOException; public abstract long size() throws IOException; public abstract FileChannel truncate(long size) throws IOException; public abstract void force(boolean metaData) throws IOException; public abstract long transferTo(long position, long count, WritableByteChannel target) throws IOException; public abstract long transferFrom(ReadableByteChannel src, long position, long count) throws IOException; public abstract int read(ByteBuffer dst, long position) throws IOException; public abstract int write(ByteBuffer src, long position) throws IOException; public abstract MappedByteBuffer map(MapMode mode, long position, long size) throws IOException; public abstract FileLock lock(long position, long size, boolean shared) throws IOException; public final FileLock lock() throws IOException { return null; }; public abstract FileLock tryLock(long position, long size, boolean shared) throws IOException; public final FileLock tryLock() throws IOException { return null; } public static class MapMode { public static final MapMode READ_ONLY = null; public static final MapMode READ_WRITE = null; public static final MapMode PRIVATE = null; } } xnio-3.3.2.Final/api/src/test/java/org/000077500000000000000000000000001257016060700175575ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/org/xnio/000077500000000000000000000000001257016060700205345ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/org/xnio/AbstractConvertingIoFutureTestCase.java000066400000000000000000000240561257016060700303270ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.concurrent.CancellationException; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; import org.xnio.IoFuture.Status; /** * Test for {@link AbstractConvertingIoFuture}. * * @author Flavia Rainone * */ public class AbstractConvertingIoFutureTestCase { private StringFuture delegate; private StringToCharArrayFuture convertingFuture; @Before public void init() { delegate = new StringFuture("Test"); convertingFuture = new StringToCharArrayFuture(delegate); } @Test public void delegate() { assertSame(delegate, convertingFuture.getDelegate()); } @Test public void convertValue() throws IOException { char[] result = convertingFuture.get(); assertNotNull(result); assertEquals(4, result.length); assertEquals('T', result[0]); assertEquals('e', result[1]); assertEquals('s', result[2]); assertEquals('t', result[3]); } @Test public void convertValueInterruptibly() throws IOException, InterruptedException { char[] result = convertingFuture.getInterruptibly(); assertNotNull(result); assertEquals(5, result.length); assertEquals('T', result[0]); assertEquals('e', result[1]); assertEquals('s', result[2]); assertEquals('t', result[3]); assertEquals('!', result[4]); } @Test public void cancel() { assertFalse(delegate.isCanceled()); assertSame(convertingFuture, convertingFuture.cancel()); assertTrue(delegate.isCanceled()); } @Test public void status() { delegate.setStatus(Status.FAILED); assertSame(Status.FAILED, convertingFuture.getStatus()); delegate.setStatus(Status.DONE); assertSame(Status.DONE, convertingFuture.getStatus()); delegate.setStatus(Status.FAILED); assertSame(Status.FAILED, convertingFuture.getStatus()); delegate.setStatus(Status.WAITING); assertSame(Status.WAITING, convertingFuture.getStatus()); } @Test public void await() { delegate.setStatus(Status.WAITING); assertFalse(delegate.hasAwaited()); assertSame(Status.WAITING, convertingFuture.await()); assertTrue(delegate.hasAwaited()); } @Test public void awaitWithTimeout() { delegate.setStatus(Status.DONE); assertFalse(delegate.hasAwaited()); assertSame(Status.DONE, convertingFuture.await(10, TimeUnit.SECONDS)); assertTrue(delegate.hasAwaited()); assertEquals(10, delegate.getAwaitTime()); assertEquals(TimeUnit.SECONDS, delegate.getAwaitTimeUnit()); assertSame(Status.DONE, convertingFuture.await(1, TimeUnit.DAYS)); assertTrue(delegate.hasAwaited()); assertEquals(1, delegate.getAwaitTime()); assertEquals(TimeUnit.DAYS, delegate.getAwaitTimeUnit()); } @Test public void awaitInterruptibly() throws InterruptedException { delegate.setStatus(Status.CANCELLED); assertFalse(delegate.hasAwaitedInterruptibly()); assertSame(Status.CANCELLED, convertingFuture.awaitInterruptibly()); assertTrue(delegate.hasAwaitedInterruptibly()); } @Test public void awaitInterruptiblyWithTimeout() throws InterruptedException { delegate.setStatus(Status.WAITING); assertFalse(delegate.hasAwaited()); assertSame(Status.WAITING, convertingFuture.awaitInterruptibly(10, TimeUnit.SECONDS)); assertTrue(delegate.hasAwaitedInterruptibly()); assertEquals(10, delegate.getAwaitTime()); assertEquals(TimeUnit.SECONDS, delegate.getAwaitTimeUnit()); assertSame(Status.WAITING, convertingFuture.awaitInterruptibly(1, TimeUnit.DAYS)); assertTrue(delegate.hasAwaitedInterruptibly()); assertEquals(1, delegate.getAwaitTime()); assertEquals(TimeUnit.DAYS, delegate.getAwaitTimeUnit()); } @Test public void exception() { final IOException exception1 = new IOException("Test exception"); final IOException exception2 = new IOException("Test exception"); final IOException exception3 = new IOException("Test exception"); delegate.setException(exception1); assertSame(exception1, convertingFuture.getException()); delegate.setException(exception2); assertSame(exception2, convertingFuture.getException()); delegate.setException(exception3); assertSame(exception3, convertingFuture.getException()); } @Test public void futureNotifier() { final CharArrayNotifier notifier = new CharArrayNotifier(); final Object attachment = new Object(); assertSame(convertingFuture, convertingFuture.addNotifier(notifier, attachment)); assertFalse(notifier.isInvoked()); delegate.invokeNotifier(); assertTrue(notifier.isInvoked()); assertSame(convertingFuture, notifier.getFuture()); assertSame(attachment, notifier.getAttachment()); } private static class StringFuture implements IoFuture { private String value; private boolean canceled; private Status status; private boolean awaited; private boolean awaitedInterruptibly; private long awaitTime; private TimeUnit awaitTimeUnit; private IOException exception; private IoFuture.Notifier notifier; private Object notifierAttachment; public StringFuture(String v) { value = v; } @Override public IoFuture cancel() { canceled = true; return this; } public boolean isCanceled() { return canceled; } public void setStatus(Status s) { status = s; } @Override public Status getStatus() { return status; } @Override public Status await() { awaited = true; return status; } public boolean hasAwaited() { return awaited; } @Override public Status await(long time, TimeUnit timeUnit) { awaited = true; awaitTime = time; awaitTimeUnit = timeUnit; return status; } public long getAwaitTime() { return awaitTime; } public TimeUnit getAwaitTimeUnit() { return awaitTimeUnit; } public boolean hasAwaitedInterruptibly() { return awaitedInterruptibly; } @Override public Status awaitInterruptibly() throws InterruptedException { awaitedInterruptibly = true; return status; } @Override public Status awaitInterruptibly(long time, TimeUnit timeUnit) throws InterruptedException { awaitedInterruptibly = true; awaitTime = time; awaitTimeUnit = timeUnit; return status; } @Override public String get() throws IOException, CancellationException { return value; } @Override public String getInterruptibly() throws IOException, InterruptedException, CancellationException { return value + "!"; } @Override public IOException getException() throws IllegalStateException { return exception; } public void setException(IOException e) { exception = e; } @SuppressWarnings("unchecked") @Override public IoFuture addNotifier(IoFuture.Notifier notifier, A attachment) { if (this.notifier != null) { throw new IllegalStateException("This test class supports only one notifier at most"); } this.notifier = (IoFuture.Notifier) notifier; this.notifierAttachment = attachment; return this; } public void invokeNotifier() { notifier.notify(this, notifierAttachment); } } private static class StringToCharArrayFuture extends AbstractConvertingIoFuture { protected StringToCharArrayFuture(IoFuture delegate) { super(delegate); } @Override protected char[] convert(String arg) throws IOException { return arg.toCharArray(); } } private static class CharArrayNotifier implements IoFuture.Notifier { private boolean invoked; private IoFuture future; private Object attachment; @Override public void notify(IoFuture f, Object a) { invoked = true; future = f; attachment = a; } public boolean isInvoked() { return invoked; } public IoFuture getFuture() { return future; } public Object getAttachment() { return attachment; } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/AbstractIoFutureTestCase.java000066400000000000000000000607711257016060700262740ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.concurrent.CancellationException; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; import org.xnio.IoFuture.Status; /** * Test for {@link AbstractIoFuture}. * * @author Flavia Rainone * */ public class AbstractIoFutureTestCase { private TestIoFuture future; @Before public void createFuture() { future = new TestIoFuture(); assertSame(Status.WAITING, future.getStatus()); } @Test public void waitForResult() throws InterruptedException { final Awaiter awaiter = new Awaiter(future); final Thread awaiterThread = new Thread(awaiter); awaiterThread.start(); awaiterThread.join(100); assertTrue(awaiterThread.isAlive()); assertTrue(future.setResult("test")); awaiterThread.join(); assertSame(Status.DONE, future.getStatus()); assertSame(Status.DONE, awaiter.getAwaitStatus()); assertSame(Status.DONE, future.await()); // shouldn't block assertFalse(future.setResult("second reult")); } @Test public void interruptWaiter() throws InterruptedException { final Awaiter awaiter = new Awaiter(future); final Thread awaiterThread = new Thread(awaiter); awaiterThread.start(); // interrupt a couple of times for (int i = 0; i < 3; i++) { awaiterThread.interrupt(); Thread.sleep(100); } assertSame(Status.WAITING, future.getStatus()); assertSame(future, future.cancel()); awaiterThread.join(); assertSame(Status.CANCELLED, awaiter.getAwaitStatus()); } @Test public void waitForResultWithTimeout() throws InterruptedException { final Awaiter awaiter = new Awaiter(future, 1, TimeUnit.DAYS); final Thread awaiterThread = new Thread(awaiter); awaiterThread.start(); awaiterThread.join(100); assertTrue(awaiterThread.isAlive()); assertTrue(future.setResult("test")); awaiterThread.join(); assertSame(Status.DONE, future.getStatus()); assertSame(Status.DONE, awaiter.getAwaitStatus()); assertSame(Status.DONE, future.await(100, TimeUnit.MILLISECONDS)); // shouldn't block assertFalse(future.setResult("second result")); } @Test public void interruptWaiterWithTimeout() throws InterruptedException { assertSame(Status.WAITING, future.await(0, TimeUnit.MICROSECONDS)); assertSame(Status.WAITING, future.await(-5, TimeUnit.MICROSECONDS)); final Awaiter awaiter = new Awaiter(future, 1000, TimeUnit.SECONDS); final Thread awaiterThread = new Thread(awaiter); awaiterThread.start(); // interrupt a couple of times for (int i = 0; i < 3; i++) { awaiterThread.interrupt(); Thread.sleep(100); } assertSame(Status.WAITING, future.getStatus()); assertTrue(awaiterThread.isAlive()); assertSame(future, future.cancel()); awaiterThread.join(); assertSame(Status.CANCELLED, awaiter.getAwaitStatus()); assertSame(Status.CANCELLED, future.getStatus()); } @Test public void waitInterruptiblyForResult() throws InterruptedException { final InterruptiblyAwaiter awaiter = new InterruptiblyAwaiter(future); final Thread awaiterThread = new Thread(awaiter); awaiterThread.start(); awaiterThread.join(100); assertTrue(awaiterThread.isAlive()); assertTrue(future.setResult("test")); awaiterThread.join(); assertSame(Status.DONE, future.getStatus()); assertSame(Status.DONE, awaiter.getAwaitStatus()); assertSame(Status.DONE, future.awaitInterruptibly()); // shouldn't block assertFalse(future.setResult("second reult")); } @Test public void interruptInterruptiblyWaiter() throws InterruptedException { final InterruptiblyAwaiter awaiter = new InterruptiblyAwaiter(future); final Thread awaiterThread = new Thread(awaiter); awaiterThread.start(); // interrupt a couple of times for (int i = 0; i < 3; i++) { awaiterThread.interrupt(); Thread.sleep(100); } assertSame(Status.WAITING, future.getStatus()); assertSame(future, future.cancel()); awaiterThread.join(); assertSame(null, awaiter.getAwaitStatus()); assertNotNull(awaiter.getException()); } @Test public void waitInterruptiblyForResultWithTimeout() throws InterruptedException { final InterruptiblyAwaiter awaiter = new InterruptiblyAwaiter(future, 1, TimeUnit.DAYS); final Thread awaiterThread = new Thread(awaiter); awaiterThread.start(); awaiterThread.join(100); assertTrue(awaiterThread.isAlive()); assertTrue(future.setResult("test")); awaiterThread.join(); assertSame(Status.DONE, future.getStatus()); assertSame(Status.DONE, awaiter.getAwaitStatus()); assertSame(Status.DONE, future.awaitInterruptibly(100, TimeUnit.MILLISECONDS)); // shouldn't block assertFalse(future.setResult("second result")); } @Test public void interruptInterruptiblyWaiterWithTimeout() throws InterruptedException { assertSame(Status.WAITING, future.awaitInterruptibly(0, TimeUnit.MICROSECONDS)); assertSame(Status.WAITING, future.awaitInterruptibly(-5, TimeUnit.MICROSECONDS)); final InterruptiblyAwaiter awaiter = new InterruptiblyAwaiter(future, 1000, TimeUnit.SECONDS); final Thread awaiterThread = new Thread(awaiter); awaiterThread.start(); // interrupt a couple of times for (int i = 0; i < 3; i++) { awaiterThread.interrupt(); Thread.sleep(100); } assertSame(Status.WAITING, future.getStatus()); assertFalse(awaiterThread.isAlive()); assertSame(future, future.cancel()); awaiterThread.join(); assertSame(null, awaiter.getAwaitStatus()); assertNotNull(awaiter.getException()); assertSame(Status.CANCELLED, future.getStatus()); } @Test public void retrieveFutureResult() throws Exception { final ResultRetriever resultRetriever = new ResultRetriever(future); final Thread retrieverThread = new Thread(resultRetriever); retrieverThread.start(); retrieverThread.join(100); assertTrue(retrieverThread.isAlive()); assertTrue(future.setResult("get this")); retrieverThread.join(); assertSame(Status.DONE, future.getStatus()); assertSame("get this", resultRetriever.getResult()); assertSame("get this", future.get()); // shouldn't block // cannot change the result nor set a new result assertFalse(future.setResult("second result")); assertFalse(future.setException(new IOException())); assertFalse(future.setCancelled()); } @Test public void retrieveFutureFailure() throws InterruptedException { final ResultRetriever resultRetriever = new ResultRetriever(future); final Thread retrieverThread = new Thread(resultRetriever); retrieverThread.start(); retrieverThread.join(100); assertTrue(retrieverThread.isAlive()); final IOException exception = new IOException("Test exception"); assertTrue(future.setException(exception)); // can't set any result after setting exception assertFalse(future.setException(exception)); assertFalse(future.setCancelled()); assertFalse(future.setResult("anything")); retrieverThread.join(); assertSame(Status.FAILED, future.getStatus()); assertNull(resultRetriever.getResult()); assertSame(exception, resultRetriever.getIOException()); IOException expected = null; try { future.get(); // shouldn't block } catch (IOException e) { expected = e; } assertNotNull(expected); } @Test public void retrieveFutureCancellationResult() throws Exception { final ResultRetriever resultRetriever = new ResultRetriever(future); final Thread retrieverThread = new Thread(resultRetriever); retrieverThread.start(); retrieverThread.join(100); assertTrue(retrieverThread.isAlive()); future.cancel(); // can't set any result after canceling assertFalse(future.setException(new IOException())); assertFalse(future.setCancelled()); future.cancel(); // useless call, future is already canceled assertFalse(future.setResult("anything")); retrieverThread.join(); assertSame(Status.CANCELLED, future.getStatus()); assertNull(resultRetriever.getResult()); assertNotNull(resultRetriever.getCancellationException()); CancellationException expected = null; try { future.get(); // shouldn't block } catch (CancellationException e) { expected = e; } assertNotNull(expected); } @Test public void interruptResultRetrieval() throws InterruptedException { final ResultRetriever resultRetriever= new ResultRetriever(future); final Thread retrieverThread = new Thread(resultRetriever); retrieverThread.start(); // interrupt a couple of times for (int i = 0; i < 3; i++) { retrieverThread.interrupt(); Thread.sleep(100); } assertSame(Status.WAITING, future.getStatus()); assertSame(future, future.cancel()); retrieverThread.join(); assertSame(null, resultRetriever.getResult()); assertNotNull(resultRetriever.getCancellationException()); } @Test public void retrieveFutureResultInterruptibly() throws Exception { final ResultRetriever resultRetriever = new ResultRetriever(future, true); final Thread retrieverThread = new Thread(resultRetriever); retrieverThread.start(); retrieverThread.join(100); assertTrue(retrieverThread.isAlive()); assertTrue(future.setResult("get this")); retrieverThread.join(); assertSame(Status.DONE, future.getStatus()); assertSame("get this", resultRetriever.getResult()); assertSame("get this", future.get()); // shouldn't block // cannot change the result nor set a new result assertFalse(future.setResult("second result")); assertFalse(future.setException(new IOException())); assertFalse(future.setCancelled()); } @Test public void retrieveFutureFailureInterruptibly() throws InterruptedException { final ResultRetriever resultRetriever = new ResultRetriever(future, true); final Thread retrieverThread = new Thread(resultRetriever); retrieverThread.start(); retrieverThread.join(100); assertTrue(retrieverThread.isAlive()); final IOException exception = new IOException("Test exception"); assertTrue(future.setException(exception)); // can't set any result after setting exception assertFalse(future.setException(exception)); assertFalse(future.setCancelled()); assertFalse(future.setResult("anything")); retrieverThread.join(); assertSame(Status.FAILED, future.getStatus()); assertNull(resultRetriever.getResult()); assertSame(exception, resultRetriever.getIOException()); IOException expected = null; try { future.get(); // shouldn't block } catch (IOException e) { expected = e; } assertNotNull(expected); } @Test public void retrieveFutureCancellationResultInterruptibly() throws Exception { final ResultRetriever resultRetriever = new ResultRetriever(future, true); final Thread retrieverThread = new Thread(resultRetriever); retrieverThread.start(); retrieverThread.join(100); assertTrue(retrieverThread.isAlive()); future.cancel(); // can't set any result after canceling assertFalse(future.setException(new IOException())); assertFalse(future.setCancelled()); future.cancel(); // useless call, future is already canceled assertFalse(future.setResult("anything")); retrieverThread.join(); assertSame(Status.CANCELLED, future.getStatus()); assertNull(resultRetriever.getResult()); assertNotNull(resultRetriever.getCancellationException()); CancellationException expected = null; try { future.get(); // shouldn't block } catch (CancellationException e) { expected = e; } assertNotNull(expected); } @Test public void interruptInterruptiblyResultRetrieval() throws InterruptedException { final ResultRetriever resultRetriever= new ResultRetriever(future, true); final Thread retrieverThread = new Thread(resultRetriever); retrieverThread.start(); // interrupt a couple of times for (int i = 0; i < 3; i++) { retrieverThread.interrupt(); Thread.sleep(100); } assertSame(Status.WAITING, future.getStatus()); retrieverThread.join(); assertSame(null, resultRetriever.getResult()); assertNotNull(resultRetriever.getInterruptedException()); } @Test public void setAndRetrieveException () { final IOException exception = new IOException(); future.setException(exception); assertSame(exception, future.getException()); assertFalse(future.setException(new IOException())); assertFalse(future.setException(new IOException())); assertFalse(future.setException(new IOException())); assertFalse(future.setException(new IOException())); assertSame(exception, future.getException()); // wrongfully try to retrieve non-existent exception IllegalStateException expected = null; final TestIoFuture future2 = new TestIoFuture(); future2.setResult("future2"); try { future2.getException(); } catch (IllegalStateException e) { expected = e; } assertNotNull(expected); expected = null; final TestIoFuture future3 = new TestIoFuture(); future3.cancel(); try { future3.getException(); } catch (IllegalStateException e) { expected = e; } assertNotNull(expected); expected = null; final TestIoFuture future4 = new TestIoFuture(); assertSame(Status.WAITING, future4.getStatus()); try { future4.getException(); } catch (IllegalStateException e) { expected = e; } assertNotNull(expected); } private void checkNotifiers(Runnable stopWaitingTask) { final TestNotifier notifier1 = new TestNotifier(); final TestNotifier notifier2 = new TestNotifier(); final TestNotifier notifier3 = new TestNotifier(); final TestNotifier notifier4 = new TestNotifier(); final TestNotifier notifier5 = new TestNotifier(); notifier2.throwExceptionOnNotify(); final Object attachment1 = new Object(); final Object attachment2 = new Object(); final Object attachment3 = new Object(); final Object attachment4 = new Object(); final Object attachment5 = new Object(); future.addNotifier(notifier1, attachment1); future.addNotifier(notifier2, attachment2); future.addNotifier(notifier3, attachment3); future.addNotifier(notifier4, attachment4); assertFalse(notifier1.isInvoked()); assertFalse(notifier2.isInvoked()); assertFalse(notifier3.isInvoked()); assertFalse(notifier4.isInvoked()); stopWaitingTask.run(); assertTrue(notifier1.isInvoked()); assertSame(future, notifier1.getFuture()); assertSame(attachment1, notifier1.getAttachment()); assertTrue(notifier2.isInvoked()); assertSame(future, notifier2.getFuture()); assertSame(attachment2, notifier2.getAttachment()); assertTrue(notifier3.isInvoked()); assertSame(future, notifier3.getFuture()); assertSame(attachment3, notifier3.getAttachment()); assertTrue(notifier4.isInvoked()); assertSame(future, notifier4.getFuture()); assertSame(attachment4, notifier4.getAttachment()); assertFalse(notifier5.isInvoked()); future.addNotifier(notifier5, attachment5); assertTrue(notifier5.isInvoked()); assertSame(future, notifier5.getFuture()); assertSame(attachment5, notifier5.getAttachment()); } @Test public void checkNotifiersWhenDone() { checkNotifiers(new Runnable() { public void run() { future.setResult("run notifiers"); } }); } @Test public void checkNotifiersWhenCancelled() { checkNotifiers(new Runnable() { public void run() { future.cancel(); } }); } @Test public void checkNotifiersWhenFailed() { checkNotifiers(new Runnable() { public void run() { future.setException(new IOException("Test exceptionś")); } }); } @Test public void invokeCancelHandlers() { final TestCancelHandler cancelHandler1 = new TestCancelHandler(); final TestCancelHandler cancelHandler2 = new TestCancelHandler(); final TestCancelHandler cancelHandler3 = new TestCancelHandler(); final TestCancelHandler cancelHandler4 = new TestCancelHandler(); future.addCancelHandler(cancelHandler1); future.addCancelHandler(cancelHandler2); assertFalse(cancelHandler1.isInvoked()); assertFalse(cancelHandler2.isInvoked()); future.startCancellation(); assertTrue(cancelHandler1.isInvoked()); assertTrue(cancelHandler2.isInvoked()); cancelHandler1.clear(); cancelHandler2.clear(); // should be idempotent future.startCancellation(); assertFalse(cancelHandler1.isInvoked()); assertFalse(cancelHandler2.isInvoked()); future.addCancelHandler(cancelHandler3); assertTrue(cancelHandler3.isInvoked()); cancelHandler3.clear(); assertSame(Status.WAITING, future.getStatus()); future.concludeCancellation(); future.addCancelHandler(cancelHandler4); assertTrue(cancelHandler4.isInvoked()); // no cancel handler should have been invoked again, they must be called only once assertFalse(cancelHandler1.isInvoked()); assertFalse(cancelHandler2.isInvoked()); assertFalse(cancelHandler3.isInvoked()); } private static class TestIoFuture extends AbstractIoFuture { @Override public TestIoFuture cancel() { super.cancel(); setCancelled(); return this; } public void startCancellation() { super.cancel(); } public void concludeCancellation() { setCancelled(); } } private static class Awaiter implements Runnable { private final IoFuture ioFuture; private final long timeout; private final TimeUnit timeoutUnit; private Status status; public Awaiter(IoFuture f) { this(f, -1, null); } public Awaiter(IoFuture f, long t, TimeUnit tu) { ioFuture = f; timeout = t; timeoutUnit = tu; } public void run() { if (timeoutUnit == null) { status = ioFuture.await(); } else { status = ioFuture.await(timeout, timeoutUnit); } } public Status getAwaitStatus() { return status; } } private static class InterruptiblyAwaiter implements Runnable { private final IoFuture ioFuture; private final long timeout; private final TimeUnit timeoutUnit; private InterruptedException exception; private Status status; public InterruptiblyAwaiter(IoFuture f) { this(f, -1, null); } public InterruptiblyAwaiter(IoFuture f, long t, TimeUnit tu) { ioFuture = f; timeout = t; timeoutUnit = tu; } public void run() { try { if (timeoutUnit == null) { status = ioFuture.awaitInterruptibly(); } else { status = ioFuture.awaitInterruptibly(timeout, timeoutUnit); } } catch (InterruptedException e) { exception = e; } } public InterruptedException getException() { return exception; } public Status getAwaitStatus() { return status; } } private static class ResultRetriever implements Runnable { private final IoFuture ioFuture; private final boolean interruptibly; private String result; private CancellationException cancellationException; private IOException exception; private InterruptedException interruptedException; public ResultRetriever(IoFuture f) { this(f, false); } public ResultRetriever(IoFuture f, boolean i) { ioFuture = f; interruptibly = i; } public void run() { try { if (interruptibly) { result = ioFuture.getInterruptibly(); } else { result = ioFuture.get(); } } catch (CancellationException e) { cancellationException = e; } catch (IOException e) { exception = e; } catch (InterruptedException e) { interruptedException = e; } } public String getResult() { return result; } public CancellationException getCancellationException() { return cancellationException; } public InterruptedException getInterruptedException() { return interruptedException; } public IOException getIOException() { return exception; } } private static class TestNotifier implements IoFuture.Notifier { private boolean throwException; private boolean invoked; private IoFuture future; private Object attachment; public void throwExceptionOnNotify() { throwException = true; } @Override public void notify(IoFuture f, Object a) { invoked = true; future = f; attachment = a; if (throwException) { throw new RuntimeException("Test exception"); } } public boolean isInvoked() { return invoked; } public IoFuture getFuture() { return future; } public Object getAttachment() { return attachment; } } private static class TestCancelHandler implements Cancellable { private boolean invoked; @Override public Cancellable cancel() { invoked = true; return this; } public boolean isInvoked() { return invoked; } public void clear() { invoked = false; } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/AssertReadWrite.java000066400000000000000000000076701257016060700244610ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertEquals; import java.nio.ByteBuffer; import org.xnio.mock.ConduitMock; import org.xnio.mock.ConnectedStreamChannelMock; /** * This class contains common assertions performed by tests after a read or a write operation. * * @author Flavia Rainone * */ public class AssertReadWrite { /** * Asserts that the message read by {@code sslChannel}, contained in {@code dst}, equals {@code message}. * @param dst the buffer containing the read message * @param message message expected to have been read into {@code dst} */ public static final void assertReadMessage(ByteBuffer dst, String... message) { final StringBuffer stringBuffer = new StringBuffer(); for (String messageString: message) { stringBuffer.append(messageString); } dst.flip(); assertEquals(stringBuffer.toString(), Buffers.getModifiedUtf8(dst)); } /** * Asserts that the message read by {@code sslChannel}, contained in {@code dst}, equals {@code message}. * @param dst the byte array containing the read message * @param message message expected to have been read into {@code dst} */ public static final void assertReadMessage(byte[] dst, String... message) { final StringBuffer stringBuffer = new StringBuffer(); for (String messageString: message) { stringBuffer.append(messageString); } final ByteBuffer buffer = ByteBuffer.wrap(dst); buffer.limit(stringBuffer.length()); assertEquals(stringBuffer.toString(), Buffers.getModifiedUtf8(buffer)); } /** * Asserts that {@code message} equals the data written to {@code connectedChannelMock}. * * @param connectedChannelMock the channel mock where {@code message} should have been written to * @param message the message expected to have been written to the channel mock */ public static final void assertWrittenMessage(ConnectedStreamChannelMock connectedChannelMock, String... message) { final StringBuffer stringBuffer = new StringBuffer(); for (String messageString: message) { stringBuffer.append(messageString); } assertEquals("expected total size: "+ stringBuffer.length() + " actual length: " + connectedChannelMock.getWrittenText().length(), stringBuffer.toString(), connectedChannelMock.getWrittenText()); } /** * Asserts that {@code message} equals the data written to {@code conduitMock}. * * @param conduitMock the conduit mock where {@code message} should have been written to * @param message the message expected to have been written to the channel mock */ public static final void assertWrittenMessage(ConduitMock conduitMock, String... message) { final StringBuffer stringBuffer = new StringBuffer(); for (String messageString: message) { stringBuffer.append(messageString); } assertEquals("expected total size: "+ stringBuffer.length() + " actual length: " + conduitMock.getWrittenText().length(), stringBuffer.toString(), conduitMock.getWrittenText()); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/BitsTestCase.java000066400000000000000000000214001257016060700237310ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import junit.framework.TestCase; import static org.xnio.Bits.*; /** * Test for {@link Bits}. * * @author David M. Lloyd * @author Flavia Rainone */ public final class BitsTestCase extends TestCase { public void testBitMask() { assertEquals(0x00FFFF00, intBitMask(8, 23)); assertEquals(1, intBitMask(0, 0)); assertEquals(0xFFFFFFFF, intBitMask(0, 31)); assertEquals(0x80000000, intBitMask(31, 31)); assertEquals(0x00FFFFFFFFFFFF00L, longBitMask(8, 55)); assertEquals(1L, longBitMask(0, 0)); assertEquals(0xFFFFFFFFFFFFFFFFL, longBitMask(0, 63)); assertEquals(0x8000000000000000L, longBitMask(63, 63)); } public void testInvalidBitMask() { AssertionError expected = null; try { intBitMask(-8, 23); } catch (AssertionError e) { expected = e; } assertNotNull(expected); expected = null; try { intBitMask(24, 23); } catch (AssertionError e) { expected = e; } assertNotNull(expected); expected = null; try { intBitMask(8, 32); } catch (AssertionError e) { expected = e; } expected = null; try { longBitMask(-8, 55); } catch (AssertionError e) { expected = e; } assertNotNull(expected); expected = null; try { longBitMask(56, 55); } catch (AssertionError e) { expected = e; } assertNotNull(expected); expected = null; try { longBitMask(8, 64); } catch (AssertionError e) { expected = e; } assertNotNull(expected); } public void testAllAreClearInt() { assertTrue(allAreClear(0xFF00FF00, 0x00FF00FF)); assertTrue(allAreClear(0xFF00FF00, 0x00230042)); assertTrue(allAreClear(0xFF00FF00, 0)); assertFalse(allAreClear(0xFF00FF00, 0xFF00FF00)); assertFalse(allAreClear(0xFF00FF00, 0x3A00E300)); assertFalse(allAreClear(0xFF00FF00, 0xFFFFFFFF)); assertFalse(allAreClear(0xFF00FF00, 0x00000100)); assertFalse(allAreClear(0xFF00FF00, 0x80000000)); } public void testAllAreClearLong() { assertTrue(allAreClear(0xFF00FF00FF00FF00L, 0x00FF00FF00FF00FFL)); assertTrue(allAreClear(0xFF00FF00FF00FF00L, 0x0023004200110055L)); assertTrue(allAreClear(0xFF00FF00FF00FF00L, 0)); assertFalse(allAreClear(0xFF00FF00FF00FF00L, 0xFF00FF00FF00FF00L)); assertFalse(allAreClear(0xFF00FF00FF00FF00L, 0x3A00E3004D002200L)); assertFalse(allAreClear(0xFF00FF00FF00FF00L, 0xFFFFFFFFFFFFFFFFL)); assertFalse(allAreClear(0xFF00FF00FF00FF00L, 0x0000010000000000L)); assertFalse(allAreClear(0xFF00FF00FF00FF00L, 0x8000000000000000L)); } // anyAreSet is the inverse of allAreClear, so each test should be duplicated in both sections public void testAnyAreSetInt() { assertFalse(anyAreSet(0xFF00FF00, 0x00FF00FF)); assertFalse(anyAreSet(0xFF00FF00, 0x00230042)); assertFalse(anyAreSet(0xFF00FF00, 0)); assertTrue(anyAreSet(0xFF00FF00, 0xFF00FF00)); assertTrue(anyAreSet(0xFF00FF00, 0x3A00E300)); assertTrue(anyAreSet(0xFF00FF00, 0xFFFFFFFF)); assertTrue(anyAreSet(0xFF00FF00, 0x00000100)); assertTrue(anyAreSet(0xFF00FF00, 0x80000000)); } public void testAnyAreSetLong() { assertFalse(anyAreSet(0xFF00FF00FF00FF00L, 0x00FF00FF00FF00FFL)); assertFalse(anyAreSet(0xFF00FF00FF00FF00L, 0x0023004200110055L)); assertFalse(anyAreSet(0xFF00FF00FF00FF00L, 0)); assertTrue(anyAreSet(0xFF00FF00FF00FF00L, 0xFF00FF00FF00FF00L)); assertTrue(anyAreSet(0xFF00FF00FF00FF00L, 0x3A00E3004D002200L)); assertTrue(anyAreSet(0xFF00FF00FF00FF00L, 0xFFFFFFFFFFFFFFFFL)); assertTrue(anyAreSet(0xFF00FF00FF00FF00L, 0x0000010000000000L)); assertTrue(anyAreSet(0xFF00FF00FF00FF00L, 0x8000000000000000L)); } public void testAllAreSetInt() { assertTrue(allAreSet(0xFF00FF00, 0xFF00FF00)); assertTrue(allAreSet(0xFF00FF00, 0x12003400)); assertTrue(allAreSet(0xFF00FF00, 0)); assertFalse(allAreSet(0xFF00FF00, 0x00FF00FF)); assertFalse(allAreSet(0xFF00FF00, 0x00800000)); assertFalse(allAreSet(0xFF00FF00, 0x00000001)); assertFalse(allAreSet(0xFF00FF00, 0x00FF0000)); } public void testAllAreSetLong() { assertTrue(allAreSet(0xFF00FF00FF00FF00L, 0xFF00FF00FF00FF00L)); assertTrue(allAreSet(0xFF00FF00FF00FF00L, 0x1200340056007800L)); assertTrue(allAreSet(0xFF00FF00FF00FF00L, 0L)); assertFalse(allAreSet(0xFF00FF00FF00FF00L, 0x00FF00FF00FF00FFL)); assertFalse(allAreSet(0xFF00FF00FF00FF00L, 0x0080000000000000L)); assertFalse(allAreSet(0xFF00FF00FF00FF00L, 0x0000000000000001L)); assertFalse(allAreSet(0xFF00FF00FF00FF00L, 0x00FF000000000000L)); } // anyAreClear is the inverse of allAreSet, so each test should be duplicated in both sections public void testAnyAreClearInt() { assertFalse(anyAreClear(0xFF00FF00, 0xFF00FF00)); assertFalse(anyAreClear(0xFF00FF00, 0x12003400)); assertFalse(anyAreClear(0xFF00FF00, 0)); assertTrue(anyAreClear(0xFF00FF00, 0x00FF00FF)); assertTrue(anyAreClear(0xFF00FF00, 0x00800000)); assertTrue(anyAreClear(0xFF00FF00, 0x00000001)); assertTrue(anyAreClear(0xFF00FF00, 0x00FF0000)); } public void testAnyAreClearLong() { assertFalse(anyAreClear(0xFF00FF00FF00FF00L, 0xFF00FF00FF00FF00L)); assertFalse(anyAreClear(0xFF00FF00FF00FF00L, 0x1200340056007800L)); assertFalse(anyAreClear(0xFF00FF00FF00FF00L, 0L)); assertTrue(anyAreClear(0xFF00FF00FF00FF00L, 0x00FF00FF00FF00FFL)); assertTrue(anyAreClear(0xFF00FF00FF00FF00L, 0x0080000000000000L)); assertTrue(anyAreClear(0xFF00FF00FF00FF00L, 0x0000000000000001L)); assertTrue(anyAreClear(0xFF00FF00FF00FF00L, 0x00FF000000000000L)); } // unsigned methods public void testUnsignedByte() { assertEquals(0x5, unsigned((byte) 0x5)); assertEquals(0xfb, unsigned((byte) -0x5)); assertEquals(0x5, unsigned((byte) -0xfb)); assertEquals(0xff, unsigned((byte) -0x1)); assertEquals(0x1, unsigned((byte) -0xff)); } public void testUnsginedShort() { assertEquals(0xf875, unsigned((short) -0x78b)); assertEquals(0x78b, unsigned((short) -0xf875)); assertEquals(0xffff, unsigned((short) -0x1)); assertEquals(0x1, unsigned((short) -0xffff)); } public void testUnsignedInt() { assertEquals(0xffffffffl, unsigned((int) 0xffffffff)); assertEquals(0xffffffffl, unsigned((int) -1)); assertEquals(0x1l, unsigned((int) -0xffffffff)); assertEquals(0xfffff544l, unsigned((int) -0xabc)); assertEquals(0xabc, unsigned((int) -0xfffff544)); assertEquals(0xfffff541l, unsigned((int) -0xabf)); assertEquals(0xabf, unsigned((int) -0xfffff541)); } // byte array methods public void testByteArrayRead() { final byte[] bytes = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16 }; assertEquals(0x01020304, intFromBytesBE(bytes, 0)); assertEquals(0x04030201, intFromBytesLE(bytes, 0)); assertEquals(0x03040506, intFromBytesBE(bytes, 2)); assertEquals(0x06050403, intFromBytesLE(bytes, 2)); assertEquals(0x0203, shortFromBytesBE(bytes, 1)); assertEquals(0x0302, shortFromBytesLE(bytes, 1)); assertEquals((char) 0x0203, charFromBytesBE(bytes, 1)); assertEquals((char) 0x0302, charFromBytesLE(bytes, 1)); assertEquals(0x00030405, mediumFromBytesBE(bytes, 2)); assertEquals(0x00050403, mediumFromBytesLE(bytes, 2)); assertEquals(0x060708090a0b0c0dL, longFromBytesBE(bytes, 5)); assertEquals(0x0d0c0b0a09080706L, longFromBytesLE(bytes, 5)); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/BuffersTestCase.java000066400000000000000000004222541257016060700244400ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertArrayEquals; import static org.xnio.AssertReadWrite.assertReadMessage; import java.io.IOException; import java.nio.Buffer; import java.nio.BufferUnderflowException; import java.nio.ByteBuffer; import java.nio.CharBuffer; import java.nio.IntBuffer; import java.nio.InvalidMarkException; import java.nio.LongBuffer; import java.nio.ReadOnlyBufferException; import java.nio.ShortBuffer; import java.nio.charset.Charset; import java.util.Arrays; import java.util.Random; import junit.framework.TestCase; import org.xnio.BufferAllocator; import org.xnio.Buffers; import org.xnio.ByteBufferSlicePool; import org.xnio.Pool; import org.xnio.Pooled; /** * Test for {@link Buffers}. * * @author David M. Lloyd * @author Flavia Rainone */ public final class BuffersTestCase extends TestCase { private void doTestFlip(Buffer buffer) { final int pos = buffer.position(); final int cap = buffer.capacity(); assertEquals(cap, buffer.limit()); assertSame(buffer, Buffers.flip(buffer)); assertEquals(0, buffer.position()); assertEquals(pos, buffer.limit()); assertEquals(cap, buffer.capacity()); } public void testFlipByte() { ByteBuffer buf = ByteBuffer.allocate(100); final byte[] data = {5, 4, 3, 2, 1, 0}; final byte[] data2 = new byte[data.length]; buf.put(data); doTestFlip(buf); buf.get(data2); assertTrue(Arrays.equals(data, data2)); assertFalse(buf.hasRemaining()); } public void testFlipChar() { CharBuffer buf = CharBuffer.allocate(100); final char[] data = {5, 4, 3, 2, 1, 0}; final char[] data2 = new char[data.length]; buf.put(data); doTestFlip(buf); buf.get(data2); assertTrue(Arrays.equals(data, data2)); assertFalse(buf.hasRemaining()); } private void doTestClear(Buffer buffer) { assertFalse(buffer.position() == 0); final int cap = buffer.capacity(); assertFalse(buffer.limit() == cap); assertSame(buffer, Buffers.clear(buffer)); assertEquals(0, buffer.position()); assertEquals(cap, buffer.limit()); assertEquals(cap, buffer.capacity()); } public void testClearByte() { final int sz = 100; ByteBuffer buf = ByteBuffer.allocate(sz); final byte[] data = {5, 4, 3, 2, 1, 0}; buf.put(data); buf.put(data); buf.put(data); buf.flip(); buf.get(); buf.get(); doTestClear(buf); } public void testClearChar() { final int sz = 100; CharBuffer buf = CharBuffer.allocate(sz); final char[] data = {5, 4, 3, 2, 1, 0}; buf.put(data); buf.put(data); buf.put(data); buf.flip(); buf.get(); buf.get(); doTestClear(buf); } private void doTestLimit(Buffer buffer) { assertFalse(buffer.limit() == 50); assertSame(buffer, Buffers.limit(buffer, 50)); assertEquals(50, buffer.limit()); } public void testLimitByte() { final int sz = 100; ByteBuffer buf = ByteBuffer.allocate(sz); final byte[] data = {5, 4, 3, 2, 1, 0}; buf.put(data); buf.put(data); buf.put(data); buf.flip(); buf.get(); buf.get(); doTestLimit(buf); } public void testLimitChar() { final int sz = 100; CharBuffer buf = CharBuffer.allocate(sz); final char[] data = {5, 4, 3, 2, 1, 0}; buf.put(data); buf.put(data); buf.put(data); buf.flip(); buf.get(); buf.get(); doTestLimit(buf); } private void doTestMarkReset(Buffer buffer) { final int p = buffer.position(); assertSame(buffer, Buffers.mark(buffer)); assertSame(buffer, Buffers.skip(buffer, 10)); assertFalse(buffer.position() == p); assertSame(buffer, Buffers.reset(buffer)); assertTrue(buffer.position() == p); assertSame(buffer, Buffers.skip(buffer, 10)); assertFalse(buffer.position() == p); assertSame(buffer, Buffers.reset(buffer)); assertTrue(buffer.position() == p); } public void testMarkResetByte() { final int sz = 100; ByteBuffer buf = ByteBuffer.allocate(sz); final byte[] data = {5, 4, 3, 2, 1, 0}; buf.put(data); buf.put(data); buf.put(data); buf.flip(); buf.get(); buf.get(); doTestMarkReset(buf); } public void testMarkResetChar() { final int sz = 100; CharBuffer buf = CharBuffer.allocate(sz); final char[] data = {5, 4, 3, 2, 1, 0}; buf.put(data); buf.put(data); buf.put(data); buf.flip(); buf.get(); buf.get(); doTestMarkReset(buf); } private void doTestPosition(Buffer buffer) { assertSame(buffer, Buffers.position(buffer, 25)); assertEquals(25, buffer.position()); assertSame(buffer, Buffers.position(buffer, 0)); assertEquals(0, buffer.position()); assertSame(buffer, Buffers.position(buffer, 100)); assertEquals(100, buffer.position()); } public void testPositionByte() { doTestPosition(ByteBuffer.allocate(200)); } public void testPositionChar() { doTestPosition(CharBuffer.allocate(200)); } private void doTestRewind(Buffer buffer) { assertSame(buffer, Buffers.position(buffer, 45)); assertEquals(45, buffer.position()); assertSame(buffer, Buffers.rewind(buffer)); assertEquals(0, buffer.position()); } public void testRewindByte() { doTestRewind(ByteBuffer.allocate(200)); } public void testRewindChar() { doTestRewind(CharBuffer.allocate(200)); } public void tetsFlipClearLimitMarkPositionResetAndRewind() { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.position(5); Buffers.flip(buffer); assertEquals(0, buffer.position()); assertEquals(5, buffer.limit()); Buffers.clear(buffer); assertEquals(0, buffer.position()); assertEquals(buffer.capacity(), buffer.limit()); assertEquals(10, buffer.limit()); Buffers.limit(buffer, 7); assertEquals(7, buffer.limit()); buffer.limit(10); buffer.position(4); Buffers.mark(buffer); buffer.position(7);; Buffers.reset(buffer); assertEquals(4, buffer.position()); Buffers.mark(buffer); Buffers.rewind(buffer); assertEquals(0, buffer.position()); InvalidMarkException expected = null; try { buffer.reset(); } catch (InvalidMarkException e) { expected = e; } assertNotNull(expected); } public void testPositiveSliceByte() { final ByteBuffer buf = ByteBuffer.allocate(200); final byte[] data = {5, 10, 15, 20, 0, 5, 10, 15}; buf.put(data).put(data).put(data).put(data).put(data).put(data).put(data); buf.flip(); final int lim = buf.limit(); final int cap = buf.capacity(); final int sz = 7; final ByteBuffer slice1 = Buffers.slice(buf, sz); assertEquals(0, slice1.position()); assertEquals(sz, slice1.capacity()); assertEquals(sz, slice1.limit()); assertEquals(sz, buf.position()); assertEquals(lim, buf.limit()); assertEquals(cap, buf.capacity()); final ByteBuffer slice2 = Buffers.slice(buf, sz * 2); assertEquals(0, slice2.position()); assertEquals(sz * 2, slice2.capacity()); assertEquals(sz * 2, slice2.limit()); assertEquals(sz * 3, buf.position()); } public void testPositiveSliceChar() { final CharBuffer buf = CharBuffer.allocate(200); final char[] data = {5, 10, 15, 20, 0, 5, 10, 15}; buf.put(data).put(data).put(data).put(data).put(data).put(data).put(data); buf.flip(); final int lim = buf.limit(); final int cap = buf.capacity(); final int sz = 7; final CharBuffer slice1 = Buffers.slice(buf, sz); assertEquals(0, slice1.position()); assertEquals(sz, slice1.capacity()); assertEquals(sz, slice1.limit()); assertEquals(sz, buf.position()); assertEquals(lim, buf.limit()); assertEquals(cap, buf.capacity()); final CharBuffer slice2 = Buffers.slice(buf, sz * 2); assertEquals(0, slice2.position()); assertEquals(sz * 2, slice2.capacity()); assertEquals(sz * 2, slice2.limit()); assertEquals(sz * 3, buf.position()); } public void testNegativeSliceByte() { final ByteBuffer buf = ByteBuffer.allocate(200); final byte[] data = {5, 10, 15, 20, 0, 5, 10, 15}; buf.put(data).put(data).put(data).put(data).put(data).put(data).put(data); buf.flip(); final int lim = buf.limit(); final int cap = buf.capacity(); final int sz = 7; final ByteBuffer slice1 = Buffers.slice(buf, sz - lim); assertEquals(0, slice1.position()); assertEquals(sz, slice1.capacity()); assertEquals(sz, slice1.limit()); assertEquals(sz, buf.position()); assertEquals(lim, buf.limit()); assertEquals(cap, buf.capacity()); final ByteBuffer slice2 = Buffers.slice(buf, sz * 2 - lim + sz); assertEquals(0, slice2.position()); assertEquals(sz * 2, slice2.capacity()); assertEquals(sz * 2, slice2.limit()); assertEquals(sz * 3, buf.position()); } public void testNegativeSliceChar() { final CharBuffer buf = CharBuffer.allocate(200); final char[] data = {5, 10, 15, 20, 0, 5, 10, 15}; buf.put(data).put(data).put(data).put(data).put(data).put(data).put(data); buf.flip(); final int lim = buf.limit(); final int cap = buf.capacity(); final int sz = 7; final CharBuffer slice1 = Buffers.slice(buf, sz - lim); assertEquals(0, slice1.position()); assertEquals(sz, slice1.capacity()); assertEquals(sz, slice1.limit()); assertEquals(sz, buf.position()); assertEquals(lim, buf.limit()); assertEquals(cap, buf.capacity()); final CharBuffer slice2 = Buffers.slice(buf, sz * 2 - lim + sz); assertEquals(0, slice2.position()); assertEquals(sz * 2, slice2.capacity()); assertEquals(sz * 2, slice2.limit()); assertEquals(sz * 3, buf.position()); } public void testMultipleByeSlices() { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("abcdefghij".getBytes()).flip(); final ByteBuffer slice1 = Buffers.slice(buffer, 3); assertEquals(3, slice1.limit()); assertEquals('a', slice1.get()); assertEquals('b', slice1.get()); assertEquals('c', slice1.get()); BufferUnderflowException expected = null; try { slice1.get(); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); assertEquals(3, buffer.position()); final ByteBuffer slice2 = Buffers.slice(buffer, 1); assertEquals('d', slice2.get()); expected = null; try { slice2.get(); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); assertEquals(4, buffer.position()); final ByteBuffer slice3 = Buffers.slice(buffer, -2); assertEquals(8, buffer.position()); assertEquals(10, buffer.limit()); assertEquals('e', slice3.get()); assertEquals('f', slice3.get()); assertEquals('g', slice3.get()); assertEquals('h', slice3.get()); final ByteBuffer slice4 = Buffers.slice(buffer, 2); assertEquals(2, slice4.limit()); assertEquals('i', slice4.get()); assertEquals('j', slice4.get()); expected = null; try { slice3.get(); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); assertEquals(10, buffer.position()); // invalid slice expected = null; try { Buffers.slice(buffer, 1); } catch(BufferUnderflowException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.slice(buffer, -1); } catch(BufferUnderflowException e) { expected = e; } assertNotNull(expected); // check slice properties buffer.put(1, (byte) 'z'); assertEquals('z', slice1.get(1)); slice2.put(0, (byte) 'y'); assertEquals('y', buffer.get(3)); buffer.put(5, (byte) 'x'); assertEquals('x', slice3.get(1)); slice4.put(0, (byte) 'w'); assertEquals('w', buffer.get(8)); } public void testMultipleCharSlices() { final CharBuffer buffer = CharBuffer.allocate(10); buffer.put(new char[] {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}).flip(); final CharBuffer slice1 = Buffers.slice(buffer, 3); assertEquals(3, slice1.limit()); assertEquals('a', slice1.get()); assertEquals('b', slice1.get()); assertEquals('c', slice1.get()); BufferUnderflowException expected = null; try { slice1.get(); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); assertEquals(3, buffer.position()); final CharBuffer slice2 = Buffers.slice(buffer, 1); assertEquals('d', slice2.get()); expected = null; try { slice2.get(); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); assertEquals(4, buffer.position()); final CharBuffer slice3 = Buffers.slice(buffer, -2); assertEquals(8, buffer.position()); assertEquals(10, buffer.limit()); assertEquals('e', slice3.get()); assertEquals('f', slice3.get()); assertEquals('g', slice3.get()); assertEquals('h', slice3.get()); final CharBuffer slice4 = Buffers.slice(buffer, 2); assertEquals(2, slice4.limit()); assertEquals('i', slice4.get()); assertEquals('j', slice4.get()); expected = null; try { slice3.get(); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); assertEquals(10, buffer.position()); // invalid slice expected = null; try { Buffers.slice(buffer, 1); } catch(BufferUnderflowException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.slice(buffer, -1); } catch(BufferUnderflowException e) { expected = e; } assertNotNull(expected); // check slice properties slice1.put(0, 'k'); assertEquals('k', buffer.get(0)); buffer.put(3, 'l'); assertEquals('l', slice2.get(0)); slice3.put(3, 'm'); assertEquals('m', buffer.get(7)); buffer.put(8, 'n'); assertEquals('n', slice4.get(0)); } public void testMultipleShortSlices() { final ShortBuffer buffer = ShortBuffer.allocate(10); buffer.put(new short[] {1, 2, 3, 4, 5, 6, 7, 8, 9}).flip(); final ShortBuffer slice1 = Buffers.slice(buffer, 2); assertEquals(2, slice1.limit()); assertEquals(1, slice1.get()); assertEquals(2, slice1.get()); BufferUnderflowException expected = null; try { slice1.get(); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); assertEquals(2, buffer.position()); final ShortBuffer slice2 = Buffers.slice(buffer, 1); assertEquals(3, slice2.get()); expected = null; try { slice2.get(); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); assertEquals(3, buffer.position()); final ShortBuffer slice3 = Buffers.slice(buffer, -3); assertEquals(6, buffer.position()); assertEquals(9, buffer.limit()); assertEquals(3, slice3.limit()); assertEquals(4, slice3.get()); assertEquals(5, slice3.get()); assertEquals(6, slice3.get()); final ShortBuffer slice4 = Buffers.slice(buffer, 3); assertEquals(3, slice4.limit()); assertEquals(9, buffer.position()); assertEquals(7, slice4.get()); assertEquals(8, slice4.get()); assertEquals(9, slice4.get()); expected = null; try { slice3.get(); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); assertEquals(9, buffer.position()); // invalid slice expected = null; try { Buffers.slice(buffer, 1); } catch(BufferUnderflowException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.slice(buffer, -1); } catch(BufferUnderflowException e) { expected = e; } assertNotNull(expected); // check slice properties buffer.put(1, (short) 10); assertEquals(10, slice1.get(1)); slice2.put(0, (short) 11); assertEquals(11, buffer.get(2)); buffer.put(3, (short) 12); assertEquals(12, slice3.get(0)); slice4.put(2, (short) 13); assertEquals(13, buffer.get(8)); } public void testMultipleIntSlices() { final IntBuffer buffer = IntBuffer.allocate(15); buffer.put(new int[]{2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37}).flip(); buffer.position(1); final IntBuffer slice1 = Buffers.slice(buffer, 3); assertEquals(3, slice1.limit()); assertEquals(3, slice1.get()); assertEquals(5, slice1.get()); assertEquals(7, slice1.get()); BufferUnderflowException expected = null; try { slice1.get(); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.slice(buffer, 31); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); assertEquals(4, buffer.position()); final IntBuffer slice2 = Buffers.slice(buffer, 5); assertEquals(5, slice2.limit()); assertEquals(11, slice2.get()); assertEquals(13, slice2.get()); assertEquals(17, slice2.get()); assertEquals(19, slice2.get()); assertEquals(23, slice2.get()); expected = null; try { Buffers.slice(buffer, -7); } catch (BufferUnderflowException e) { expected = e; } assertEquals(9, buffer.position()); buffer.get(); final IntBuffer slice3 = Buffers.slice(buffer, -2); expected = null; try { slice3.get(); } catch (BufferUnderflowException e) { expected = e; } final IntBuffer slice4 = Buffers.slice(buffer, 2); assertEquals(2, slice4.limit()); assertEquals(31, slice4.get()); assertEquals(37, slice4.get()); assertEquals(12, buffer.position()); // check slice properties slice1.put(0, 41); assertEquals(41, buffer.get(1)); buffer.put(4, 43); assertEquals(43, slice2.get(0)); slice4.put(1, 47); assertEquals(47, buffer.get(11)); } public void testMultipleLongSlices() { final LongBuffer buffer = LongBuffer.allocate(15); buffer.put(new long[]{1, 4, 9, 16, 25, 36, 49, 64, 81, 100, 121}).flip(); buffer.position(1); final LongBuffer slice1 = Buffers.slice(buffer, 3); assertEquals(3, slice1.limit()); assertEquals(4, slice1.get()); assertEquals(9, slice1.get()); assertEquals(16, slice1.get()); BufferUnderflowException expected = null; try { slice1.get(); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.slice(buffer, 144); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); assertEquals(4, buffer.position()); final LongBuffer slice2 = Buffers.slice(buffer, 5); assertEquals(5, slice2.limit()); assertEquals(25, slice2.get()); assertEquals(36, slice2.get()); assertEquals(49, slice2.get()); assertEquals(64, slice2.get()); assertEquals(81, slice2.get()); expected = null; try { Buffers.slice(buffer, -169); } catch (BufferUnderflowException e) { expected = e; } assertEquals(9, buffer.position()); buffer.get(); final LongBuffer slice3 = Buffers.slice(buffer, -1); assertEquals(0, slice3.limit()); final LongBuffer slice4 = Buffers.slice(buffer, 1); assertEquals(1, slice4.limit()); assertEquals(121, slice4.get()); // check slice properties buffer.put(1, 144); assertEquals(144, slice1.get(0)); slice2.put(0, 169); assertEquals(169, buffer.get(4)); buffer.put(10, 196); assertEquals(196, slice4.get(0)); } private void assertBufferContent(ByteBuffer buffer, String content) { assertReadMessage(buffer, content); } public void testCopyFullBuffer() { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("1234567890".getBytes()).flip(); final ByteBuffer copy1 = Buffers.copy(buffer, 10, BufferAllocator.BYTE_BUFFER_ALLOCATOR); assertEquals(buffer.limit(), buffer.position()); assertEquals(copy1.limit(), copy1.position()); assertArrayEquals(buffer.array(), copy1.array()); buffer.position(0); final ByteBuffer copy2 = ByteBuffer.allocate(10); assertEquals(10, Buffers.copy(copy2, buffer)); assertEquals(buffer.limit(), buffer.position()); assertEquals(copy2.limit(), copy2.position()); assertArrayEquals(buffer.array(), copy2.array()); buffer.position(0); final ByteBuffer[] copy3 = new ByteBuffer[] {ByteBuffer.allocate(5), ByteBuffer.allocate(5)}; assertEquals(10 , Buffers.copy(copy3, 0, 2, buffer)); assertEquals(buffer.limit(), buffer.position()); assertEquals(copy3[0].limit(), copy3[0].position()); assertEquals(copy3[1].limit(), copy3[1].position()); assertBufferContent(copy3[0], "12345"); assertBufferContent(copy3[1], "67890"); buffer.position(0); final ByteBuffer copy4 = ByteBuffer.allocate(10); assertEquals(10, Buffers.copy(10, copy4, buffer)); assertEquals(buffer.limit(), buffer.position()); assertEquals(copy4.limit(), copy4.position()); assertArrayEquals(buffer.array(), copy4.array()); buffer.position(0); final ByteBuffer[] copy5 = new ByteBuffer[] {ByteBuffer.allocate(5), ByteBuffer.allocate(5), ByteBuffer.allocate(5)}; assertEquals(10, Buffers.copy(10, copy5, 1, 2, buffer)); assertEquals(buffer.limit(), buffer.position()); assertEquals(copy5[1].limit(), copy5[1].position()); assertEquals(copy5[2].limit(), copy5[2].position()); assertBufferContent(copy5[1], "12345"); assertBufferContent(copy5[2], "67890"); buffer.position(0); final ByteBuffer[] copy6 = new ByteBuffer[] {ByteBuffer.allocate(5), ByteBuffer.allocate(5), ByteBuffer.allocate(5)}; assertEquals(10, Buffers.copy(30, copy6, 0, 3, buffer)); assertEquals(buffer.limit(), buffer.position()); assertEquals(copy6[0].limit(), copy6[0].position()); assertEquals(copy6[1].limit(), copy6[1].position()); assertBufferContent(copy6[0], "12345"); assertBufferContent(copy6[1], "67890"); //check copy properties buffer.position(0); buffer.put((byte) '0'); buffer.put((byte) '9'); assertEquals('1', copy1.get(0)); assertEquals('2', copy1.get(1)); assertEquals('1', copy2.get(0)); assertEquals('2', copy2.get(1)); assertEquals('1', copy3[0].get(0)); assertEquals('2', copy3[0].get(1)); assertEquals('1', copy4.get(0)); assertEquals('2', copy4.get(1)); assertEquals('1', copy5[1].get(0)); assertEquals('2', copy5[1].get(1)); assertEquals('1', copy6[0].get(0)); assertEquals('2', copy6[0].get(1)); copy1.put(2, (byte) '8'); copy2.put(3, (byte) '7'); copy3[0].put(4, (byte) '6'); copy4.put(5, (byte)'5'); copy5[2].put(1, (byte)'4'); copy6[1].put(2, (byte) '3'); assertEquals('3', buffer.get(2)); assertEquals('4', buffer.get(3)); assertEquals('5', buffer.get(4)); assertEquals('6', buffer.get(5)); assertEquals('7', buffer.get(6)); assertEquals('8', buffer.get(7)); } public void testCopyPartialBuffer() { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("1234567890".getBytes()).flip(); final ByteBuffer copy1 = Buffers.copy(buffer, 5, BufferAllocator.BYTE_BUFFER_ALLOCATOR); assertEquals(5, buffer.position()); assertEquals(copy1.limit(), copy1.position()); assertBufferContent(copy1, "12345"); buffer.position(0); final ByteBuffer copy2 = ByteBuffer.allocate(7); assertEquals(7, Buffers.copy(copy2, buffer)); assertEquals(7, buffer.position()); assertEquals(copy2.limit(), copy2.position()); assertBufferContent(copy2, "1234567"); buffer.position(0); final ByteBuffer[] copy3 = new ByteBuffer[] {ByteBuffer.allocate(2), ByteBuffer.allocate(2)}; assertEquals(4, Buffers.copy(copy3, 0, 2, buffer)); assertEquals(4, buffer.position()); assertEquals(copy3[0].limit(), copy3[0].position()); assertEquals(copy3[1].limit(), copy3[1].position()); assertBufferContent(copy3[0], "12"); assertBufferContent(copy3[1], "34"); buffer.position(0); final ByteBuffer copy4 = ByteBuffer.allocate(10); assertEquals(1, Buffers.copy(1, copy4, buffer)); assertEquals(1, buffer.position()); assertEquals(1, copy4.position()); assertEquals('1', copy4.get(0)); buffer.position(0); final ByteBuffer[] copy5 = new ByteBuffer[] {ByteBuffer.allocate(3), ByteBuffer.allocate(4), ByteBuffer.allocate(6)}; assertEquals(9, Buffers.copy(9, copy5, 1, 2, buffer)); assertEquals(9, buffer.position()); assertEquals(copy5[1].limit(), copy5[1].position()); assertEquals(5, copy5[2].position()); assertBufferContent(copy5[1], "1234"); assertBufferContent(copy5[2], "56789"); //check copy properties buffer.position(0); buffer.put((byte) '0'); buffer.put((byte) '9'); assertEquals('1', copy1.get(0)); assertEquals('2', copy1.get(1)); assertEquals('1', copy2.get(0)); assertEquals('2', copy2.get(1)); assertEquals('1', copy3[0].get(0)); assertEquals('2', copy3[0].get(1)); assertEquals('1', copy4.get(0)); assertEquals('1', copy5[1].get(0)); assertEquals('2', copy5[1].get(1)); copy1.put(2, (byte) '8'); copy2.put(3, (byte) '7'); copy3[1].put(1, (byte) '6'); copy4.put(5, (byte)'5'); copy5[2].put(1, (byte)'4'); assertEquals('3', buffer.get(2)); assertEquals('4', buffer.get(3)); assertEquals('5', buffer.get(4)); assertEquals('6', buffer.get(5)); assertEquals('7', buffer.get(6)); } public void testCopyToSmallerBuffer() { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("1234567890".getBytes()).flip(); final ByteBuffer copy1 = ByteBuffer.allocate(7); assertEquals(7, Buffers.copy(copy1, buffer)); assertEquals(7, buffer.position()); assertEquals(copy1.limit(), copy1.position()); assertBufferContent(copy1, "1234567"); buffer.position(0); final ByteBuffer[] copy2 = new ByteBuffer[] {ByteBuffer.allocate(2)}; assertEquals(2, Buffers.copy(copy2, 0, 1, buffer)); assertEquals(2, buffer.position()); assertEquals(copy2[0].limit(), copy2[0].position()); assertBufferContent(copy2[0], "12"); buffer.position(0); final ByteBuffer copy3 = ByteBuffer.allocate(1); assertEquals(1, Buffers.copy(10, copy3, buffer)); assertEquals(1, buffer.position()); assertEquals(1, copy3.position()); assertEquals('1', copy3.get(0)); buffer.position(0); final ByteBuffer[] copy4 = new ByteBuffer[] {ByteBuffer.allocate(3), ByteBuffer.allocate(5)}; assertEquals(3, Buffers.copy(15, copy4, 0, 1, buffer)); assertEquals(3, buffer.position()); assertEquals(copy4[0].limit(), copy4[0].position()); assertBufferContent(copy4[0], "123"); //check copy properties buffer.position(0); buffer.put((byte) '0'); buffer.put((byte) '9'); assertEquals('1', copy1.get(0)); assertEquals('2', copy1.get(1)); assertEquals('1', copy2[0].get(0)); assertEquals('2', copy2[0].get(1)); assertEquals('1', copy3.get(0)); assertEquals('1', copy4[0].get(0)); assertEquals('2', copy4[0].get(1)); copy1.put(2, (byte) '8'); copy1.put(3, (byte) '7'); copy2[0].put(0, (byte) '6'); copy3.put(0, (byte)'5'); copy4[1].put(2, (byte)'4'); assertEquals('0', buffer.get(0)); assertEquals('9', buffer.get(1)); assertEquals('3', buffer.get(2)); assertEquals('4', buffer.get(3)); assertEquals('5', buffer.get(4)); assertEquals('6', buffer.get(5)); assertEquals('7', buffer.get(6)); } public void testBufferUnderflowExceptionThrownByCopy() { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("1234567890".getBytes()).flip(); buffer.position(2); BufferUnderflowException expected = null; try { Buffers.copy(buffer, 20, BufferAllocator.DIRECT_BYTE_BUFFER_ALLOCATOR); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.copy(buffer, 9, BufferAllocator.DIRECT_BYTE_BUFFER_ALLOCATOR); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.copy(buffer, -15, BufferAllocator.DIRECT_BYTE_BUFFER_ALLOCATOR); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.copy(buffer, -9, BufferAllocator.DIRECT_BYTE_BUFFER_ALLOCATOR); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); } // FIXME XNIO-120 public void testCopyWithNegativeSliceSize() { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("1234567890".getBytes()).flip(); final ByteBuffer copy1 = Buffers.copy(buffer, -2, BufferAllocator.DIRECT_BYTE_BUFFER_ALLOCATOR); assertEquals(8, buffer.position()); assertEquals(2, copy1.limit()); assertEquals(2, copy1.position()); assertBufferContent(copy1, "90"); buffer.position(0); final ByteBuffer copy2 = ByteBuffer.allocate(6); assertEquals(6, Buffers.copy(-4, copy2, buffer)); assertEquals(6, buffer.position()); assertEquals(6, copy2.limit()); assertEquals(6, copy2.position()); assertBufferContent(copy2, "123456"); final ByteBuffer copy3 = ByteBuffer.allocate(10); assertEquals(0, Buffers.copy(-4, copy3, buffer)); assertEquals(0, Buffers.copy(-40, copy3, buffer)); buffer.position(0); final ByteBuffer[] copy4 = new ByteBuffer[] {ByteBuffer.allocate(3), ByteBuffer.allocate(2)}; UnsupportedOperationException expected = null; try { assertEquals(5, Buffers.copy(-2, copy4, 0, 2, buffer)); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); // XNIO-120 these test assertions are wrong, negative count must work just like negative slice size // assertEquals(5, buffer.position()); // assertEquals(copy4[0].limit(), copy4[0].position()); // assertEquals(copy4[1].limit(), copy4[1].position()); // assertBufferContent(copy4[0], "123"); // assertBufferContent(copy4[1], "45"); buffer.position(0); final ByteBuffer[] copy5 = new ByteBuffer[] {ByteBuffer.allocate(3), ByteBuffer.allocate(2)}; expected = null; try { assertEquals(4, Buffers.copy(-6, copy5, 0, 2, buffer)); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); // XNIO-120 these test assertions are wrong, negative count must work just like negative slice size // assertEquals(4, buffer.position()); // assertEquals(copy5[0].limit(), copy5[0].position()); // assertEquals(1, copy5[1].position()); // assertBufferContent(copy5[0], "123"); // assertBufferContent(copy5[1], "4"); final ByteBuffer[] copy6 = new ByteBuffer[] {ByteBuffer.allocate(5), ByteBuffer.allocate(5)}; expected = null; try { assertEquals(0, Buffers.copy(-6, copy6, 0, 2, buffer)); } catch (UnsupportedOperationException e) { expected = e; } expected = null; try { assertEquals(0, Buffers.copy(-10, copy6, 0, 2, buffer)); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); } public void testCopyMultipleBuffers() { final ByteBuffer[] buffer = new ByteBuffer[]{ByteBuffer.allocate(2), ByteBuffer.allocate(2), ByteBuffer.allocate(2), ByteBuffer.allocate(2), ByteBuffer.allocate(2)}; buffer[0].put("12".getBytes()).flip(); buffer[1].put("34".getBytes()).flip(); buffer[2].put("56".getBytes()).flip(); buffer[3].put("78".getBytes()).flip(); buffer[4].put("90".getBytes()).flip(); final ByteBuffer copy1 = ByteBuffer.allocate(10); assertEquals(10, Buffers.copy(copy1, buffer, 0, 5)); for (int i = 0; i < 5; i++) { assertEquals(buffer[i].limit(), buffer[i].position()); buffer[i].position(0); } assertEquals(copy1.limit(), copy1.position()); assertBufferContent(copy1, "1234567890"); final ByteBuffer[] copy2 = new ByteBuffer[] {ByteBuffer.allocate(5), ByteBuffer.allocate(5)}; assertEquals(10 , Buffers.copy(copy2, 0, 2, buffer, 0, 5)); for (int i = 0; i < 5; i++) { assertEquals(buffer[i].limit(), buffer[i].position()); buffer[i].position(0); } assertEquals(copy2[0].limit(), copy2[0].position()); assertEquals(copy2[1].limit(), copy2[1].position()); assertBufferContent(copy2[0], "12345"); assertBufferContent(copy2[1], "67890"); final ByteBuffer copy3 = ByteBuffer.allocate(10); assertEquals(10, Buffers.copy(10, copy3, buffer, 0, 5)); for (int i = 0; i < 5; i++) { assertEquals(buffer[i].limit(), buffer[i].position()); buffer[i].position(0); } assertEquals(copy3.limit(), copy3.position()); assertBufferContent(copy3, "1234567890"); final ByteBuffer copy4 = ByteBuffer.allocate(50); assertEquals(10, Buffers.copy(40, copy4, buffer, 0, 5)); for (int i = 0; i < 5; i++) { assertEquals(buffer[i].limit(), buffer[i].position()); buffer[i].position(0); } assertEquals(10, copy4.position()); assertBufferContent(copy4, "1234567890"); final ByteBuffer[] copy5 = new ByteBuffer[] {ByteBuffer.allocate(5), ByteBuffer.allocate(5), ByteBuffer.allocate(5)}; assertEquals(10, Buffers.copy(10, copy5, 1, 2, buffer, 0, 5)); for (int i = 0; i < 5; i++) { assertEquals(buffer[i].limit(), buffer[i].position()); buffer[i].position(0); } assertEquals(copy5[1].limit(), copy5[1].position()); assertEquals(copy5[2].limit(), copy5[2].position()); assertBufferContent(copy5[1], "12345"); assertBufferContent(copy5[2], "67890"); final ByteBuffer[] copy6 = new ByteBuffer[] {ByteBuffer.allocate(5), ByteBuffer.allocate(5), ByteBuffer.allocate(5)}; assertEquals(10, Buffers.copy(30, copy6, 0, 3, buffer, 0, 5)); for (int i = 0; i < 5; i++) { assertEquals(buffer[i].limit(), buffer[i].position()); buffer[i].position(0); } assertEquals(copy6[0].limit(), copy6[0].position()); assertEquals(copy6[1].limit(), copy6[1].position()); assertBufferContent(copy6[0], "12345"); assertBufferContent(copy6[1], "67890"); //check copy properties buffer[0].put((byte) '0'); buffer[0].put((byte) '9'); assertEquals('1', copy1.get(0)); assertEquals('2', copy1.get(1)); assertEquals('1', copy2[0].get(0)); assertEquals('2', copy2[0].get(1)); assertEquals('1', copy3.get(0)); assertEquals('2', copy3.get(1)); assertEquals('1', copy4.get(0)); assertEquals('2', copy4.get(1)); assertEquals('1', copy5[1].get(0)); assertEquals('2', copy5[1].get(1)); assertEquals('1', copy6[0].get(0)); assertEquals('2', copy6[0].get(1)); copy1.put(2, (byte) '8'); copy2[0].put(3, (byte) '7'); copy3.put(4, (byte) '6'); copy4.put(5, (byte)'5'); copy5[2].put(1, (byte)'4'); copy6[1].put(2, (byte) '3'); assertEquals('3', buffer[1].get(0)); assertEquals('4', buffer[1].get(1)); assertEquals('5', buffer[2].get(0)); assertEquals('6', buffer[2].get(1)); assertEquals('7', buffer[3].get(0)); assertEquals('8', buffer[3].get(1)); } public void testPartiallyCopyMultipleBuffers() { final ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(5), ByteBuffer.allocate(5), ByteBuffer.allocate(5), ByteBuffer.allocate(5)}; buffer[0].put("09876".getBytes()).flip(); buffer[1].put("12345".getBytes()).flip(); buffer[2].put("67890".getBytes()).flip(); buffer[3].put("54321".getBytes()).flip(); final ByteBuffer copy1 = ByteBuffer.allocate(7); assertEquals(7, Buffers.copy(copy1, buffer, 1, 2)); assertEquals(buffer[1].limit(), buffer[1].position()); assertEquals(2, buffer[2].position()); assertEquals(copy1.limit(), copy1.position()); assertBufferContent(copy1, "1234567"); buffer[1].position(0); buffer[2].position(0); final ByteBuffer[] copy2 = new ByteBuffer[] {ByteBuffer.allocate(2), ByteBuffer.allocate(2)}; assertEquals(4, Buffers.copy(copy2, 0, 2, buffer, 1, 2)); assertEquals(4, buffer[1].position()); assertEquals(copy2[0].limit(), copy2[0].position()); assertEquals(copy2[1].limit(), copy2[1].position()); assertBufferContent(copy2[0], "12"); assertBufferContent(copy2[1], "34"); buffer[1].position(0); final ByteBuffer copy3 = ByteBuffer.allocate(10); assertEquals(1, Buffers.copy(1, copy3, buffer, 1, 2)); assertEquals(1, buffer[1].position()); assertEquals(1, copy3.position()); assertEquals('1', copy3.get(0)); buffer[1].position(0); final ByteBuffer[] copy4 = new ByteBuffer[] {ByteBuffer.allocate(3), ByteBuffer.allocate(4), ByteBuffer.allocate(6)}; assertEquals(9, Buffers.copy(9, copy4, 1, 2, buffer, 1, 2)); assertEquals(buffer[1].limit(), buffer[1].position()); assertEquals(4, buffer[2].position()); assertEquals(copy4[1].limit(), copy4[1].position()); assertEquals(5, copy4[2].position()); assertBufferContent(copy4[1], "1234"); assertBufferContent(copy4[2], "56789"); //check copy properties buffer[1].position(0); buffer[1].put((byte) '0'); buffer[1].put((byte) '9'); assertEquals('1', copy1.get(0)); assertEquals('2', copy1.get(1)); assertEquals('1', copy2[0].get(0)); assertEquals('2', copy2[0].get(1)); assertEquals('1', copy3.get(0)); assertEquals('1', copy4[1].get(0)); assertEquals('2', copy4[1].get(1)); copy1.put(2, (byte) '8'); copy2[1].put(1, (byte) '7'); copy3.put(4, (byte) '6'); copy4[2].put(1, (byte)'5'); assertEquals('3', buffer[1].get(2)); assertEquals('4', buffer[1].get(3)); assertEquals('5', buffer[1].get(4)); assertEquals('6', buffer[2].get(0)); } public void testCopyMultipleBuffersToSmallerBuffer() { final ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(5), ByteBuffer.allocate(5), ByteBuffer.allocate(5), ByteBuffer.allocate(5)}; buffer[0].put("09876".getBytes()).flip(); buffer[1].put("12345".getBytes()).flip(); buffer[2].put("67890".getBytes()).flip(); buffer[3].put("54321".getBytes()).flip(); final ByteBuffer copy1 = ByteBuffer.allocate(7); assertEquals(0, Buffers.copy(copy1, buffer, 1, 0)); assertEquals(7, Buffers.copy(copy1, buffer, 1, 2)); assertEquals(buffer[1].limit(), buffer[1].position()); assertEquals(2, buffer[2].position()); assertEquals(copy1.limit(), copy1.position()); assertBufferContent(copy1, "1234567"); buffer[1].position(0); buffer[2].position(0); final ByteBuffer[] copy2 = new ByteBuffer[] {ByteBuffer.allocate(2)}; assertEquals(0, Buffers.copy(copy2, 0, 0, buffer, 1, 2)); assertEquals(0, Buffers.copy(copy2, 0, 1, buffer, 0, 0)); assertEquals(2, Buffers.copy(copy2, 0, 1, buffer, 1, 2)); assertEquals(2, buffer[1].position()); assertEquals(copy2[0].limit(), copy2[0].position()); assertBufferContent(copy2[0], "12"); buffer[1].position(0); final ByteBuffer copy3 = ByteBuffer.allocate(1); assertEquals(0, Buffers.copy(10, copy3, buffer, 1, 0)); assertEquals(1, Buffers.copy(10, copy3, buffer, 1, 2)); assertEquals(1, buffer[1].position()); assertEquals(1, copy3.position()); assertEquals('1', copy3.get(0)); buffer[1].position(0); final ByteBuffer[] copy4 = new ByteBuffer[] {ByteBuffer.allocate(3), ByteBuffer.allocate(5)}; assertEquals(0, Buffers.copy(15, copy4, 0, 0, buffer, 1, 2)); assertEquals(0, Buffers.copy(15, copy4, 0, 1, buffer, 1, 0)); assertEquals(0, Buffers.copy(0, copy4, 0, 1, buffer, 1, 2)); assertEquals(3, Buffers.copy(15, copy4, 0, 1, buffer, 1, 2)); assertEquals(3, buffer[1].position()); assertEquals(copy4[0].limit(), copy4[0].position()); assertBufferContent(copy4[0], "123"); //check copy properties buffer[1].position(0); buffer[1].put((byte) '0'); buffer[1].put((byte) '9'); assertEquals('1', copy1.get(0)); assertEquals('2', copy1.get(1)); assertEquals('1', copy2[0].get(0)); assertEquals('2', copy2[0].get(1)); assertEquals('1', copy3.get(0)); assertEquals('1', copy4[0].get(0)); assertEquals('2', copy4[0].get(1)); copy1.put(2, (byte) '8'); copy1.put(3, (byte) '7'); copy2[0].put(0, (byte) '6'); copy3.put(0, (byte)'5'); copy4[1].put(2, (byte)'4'); assertEquals('0', buffer[1].get(0)); assertEquals('9', buffer[1].get(1)); assertEquals('3', buffer[1].get(2)); assertEquals('4', buffer[1].get(3)); assertEquals('5', buffer[1].get(4)); assertEquals('6', buffer[2].get(0)); } // FIXME XNIO-120 public void testCopyMultipleBuffersWithNegativeSliceSize() { final ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(10), ByteBuffer.allocate(10)}; buffer[0].put("1234567890".getBytes()).flip(); buffer[1].put("1234567890".getBytes()).flip(); final ByteBuffer copy1 = ByteBuffer.allocate(20); buffer[0].position(8); UnsupportedOperationException expected = null; try { assertEquals(0, Buffers.copy(-40, copy1, buffer, 0, 2)); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); expected = null; try { assertEquals(8, Buffers.copy(-4, copy1, buffer, 0, 2)); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); // XNIO-120 these test assertions are wrong, negative count must work just like negative slice size // assertEquals(buffer[0].limit(), buffer[0].position()); // assertEquals(6, buffer[1].position()); // assertEquals(20, copy1.limit()); // assertEquals(8, copy1.position()); // assertBufferContent(copy1, "90123456"); final ByteBuffer copy2 = ByteBuffer.allocate(10); expected = null; try { assertEquals(0, Buffers.copy(-4, copy2, buffer, 0, 2)); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); expected = null; try { assertEquals(0, Buffers.copy(-40, copy2, buffer, 0, 2)); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); buffer[1].position(0); final ByteBuffer[] copy3 = new ByteBuffer[] {ByteBuffer.allocate(3), ByteBuffer.allocate(2)}; expected = null; try { assertEquals(0, Buffers.copy(-2, copy3, 0, 2, buffer, 0, 2)); // was 5 } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); // XNIO-120 these test assertions are wrong, negative count must work just like negative slice size // assertEquals(5, buffer[1].position()); // assertEquals(copy3[0].limit(), copy3[0].position()); // assertEquals(copy3[1].limit(), copy3[1].position()); // assertBufferContent(copy3[0], "123"); // assertBufferContent(copy3[1], "45"); buffer[0].position(0); final ByteBuffer[] copy4 = new ByteBuffer[] {ByteBuffer.allocate(3), ByteBuffer.allocate(2), ByteBuffer.allocate(6)}; expected = null; try { assertEquals(0, Buffers.copy(-6, copy4, 0, 3, buffer, 0, 2)); // was 9 } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); // XNIO-120 these test assertions are wrong, negative count must work just like negative slice size // assertEquals(9, buffer[0].position()); // assertEquals(5, buffer[1].position()); // assertEquals(copy4[0].limit(), copy4[0].position()); // assertEquals(copy4[1].limit(), copy4[1].position()); // assertEquals(4, copy4[2].position()); // assertBufferContent(copy4[0], "123"); // assertBufferContent(copy4[1], "45"); // assertBufferContent(copy4[2], "6789"); final ByteBuffer[] copy6 = new ByteBuffer[] {ByteBuffer.allocate(5), ByteBuffer.allocate(5)}; expected = null; try { assertEquals(0, Buffers.copy(-6, copy6, 0, 2, buffer, 0, 2)); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); expected = null; try { assertEquals(0, Buffers.copy(-10, copy6, 0, 2, buffer, 0, 2)); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); } private void doTestFillByte(final ByteBuffer buf) { assertSame(buf, Buffers.fill(buf, 5, 30)); assertSame(buf, Buffers.fill(buf, 90, 20)); assertEquals(50, buf.position()); assertEquals(5, buf.get(3)); assertEquals(5, buf.get(29)); assertEquals(90, buf.get(30)); assertEquals(90, buf.get(31)); assertEquals(90, buf.get(49)); BufferUnderflowException expected = null; try { Buffers.fill(buf, 75, 300); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.fill(buf, 75, buf.remaining() + 1); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); } public void testFillByte() { final ByteBuffer buf = ByteBuffer.allocate(100); doTestFillByte(buf); final ByteBuffer dbuf = ByteBuffer.allocateDirect(100); doTestFillByte(dbuf); } private void doTestFillChar(final CharBuffer buf) { assertSame(buf, Buffers.fill(buf, 5, 30)); assertSame(buf, Buffers.fill(buf, 90, 20)); assertEquals(50, buf.position()); assertEquals(5, buf.get(3)); assertEquals(5, buf.get(29)); assertEquals(90, buf.get(30)); assertEquals(90, buf.get(31)); assertEquals(90, buf.get(49)); BufferUnderflowException expected = null; try { Buffers.fill(buf, 75, 300); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.fill(buf, 75, buf.remaining() + 1); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); } public void testFillChar() { final CharBuffer buf1 = CharBuffer.allocate(100); doTestFillChar(buf1); final ByteBuffer buf2 = ByteBuffer.allocateDirect(100 << 1); doTestFillChar(buf2.asCharBuffer()); } private void doTestFillShort(final ShortBuffer buf) { assertSame(buf, Buffers.fill(buf, 5, 30)); assertSame(buf, Buffers.fill(buf, 90, 20)); assertEquals(50, buf.position()); assertEquals(5, buf.get(3)); assertEquals(5, buf.get(29)); assertEquals(90, buf.get(30)); assertEquals(90, buf.get(31)); assertEquals(90, buf.get(49)); BufferUnderflowException expected = null; try { Buffers.fill(buf, 75, 300); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.fill(buf, 75, buf.remaining() + 1); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); } public void testFillShort() { final ShortBuffer buf1 = ShortBuffer.allocate(100); doTestFillShort(buf1); final ByteBuffer buf2 = ByteBuffer.allocateDirect(100 << 1); doTestFillShort(buf2.asShortBuffer()); } private void doTestFillInt(final IntBuffer buf) { assertSame(buf, Buffers.fill(buf, 5, 30)); assertSame(buf, Buffers.fill(buf, 90, 20)); assertEquals(50, buf.position()); assertEquals(5, buf.get(3)); assertEquals(5, buf.get(29)); assertEquals(90, buf.get(30)); assertEquals(90, buf.get(31)); assertEquals(90, buf.get(49)); BufferUnderflowException expected = null; try { Buffers.fill(buf, 75, 300); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.fill(buf, 75, buf.remaining() + 1); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); } public void testFillInt() { final IntBuffer buf1 = IntBuffer.allocate(100); doTestFillInt(buf1); final ByteBuffer buf2 = ByteBuffer.allocateDirect(100 << 2); doTestFillInt(buf2.asIntBuffer()); } private void doTestFillLong(final LongBuffer buf) { assertSame(buf, Buffers.fill(buf, 5, 30)); assertSame(buf, Buffers.fill(buf, 90, 20)); assertEquals(50, buf.position()); assertEquals(5, buf.get(3)); assertEquals(5, buf.get(29)); assertEquals(90, buf.get(30)); assertEquals(90, buf.get(31)); assertEquals(90, buf.get(49)); BufferUnderflowException expected = null; try { Buffers.fill(buf, 75, 300); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.fill(buf, 75, buf.remaining() + 1); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); } public void testFillLong() { final LongBuffer buf1 = LongBuffer.allocate(100); doTestFillLong(buf1); final ByteBuffer buf2 = ByteBuffer.allocateDirect(100 << 3); doTestFillLong(buf2.asLongBuffer()); } public void testSkip() { ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("abcdefghij".getBytes()).flip(); assertEquals(0, buffer.position()); assertSame(buffer, Buffers.skip(buffer, 3)); assertEquals(3, buffer.position()); assertSame(buffer, Buffers.skip(buffer, 5)); assertEquals(8, buffer.position()); Exception expected = null; try { Buffers.skip(buffer, -1); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.skip(buffer, -20); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.skip(buffer, 3); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.skip(buffer, 5); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); } public void testTrySkip() { ByteBuffer buffer = ByteBuffer.allocate(20); buffer.put("abcdefghijklmnopqrst".getBytes()).flip(); assertEquals(0, buffer.position()); assertEquals(6, Buffers.trySkip(buffer, 6)); assertEquals(6, buffer.position()); assertEquals(10, Buffers.trySkip(buffer, 10)); assertEquals(16, buffer.position()); Exception expected = null; try { Buffers.trySkip(buffer, -1); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.trySkip(buffer, -40); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); assertEquals(4, Buffers.trySkip(buffer, 6)); assertEquals(buffer.limit(), buffer.position()); } public void testTrySkipBufferArray() { ByteBuffer[] buffers = new ByteBuffer[] {ByteBuffer.allocate(2), ByteBuffer.allocate(3), ByteBuffer.allocate(4), ByteBuffer.allocate(5), ByteBuffer.allocate(1)}; buffers[0].put(new byte[] {1, 2}).flip(); buffers[1].put(new byte[] {3, 4, 5}).flip(); buffers[2].put(new byte[] {5, 6, 7, 8}).flip(); buffers[3].put(new byte[] {8, 9, 10, 11}).flip(); // 4 elements only buffers[4].put((byte) 12).flip(); assertEquals(4, Buffers.trySkip(buffers, 1, 4, 4)); assertEquals(0, buffers[0].position()); assertEquals(3, buffers[1].position()); assertEquals(1, buffers[2].position()); assertEquals(9, Buffers.trySkip(buffers, 0, 4, 10)); assertEquals(2, buffers[0].position()); assertEquals(3, buffers[1].position()); assertEquals(4, buffers[2].position()); assertEquals(4, buffers[3].position()); assertEquals(0, buffers[4].position()); Exception expected = null; try { Buffers.trySkip(buffers, 0, 3, -1); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.trySkip(buffers, 1, 4, -40); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.trySkip(buffers, 1, -34, 40); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.trySkip(buffers, -1, 34, 40); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.trySkip(buffers, 34, 1, 40); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.trySkip(buffers, 1, 5, 40); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); assertEquals(1, Buffers.trySkip(buffers, 2, 3, 6)); assertEquals(2, buffers[0].position()); assertEquals(3, buffers[1].position()); assertEquals(4, buffers[2].position()); assertEquals(4, buffers[3].position()); assertEquals(1, buffers[4].position()); } public void testUnget() { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("123456".getBytes()); Buffers.unget(buffer, 3); assertEquals('4', buffer.get()); buffer.flip(); Exception expected = null; try { Buffers.unget(buffer, 3); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.unget(buffer, -1); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } private void assertBufferContent(byte[] buffer, String content) { assertReadMessage(buffer, content); } public void testTakeBytes() { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("1234567890".getBytes()).flip(); byte[] takeResult = Buffers.take(buffer, 2); assertEquals(2, takeResult.length); assertBufferContent(takeResult, "12"); Exception expected = null; try { Buffers.take(buffer, -5); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.take((ByteBuffer) null, 1); } catch (NullPointerException e) { expected = e; } assertNotNull(expected); takeResult = Buffers.take(buffer, 5); assertEquals(5, takeResult.length); assertBufferContent(takeResult, "34567"); expected = null; try { takeResult = Buffers.take(buffer, 5); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); takeResult = Buffers.take(buffer, 0); assertEquals(0, takeResult.length); takeResult = Buffers.take(buffer); assertEquals(3, takeResult.length); assertBufferContent(takeResult, "890"); takeResult = Buffers.take(buffer); assertEquals(0, takeResult.length); expected = null; try { Buffers.take((ByteBuffer) null); } catch(NullPointerException e) { expected = e; } assertNotNull(expected); } public void testTakeChars() { final CharBuffer buffer = CharBuffer.allocate(10); buffer.put(new char[] {'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'}).flip(); char[] takeResult = Buffers.take(buffer, 1); assertEquals(1, takeResult.length); assertEquals('a', takeResult[0]); Exception expected = null; try { Buffers.take(buffer, -2); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.take((CharBuffer) null, 11); } catch (NullPointerException e) { expected = e; } assertNotNull(expected); takeResult = Buffers.take(buffer, 5); assertEquals(5, takeResult.length); assertEquals('b', takeResult[0]); assertEquals('c', takeResult[1]); assertEquals('d', takeResult[2]); assertEquals('e', takeResult[3]); assertEquals('f', takeResult[4]); expected = null; try { takeResult = Buffers.take(buffer, 6); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); takeResult = Buffers.take(buffer, 0); assertEquals(0, takeResult.length); takeResult = Buffers.take(buffer); assertEquals(4, takeResult.length); assertEquals('g', takeResult[0]); assertEquals('h', takeResult[1]); assertEquals('i', takeResult[2]); assertEquals('j', takeResult[3]); takeResult = Buffers.take(buffer); assertEquals(0, takeResult.length); expected = null; try { Buffers.take((CharBuffer) null); } catch(NullPointerException e) { expected = e; } assertNotNull(expected); } public void testTakeShorts() { final ShortBuffer buffer = ShortBuffer.allocate(10); buffer.put(new short[] {1, 2, 3, 5, 7, 11, 13, 17, 19}).flip(); short[] takeResult = Buffers.take(buffer, 4); assertEquals(4, takeResult.length); assertEquals(1, takeResult[0]); assertEquals(2, takeResult[1]); assertEquals(3, takeResult[2]); assertEquals(5, takeResult[3]); Exception expected = null; try { Buffers.take(buffer, -7); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.take((ShortBuffer) null, 1); } catch (NullPointerException e) { expected = e; } assertNotNull(expected); takeResult = Buffers.take(buffer, 4); assertEquals(4, takeResult.length); assertEquals(7, takeResult[0]); assertEquals(11, takeResult[1]); assertEquals(13, takeResult[2]); assertEquals(17, takeResult[3]); expected = null; try { takeResult = Buffers.take(buffer, 5); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); takeResult = Buffers.take(buffer, 0); assertEquals(0, takeResult.length); takeResult = Buffers.take(buffer); assertEquals(1, takeResult.length); assertEquals(19, takeResult[0]); takeResult = Buffers.take(buffer); assertEquals(0, takeResult.length); expected = null; try { Buffers.take((ShortBuffer) null); } catch(NullPointerException e) { expected = e; } assertNotNull(expected); } public void testTakeInts() { final IntBuffer buffer = IntBuffer.allocate(10); buffer.put(new int[] {2, 4, 6, 8, 10, 12, 14, 16, 18, 20}).flip(); int[] takeResult = Buffers.take(buffer, 2); assertEquals(2, takeResult.length); assertEquals(2, takeResult[0]); assertEquals(4, takeResult[1]); Exception expected = null; try { Buffers.take(buffer, -5); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.take((IntBuffer) null, 1); } catch (NullPointerException e) { expected = e; } assertNotNull(expected); takeResult = Buffers.take(buffer, 5); assertEquals(5, takeResult.length); assertEquals(6, takeResult[0]); assertEquals(8, takeResult[1]); assertEquals(10, takeResult[2]); assertEquals(12, takeResult[3]); assertEquals(14, takeResult[4]); expected = null; try { takeResult = Buffers.take(buffer, 5); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); takeResult = Buffers.take(buffer, 0); assertEquals(0, takeResult.length); takeResult = Buffers.take(buffer); assertEquals(3, takeResult.length); assertEquals(16, takeResult[0]); assertEquals(18, takeResult[1]); assertEquals(20, takeResult[2]); takeResult = Buffers.take(buffer); assertEquals(0, takeResult.length); expected = null; try { Buffers.take((ByteBuffer) null); } catch(NullPointerException e) { expected = e; } assertNotNull(expected); } public void testTakeLongs() { final LongBuffer buffer = LongBuffer.allocate(10); buffer.put(new long[] {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}).flip(); long[] takeResult = Buffers.take(buffer, 5); assertEquals(5, takeResult.length); assertEquals(0, takeResult[0]); assertEquals(1, takeResult[1]); assertEquals(2, takeResult[2]); assertEquals(3, takeResult[3]); assertEquals(4, takeResult[4]); Exception expected = null; try { Buffers.take(buffer, -1000); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.take((LongBuffer) null, 3); } catch (NullPointerException e) { expected = e; } assertNotNull(expected); takeResult = Buffers.take(buffer, 1); assertEquals(1, takeResult.length); assertEquals(5, takeResult[0]); expected = null; try { takeResult = Buffers.take(buffer, 5); } catch (BufferUnderflowException e) { expected = e; } assertNotNull(expected); takeResult = Buffers.take(buffer, 0); assertEquals(0, takeResult.length); takeResult = Buffers.take(buffer); assertEquals(4, takeResult.length); assertEquals(6, takeResult[0]); assertEquals(7, takeResult[1]); assertEquals(8, takeResult[2]); assertEquals(9, takeResult[3]); takeResult = Buffers.take(buffer); assertEquals(0, takeResult.length); expected = null; try { Buffers.take((LongBuffer) null); } catch(NullPointerException e) { expected = e; } assertNotNull(expected); } public void testDumpByteBuffer() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(15); buffer.put("create dumper".getBytes()).flip(); assertNotNull(Buffers.createDumper(buffer, 3, 3).toString()); StringBuilder builder = new StringBuilder(); Buffers.dump(buffer, builder, 5, 20); assertTrue(builder.toString().length() > 0); assertNotNull(Buffers.createDumper(buffer, 0, 5).toString()); builder = new StringBuilder(); Buffers.dump(buffer, builder, 0, 15); assertTrue(builder.toString().length() > 0); IllegalArgumentException expected = null; try { Buffers.createDumper(buffer, 3, 0); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.createDumper(buffer, 3, -1); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.createDumper(buffer, -1, 4); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.dump(buffer, builder, 3, 0); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.dump(buffer, builder, 3, -1); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.dump(buffer, builder, -1, 4); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } public void testDumpCharBuffers() throws IOException { final CharBuffer buffer = CharBuffer.allocate(15); buffer.put(new char[] {'d', 'u', 'm', 'p', ' ', 'c', 'h', 'a', 'r', 's'}).flip(); assertNotNull(Buffers.createDumper(buffer, 3, 3).toString()); StringBuilder builder = new StringBuilder(); Buffers.dump(buffer, builder, 5, 20); assertTrue(builder.toString().length() > 0); assertNotNull(Buffers.createDumper(buffer, 0, 10).toString()); builder = new StringBuilder(); Buffers.dump(buffer, builder, 0, 13); assertTrue(builder.toString().length() > 0); IllegalArgumentException expected = null; try { Buffers.createDumper(buffer, 10, 0); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.createDumper(buffer, 30, -5); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.createDumper(buffer, -5, 8); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.dump(buffer, builder, 10, 0); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.dump(buffer, builder, 30, -5); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.dump(buffer, builder, -5, 8); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } public void testEmptyPooledByteBuffer() { assertEquals(0, Buffers.EMPTY_POOLED_BYTE_BUFFER.getResource().capacity()); Buffers.EMPTY_POOLED_BYTE_BUFFER.discard(); assertEquals(0, Buffers.EMPTY_POOLED_BYTE_BUFFER.getResource().capacity()); Buffers.EMPTY_POOLED_BYTE_BUFFER.free(); assertEquals(0, Buffers.EMPTY_POOLED_BYTE_BUFFER.getResource().capacity()); assertNotNull(Buffers.EMPTY_POOLED_BYTE_BUFFER.toString()); } public void testRemaining() { assertFalse(Buffers.hasRemaining(new Buffer[0])); assertEquals(0, Buffers.remaining(new Buffer[0])); final ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(10)}; assertTrue(Buffers.hasRemaining(buffer)); assertEquals(10, Buffers.remaining(buffer)); buffer[0].put("12345".getBytes()); assertTrue(Buffers.hasRemaining(buffer)); assertEquals(5, Buffers.remaining(buffer)); buffer[0].put("67890".getBytes()); assertFalse(Buffers.hasRemaining(buffer)); assertEquals(0, Buffers.remaining(buffer)); final ByteBuffer[] buffers = new ByteBuffer[] {ByteBuffer.allocate(2), ByteBuffer.allocate(2), ByteBuffer.allocate(2), ByteBuffer.allocate(2), ByteBuffer.allocate(2)}; assertTrue(Buffers.hasRemaining(buffers)); assertEquals(10, Buffers.remaining(buffers)); assertEquals(8, Buffers.remaining(buffers, 1, 4)); buffers[2].put("12".getBytes()); assertTrue(Buffers.hasRemaining(buffers)); assertEquals(8, Buffers.remaining(buffers)); assertEquals(6, Buffers.remaining(buffers, 1, 4)); } public void testPutModifiedUtf8() { final StringBuilder stringBuilder = new StringBuilder(); stringBuilder.append('a'); stringBuilder.append((char) -10); stringBuilder.append((char) 0x777); stringBuilder.append((char) 0xfff); stringBuilder.append((char) 0); final ByteBuffer buffer = ByteBuffer.allocate(15); Buffers.putModifiedUtf8(buffer, stringBuilder.toString()); assertEquals(11, buffer.position()); buffer.flip(); assertEquals('a', buffer.get()); assertEquals((byte)(0xe0 | 0x0f & ((char)-10) >> 12), buffer.get()); assertEquals((byte)(0x80 | 0x3f & ((char)-10) >> 6), buffer.get()); assertEquals((byte)(0x80 | 0x3f & ((char)-10)), buffer.get()); assertEquals((byte) (0xc0 | 0x1f & ((char) 0x777) >> 6), buffer.get()); assertEquals((byte)(0x80 | 0x3f & ((char) 0x777)), buffer.get()); assertEquals((byte)(0xe0 | 0x0f & ((char) 0xfff) >> 12), buffer.get()); assertEquals((byte)(0x80 | 0x3f & ((char) 0xfff) >> 6), buffer.get()); assertEquals((byte)(0x80 | 0x3f & ((char) 0xfff)), buffer.get()); assertEquals((byte) 0xc0, buffer.get()); assertEquals((byte) 0x80, buffer.get()); } private void fillBufferModifiedUtf8Test(ByteBuffer buffer) { // fist char: 'a' buffer.put((byte)'a'); // second char: '?' buffer.put((byte) 0xb1); // third char: '?' buffer.put((byte) 0xc0); buffer.put((byte) 0xcd); // fourth char: (char) 1215 buffer.put((byte) 0xd2); buffer.put((byte) 0xfbf); // fifth char: (char) '?' buffer.put((byte) 0xe9); buffer.put((byte) 0xc1); // sixth char: (char) '?' buffer.put((byte) 0xe0); buffer.put((byte) 0xdef); // seventh char: (char)'?' buffer.put((byte) 0xee); buffer.put((byte) 0xebf); buffer.put((byte) 0x1); // eigth char: (char) 44730 buffer.put((byte) 0xea); buffer.put((byte) 0xeba); buffer.put((byte) 0xeba); // ninth char: '?' buffer.put((byte) 426); //0xd0+ 0x80, it will be transformed to 170 // tenth char: '?' buffer.put((byte) 0xff); // last char: 0 buffer.put((byte) 0); // char that should not be read buffer.put((byte) 'z'); buffer.flip(); } private void assertModifiedUtf8Result(char[] modifiedUtf8) { assertEquals('a', modifiedUtf8[0]); assertEquals('?', modifiedUtf8[1]); assertEquals('?', modifiedUtf8[2]); assertEquals((char) 1215, modifiedUtf8[3]); assertEquals('?', modifiedUtf8[4]); assertEquals('?', modifiedUtf8[5]); assertEquals('?', modifiedUtf8[6]); assertEquals((char) 44730, modifiedUtf8[7]); assertEquals('?', modifiedUtf8[8]); assertEquals('?', modifiedUtf8[9]); } public void testGetMotifiedUtf8Z() { final ByteBuffer buffer = ByteBuffer.allocate(20); fillBufferModifiedUtf8Test(buffer); String result = Buffers.getModifiedUtf8Z(buffer); char[] resultChars = result.toCharArray(); assertEquals(10, resultChars.length); assertModifiedUtf8Result(resultChars); } public void testGetMotifiedUtf8() { final ByteBuffer buffer = ByteBuffer.allocate(20); fillBufferModifiedUtf8Test(buffer); String result = Buffers.getModifiedUtf8(buffer); char[] resultChars = result.toCharArray(); assertEquals(12, resultChars.length); assertModifiedUtf8Result(resultChars); assertEquals('\0', resultChars[10]); assertEquals('z', resultChars[11]); } public void testReadAsciiZ() { final ByteBuffer buffer = ByteBuffer.allocate(20); buffer.put((byte) 'a'); buffer.put((byte) 'b'); buffer.put((byte) 'c'); buffer.put((byte) 0xeba); buffer.put((byte) -0xff); buffer.flip(); StringBuilder builder = new StringBuilder(); assertFalse(Buffers.readAsciiZ(buffer, builder)); char[] result = builder.toString().toCharArray(); assertEquals(5, result.length); assertEquals('a', result[0]); assertEquals('b', result[1]); assertEquals('c', result[2]); assertEquals('?', result[3]); assertEquals(1, result[4]); buffer.limit(buffer.capacity()); buffer.put((byte) 0); buffer.put((byte) 'd'); buffer.flip(); builder = new StringBuilder(); assertTrue(Buffers.readAsciiZ(buffer, builder)); result = builder.toString().toCharArray(); assertEquals(5, result.length); assertEquals('a', result[0]); assertEquals('b', result[1]); assertEquals('c', result[2]); assertEquals('?', result[3]); assertEquals(1, result[4]); assertFalse(Buffers.readAsciiZ(buffer, builder)); } public void testReadAsciiZWithReplacement() { final ByteBuffer buffer = ByteBuffer.allocate(20); buffer.put((byte) 'D'); buffer.put((byte) 'E'); buffer.put((byte) '#'); buffer.put((byte) 0xe0); buffer.put((byte) 0xaa); buffer.flip(); StringBuilder builder = new StringBuilder(); assertFalse(Buffers.readAsciiZ(buffer, builder, '#')); char[] result = builder.toString().toCharArray(); assertEquals(5, result.length); assertEquals('D', result[0]); assertEquals('E', result[1]); assertEquals('#', result[2]); assertEquals('#', result[3]); assertEquals((char) '#', result[4]); buffer.limit(buffer.capacity()); buffer.put((byte) 0); buffer.put((byte) 'F'); buffer.flip(); builder = new StringBuilder(); assertTrue(Buffers.readAsciiZ(buffer, builder, '\'')); result = builder.toString().toCharArray(); assertEquals(5, result.length); assertEquals('D', result[0]); assertEquals('E', result[1]); assertEquals('#', result[2]); assertEquals('\'', result[3]); assertEquals('\'', result[4]); assertFalse(Buffers.readAsciiZ(buffer, builder, '0')); } public void testReadAsciiLine() { final ByteBuffer buffer = ByteBuffer.allocate(30); buffer.put((byte) 'R'); buffer.put((byte) 'e'); buffer.put((byte) 'a'); buffer.put((byte) 'd'); buffer.put((byte) '\n'); buffer.put((byte) '\t'); buffer.put((byte) 'w'); buffer.put((byte) 'e'); buffer.put((byte) 'i'); buffer.put((byte) 'r'); buffer.put((byte) 'd'); buffer.put((byte) '\n'); buffer.put((byte) '\n'); buffer.put((byte) ' '); buffer.put((byte) 'c'); buffer.put((byte) 'h'); buffer.put((byte) 'a'); buffer.put((byte) 'r'); buffer.put((byte) 's'); buffer.put((byte) ':'); buffer.put((byte) 0xaa); buffer.put((byte) '\n'); buffer.put((byte) 0xeba); buffer.put((byte) '\n'); buffer.put((byte) 0xe0); buffer.put((byte) '\n'); buffer.put((byte) 0); buffer.put((byte) '#'); buffer.flip(); StringBuilder builder = new StringBuilder(); assertTrue(Buffers.readAsciiLine(buffer, builder)); assertEquals("Read\n", builder.toString()); builder = new StringBuilder(); assertTrue(Buffers.readAsciiLine(buffer, builder, '+')); assertEquals("\tweird\n", builder.toString()); builder = new StringBuilder(); assertTrue(Buffers.readAsciiLine(buffer, builder, '=', '\n')); assertEquals("\n", builder.toString()); builder = new StringBuilder(); assertTrue(Buffers.readAsciiLine(buffer, builder, '=', ':')); assertEquals(" chars:", builder.toString()); builder = new StringBuilder(); assertTrue(Buffers.readAsciiLine(buffer, builder)); assertEquals("?\n", builder.toString()); builder = new StringBuilder(); assertTrue(Buffers.readAsciiLine(buffer, builder, '1')); assertEquals("1\n", builder.toString()); builder = new StringBuilder(); assertTrue(Buffers.readAsciiLine(buffer, builder, '2')); assertEquals("2\n", builder.toString()); builder = new StringBuilder(); assertFalse(Buffers.readAsciiLine(buffer, builder, '3', '\n')); assertEquals("\0#", builder.toString()); builder = new StringBuilder(); assertFalse(Buffers.readAsciiLine(buffer, builder, '4', '\n')); assertTrue(builder.toString().isEmpty()); assertFalse(Buffers.readAsciiLine(buffer, builder, '5', '\n')); assertTrue(builder.toString().isEmpty()); } public void testReadAscii() { final ByteBuffer buffer = ByteBuffer.allocate(30); buffer.put("read".getBytes()); buffer.put((byte) 0xeba); buffer.put("this".getBytes()); buffer.put((byte)0xeba); buffer.put("until".getBytes()); buffer.put((byte)0xaa); buffer.put("the".getBytes()); buffer.put((byte)0xaa); buffer.put("end!!!".getBytes()); buffer.flip(); final StringBuilder builder = new StringBuilder(); Buffers.readAscii(buffer, builder); assertEquals("read?this?until?the?end!!!", builder.toString()); } public void testReadAsciiWithReplacement() { final ByteBuffer buffer = ByteBuffer.allocate(30); buffer.put("read".getBytes()); buffer.put((byte) 0xeba); buffer.put("this".getBytes()); buffer.put((byte)0xeba); buffer.put("until".getBytes()); buffer.put((byte)0xaa); buffer.put("the".getBytes()); buffer.put((byte)0xaa); buffer.put("end!!!".getBytes()); buffer.flip(); final StringBuilder builder = new StringBuilder(); Buffers.readAscii(buffer, builder, '@'); assertEquals("read@this@until@the@end!!!", builder.toString()); } public void testReadAsciiWithLimit() { final ByteBuffer buffer = ByteBuffer.allocate(30); buffer.put("read".getBytes()); buffer.put((byte) 0xeba); buffer.put("this".getBytes()); buffer.put((byte)0xeba); buffer.put("with".getBytes()); buffer.put((byte)0xaa); buffer.put("some".getBytes()); buffer.put((byte)0xaa); buffer.put("limit!!!".getBytes()); buffer.flip(); final StringBuilder builder = new StringBuilder(); Buffers.readAscii(buffer, builder, 10, '('); assertEquals("read(this(", builder.toString()); Buffers.readAscii(buffer, builder, 10, ')'); assertEquals("read(this(with)some)", builder.toString()); Buffers.readAscii(buffer, builder, 5, ' '); assertEquals("read(this(with)some)limit", builder.toString()); Buffers.readAscii(buffer, builder, 8, ' '); assertEquals("read(this(with)some)limit!!!", builder.toString()); } public void testReadLatin1Z() { final ByteBuffer buffer = ByteBuffer.allocate(15); buffer.put((byte) 0xaaa); buffer.put((byte) 0xa01); buffer.put((byte) 0xa02); buffer.put((byte) 0xa03); buffer.put((byte) 0xa04); buffer.put((byte) 0xa05); buffer.put((byte) 0xa06); buffer.put((byte) 0x20); buffer.put((byte) 0x21); buffer.put((byte) 0x22); buffer.flip(); StringBuilder builder = new StringBuilder(); assertFalse(Buffers.readLatin1Z(buffer, builder)); char[] chars = builder.toString().toCharArray(); assertEquals(10, chars.length); assertEquals(0xaa, chars[0]); assertEquals(1, chars[1]); assertEquals(2, chars[2]); assertEquals(3, chars[3]); assertEquals(4, chars[4]); assertEquals(5, chars[5]); assertEquals(6, chars[6]); assertEquals(0x20, chars[7]); assertEquals(0x21, chars[8]); assertEquals(0x22, chars[9]); buffer.limit(buffer.capacity()); buffer.put((byte) 0x23); buffer.put((byte) 0xa00); buffer.put((byte) 0x24); buffer.flip(); builder = new StringBuilder(); assertTrue(Buffers.readLatin1Z(buffer, builder)); chars = builder.toString().toCharArray(); assertEquals(11, chars.length); assertEquals(0xaa, chars[0]); assertEquals(1, chars[1]); assertEquals(2, chars[2]); assertEquals(3, chars[3]); assertEquals(4, chars[4]); assertEquals(5, chars[5]); assertEquals(6, chars[6]); assertEquals(0x20, chars[7]); assertEquals(0x21, chars[8]); assertEquals(0x22, chars[9]); assertEquals(0x23, chars[10]); } public void testReadLatin1Line() { final ByteBuffer buffer = ByteBuffer.allocate(15); buffer.put((byte) 0xaaa); buffer.put((byte) 0); buffer.put((byte) 0xa01); buffer.put((byte) 0xa02); buffer.put((byte) 0xa03); buffer.put((byte) 0xa04); buffer.put((byte) '\n'); buffer.put((byte) '\n'); buffer.put((byte) 0xa05); buffer.put((byte) 0xa06); buffer.put((byte) 0x20); buffer.put((byte) '\n'); buffer.put((byte) 0x21); buffer.put((byte) '\n'); buffer.put((byte) 0x22); buffer.flip(); StringBuilder builder = new StringBuilder(); assertTrue(Buffers.readLatin1Line(buffer, builder)); char[] chars = builder.toString().toCharArray(); assertEquals(7, chars.length); assertEquals(0xaa, chars[0]); assertEquals(0, chars[1]); assertEquals(1, chars[2]); assertEquals(2, chars[3]); assertEquals(3, chars[4]); assertEquals(4, chars[5]); assertEquals('\n', chars[6]); builder = new StringBuilder(); assertTrue(Buffers.readLatin1Line(buffer, builder)); chars = builder.toString().toCharArray(); assertEquals(1, chars.length); assertEquals('\n', chars[0]); builder = new StringBuilder(); assertTrue(Buffers.readLatin1Line(buffer, builder)); chars = builder.toString().toCharArray(); assertEquals(4, chars.length); assertEquals(5, chars[0]); assertEquals(6, chars[1]); assertEquals(0x20, chars[2]); assertEquals('\n', chars[3]); builder = new StringBuilder(); assertTrue(Buffers.readLatin1Line(buffer, builder)); chars = builder.toString().toCharArray(); assertEquals(2, chars.length); assertEquals(0x21, chars[0]); assertEquals('\n', chars[1]); builder = new StringBuilder(); assertFalse(Buffers.readLatin1Line(buffer, builder)); chars = builder.toString().toCharArray(); assertEquals(1, chars.length); assertEquals(0x22, chars[0]); } public void testReadLatin1LineWithDelimeter() { final ByteBuffer buffer = ByteBuffer.allocate(15); buffer.put((byte) 0xaaa); buffer.put((byte) 0); buffer.put((byte) 0xa01); buffer.put((byte) 0xa02); buffer.put((byte) 0xa03); buffer.put((byte) 0xa04); buffer.put((byte) '\t'); buffer.put((byte) 'x'); buffer.put((byte) 0xa05); buffer.put((byte) 0xa06); buffer.put((byte) 0x20); buffer.put((byte) 'y'); buffer.put((byte) 0x21); buffer.put((byte) 'z'); buffer.put((byte) 0x22); buffer.flip(); StringBuilder builder = new StringBuilder(); assertTrue(Buffers.readLatin1Line(buffer, builder, '\t')); char[] chars = builder.toString().toCharArray(); assertEquals(7, chars.length); assertEquals(0xaa, chars[0]); assertEquals(0, chars[1]); assertEquals(1, chars[2]); assertEquals(2, chars[3]); assertEquals(3, chars[4]); assertEquals(4, chars[5]); assertEquals('\t', chars[6]); builder = new StringBuilder(); assertTrue(Buffers.readLatin1Line(buffer, builder, 'x')); chars = builder.toString().toCharArray(); assertEquals(1, chars.length); assertEquals('x', chars[0]); builder = new StringBuilder(); assertTrue(Buffers.readLatin1Line(buffer, builder, 'y')); chars = builder.toString().toCharArray(); assertEquals(4, chars.length); assertEquals(5, chars[0]); assertEquals(6, chars[1]); assertEquals(0x20, chars[2]); assertEquals('y', chars[3]); builder = new StringBuilder(); assertTrue(Buffers.readLatin1Line(buffer, builder, 'z')); chars = builder.toString().toCharArray(); assertEquals(2, chars.length); assertEquals(0x21, chars[0]); assertEquals('z', chars[1]); builder = new StringBuilder(); assertFalse(Buffers.readLatin1Line(buffer, builder, (char) 0)); chars = builder.toString().toCharArray(); assertEquals(1, chars.length); assertEquals(0x22, chars[0]); } public void testReadLatin1() { final ByteBuffer buffer = ByteBuffer.allocate(15); buffer.put((byte) 0xa59); buffer.put((byte) 0xa58); buffer.put((byte) 0xa57); buffer.put((byte) 0xa56); buffer.put((byte) 0xa55); buffer.put((byte) 0xa54); buffer.put((byte) 0x53); buffer.put((byte) 0x52); buffer.put((byte) 0x51); buffer.put((byte) 0x0); buffer.put((byte) 0x50); buffer.flip(); final StringBuilder builder = new StringBuilder(); Buffers.readLatin1(buffer, builder); final char[] chars = builder.toString().toCharArray(); assertEquals(11, chars.length); assertEquals(0x59, chars[0]); assertEquals(0x58, chars[1]); assertEquals(0x57, chars[2]); assertEquals(0x56, chars[3]); assertEquals(0x55, chars[4]); assertEquals(0x54, chars[5]); assertEquals(0x53, chars[6]); assertEquals(0x52, chars[7]); assertEquals(0x51, chars[8]); assertEquals(0x0, chars[9]); assertEquals(0x50, chars[10]); } public void testReadModifiedUtf8Z() { final ByteBuffer buffer = ByteBuffer.allocate(30); buffer.put((byte) 0xa00); // '\0' buffer.put((byte) 'a'); // 'a' buffer.put((byte) 'B'); // 'B' buffer.put((byte) 0xf89); // '?' buffer.put((byte) 0xaa1); // '?' buffer.put((byte) 0xd9); // partial char info buffer.flip(); StringBuilder builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Z(buffer, builder)); assertEquals(1, buffer.position()); assertTrue(builder.toString().isEmpty()); assertFalse(Buffers.readModifiedUtf8Z(buffer, builder)); assertEquals(5, buffer.position()); char[] modifiedUtf8Chars = builder.toString().toCharArray(); assertEquals(4, modifiedUtf8Chars.length); assertEquals('a', modifiedUtf8Chars[0]); assertEquals('B', modifiedUtf8Chars[1]); assertEquals('?', modifiedUtf8Chars[2]); assertEquals('?', modifiedUtf8Chars[3]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Z(buffer, builder)); assertEquals(5, buffer.position()); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(6, (byte) 0xc1); // '?' buffer.put(7, (byte) 0xd5); buffer.put(8, (byte) 0x88); // (0xd5 & 0x1f) << 6 | 0x88 & 0x3f) buffer.put(9, (byte) 0xe2); // partial char info buffer.limit(10); assertFalse(Buffers.readModifiedUtf8Z(buffer, builder)); assertEquals(9, buffer.position()); modifiedUtf8Chars = builder.toString().toCharArray(); assertEquals(2, modifiedUtf8Chars.length); assertEquals('?', modifiedUtf8Chars[0]); assertEquals((char) (0xd5 & 0x1f) << 6 | (0x88 & 0x3f), modifiedUtf8Chars[1]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Z(buffer, builder)); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(10, (byte) 0xcc); // '?' buffer.put(11, (byte) 0xfee); buffer.put(12, (byte) 0x81); // partial char info buffer.limit(13); assertFalse(Buffers.readModifiedUtf8Z(buffer, builder)); assertEquals(11, buffer.position()); modifiedUtf8Chars = builder.toString().toCharArray(); assertEquals(1, modifiedUtf8Chars.length); assertEquals('?', modifiedUtf8Chars[0]); buffer.limit(buffer.capacity()); buffer.put(13, (byte) 0x8ca); // '?' buffer.put(14, (byte) 0xef); buffer.put(15, (byte) 0xc8a); buffer.put(16, (byte) 0xc8b); // (0xef & 0x0f) << 12 | (0x8a & 0x3f) << 6 | 0x8b & 0x3f buffer.put(17, (byte) 0xfff); buffer.put(18, (byte) 0xffa); buffer.put(19, (byte) 0xff6); buffer.limit(20); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Z(buffer, builder)); assertEquals(buffer.limit(), buffer.position()); modifiedUtf8Chars = builder.toString().toCharArray(); assertEquals(5, modifiedUtf8Chars.length); assertEquals('?', modifiedUtf8Chars[0]); assertEquals((char) (0xef & 0x0f) << 12 | (0x8a & 0x3f) << 6 | 0x8b & 0x3f, modifiedUtf8Chars[1]); assertEquals('?', modifiedUtf8Chars[2]); assertEquals('?', modifiedUtf8Chars[3]); assertEquals('?', modifiedUtf8Chars[4]); // test with empty buffer builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Z(buffer, builder)); assertTrue(builder.toString().isEmpty()); } public void testReadModifiedUtf8ZWithReplacement() { final ByteBuffer buffer = ByteBuffer.allocate(30); buffer.put((byte) 0xa00); // '\0' buffer.put((byte) 'a'); // 'a' buffer.put((byte) 'B'); // 'B' buffer.put((byte) 0xf89); // replacement char buffer.put((byte) 0xaa1); // replacement char buffer.put((byte) 0xd9); // partial char info buffer.flip(); StringBuilder builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Z(buffer, builder, '!')); assertEquals(1, buffer.position()); assertTrue(builder.toString().isEmpty()); assertFalse(Buffers.readModifiedUtf8Z(buffer, builder, '@')); assertEquals(5, buffer.position()); char[] modifiedUtf8Chars = builder.toString().toCharArray(); assertEquals(4, modifiedUtf8Chars.length); assertEquals('a', modifiedUtf8Chars[0]); assertEquals('B', modifiedUtf8Chars[1]); assertEquals('@', modifiedUtf8Chars[2]); assertEquals('@', modifiedUtf8Chars[3]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Z(buffer, builder, '#')); assertEquals(5, buffer.position()); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(6, (byte) 0xc1); // replacement char buffer.put(7, (byte) 0xd5); buffer.put(8, (byte) 0x88); // (0xd5 & 0x1f) << 6 | 0x88 & 0x3f) buffer.put(9, (byte) 0xe2); // partial char info buffer.limit(10); assertFalse(Buffers.readModifiedUtf8Z(buffer, builder, '$')); assertEquals(9, buffer.position()); modifiedUtf8Chars = builder.toString().toCharArray(); assertEquals(2, modifiedUtf8Chars.length); assertEquals('$', modifiedUtf8Chars[0]); assertEquals((char) (0xd5 & 0x1f) << 6 | (0x88 & 0x3f), modifiedUtf8Chars[1]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Z(buffer, builder, '%')); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(10, (byte) 0xcc); // replacement char buffer.put(11, (byte) 0xfee); buffer.put(12, (byte) 0x81); // partial char info buffer.limit(13); assertFalse(Buffers.readModifiedUtf8Z(buffer, builder, '&')); assertEquals(11, buffer.position()); modifiedUtf8Chars = builder.toString().toCharArray(); assertEquals(1, modifiedUtf8Chars.length); assertEquals('&', modifiedUtf8Chars[0]); buffer.limit(buffer.capacity()); buffer.put(13, (byte) 0x8ca); // replacement char buffer.put(14, (byte) 0xef); buffer.put(15, (byte) 0xc8a); buffer.put(16, (byte) 0xc8b); // (0xef & 0x0f) << 12 | (0x8a & 0x3f) << 6 | 0x8b & 0x3f buffer.put(17, (byte) 0xfff); buffer.put(18, (byte) 0xffa); buffer.put(19, (byte) 0xff6); buffer.limit(20); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Z(buffer, builder, '*')); assertEquals(buffer.limit(), buffer.position()); modifiedUtf8Chars = builder.toString().toCharArray(); assertEquals(5, modifiedUtf8Chars.length); assertEquals('*', modifiedUtf8Chars[0]); assertEquals((char) (0xef & 0x0f) << 12 | (0x8a & 0x3f) << 6 | 0x8b & 0x3f, modifiedUtf8Chars[1]); assertEquals('*', modifiedUtf8Chars[2]); assertEquals('*', modifiedUtf8Chars[3]); assertEquals('*', modifiedUtf8Chars[4]); // test with empty buffer builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Z(buffer, builder, '+')); assertTrue(builder.toString().isEmpty()); } public void testReadModifiedUtf8Line() { final ByteBuffer buffer = ByteBuffer.allocate(40); buffer.put((byte) '\n'); buffer.put((byte) '\n'); buffer.put((byte) 0xa00); // '\0' buffer.put((byte) '\n'); buffer.put((byte) 'a'); // 'a' buffer.put((byte) 'B'); // 'B' buffer.put((byte) 0xf89); // '?' buffer.put((byte) 0xaa1); // '?' buffer.put((byte) '\n'); buffer.put((byte) 0xd9); // partial char info buffer.flip(); StringBuilder builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder)); assertEquals(1, buffer.position()); char[] modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(1, modifiedUtf8Line.length); assertEquals('\n', modifiedUtf8Line[0]); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder)); assertEquals(2, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(1, modifiedUtf8Line.length); assertEquals('\n', modifiedUtf8Line[0]); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder)); assertEquals(4, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(2, modifiedUtf8Line.length); assertEquals('\0', modifiedUtf8Line[0]); assertEquals('\n', modifiedUtf8Line[1]); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder)); assertEquals(9, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(5, modifiedUtf8Line.length); assertEquals('a', modifiedUtf8Line[0]); assertEquals('B', modifiedUtf8Line[1]); assertEquals('?', modifiedUtf8Line[2]); assertEquals('?', modifiedUtf8Line[3]); assertEquals('\n', modifiedUtf8Line[4]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder)); assertEquals(9, buffer.position()); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(10, (byte) 0xc1); // '?' buffer.put(11, (byte) 0xd5); buffer.put(12, (byte) 0x88); // (0xd5 & 0x1f) << 6 | 0x88 & 0x3f) buffer.put(13, (byte) 0xe2); // partial char info buffer.limit(14); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder)); assertEquals(13, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(2, modifiedUtf8Line.length); assertEquals('?', modifiedUtf8Line[0]); assertEquals((char) (0xd5 & 0x1f) << 6 | (0x88 & 0x3f), modifiedUtf8Line[1]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder)); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(14, (byte) 0xcc); // '?' buffer.put(15, (byte) '\n'); buffer.put(16, (byte) 0xfee); buffer.put(17, (byte) 0x81); // partial char info buffer.limit(18); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder)); assertEquals(16, buffer.position()); modifiedUtf8Line= builder.toString().toCharArray(); assertEquals(2, modifiedUtf8Line.length); assertEquals('?', modifiedUtf8Line[0]); assertEquals('\n', modifiedUtf8Line[1]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder)); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(18, (byte) 0x8ca); // '?' buffer.put(19, (byte) 0xef); buffer.put(20, (byte) 0xc8a); buffer.put(21, (byte) 0xc8b); // (0xef & 0x0f) << 12 | (0x8a & 0x3f) << 6 | 0x8b & 0x3f buffer.put(22, (byte) 0xfff); // '?' buffer.put(23, (byte) '\n'); buffer.put(24, (byte) 0xffa); // '?' buffer.put(25, (byte) '\n'); buffer.put(26, (byte) 0xff6); // '?' buffer.limit(27); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder)); assertEquals(24, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(4, modifiedUtf8Line.length); assertEquals('?', modifiedUtf8Line[0]); assertEquals((char) (0xef & 0x0f) << 12 | (0x8a & 0x3f) << 6 | 0x8b & 0x3f, modifiedUtf8Line[1]); assertEquals('?', modifiedUtf8Line[2]); assertEquals('\n', modifiedUtf8Line[3]); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder)); assertEquals(26, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(2, modifiedUtf8Line.length); assertEquals('?', modifiedUtf8Line[0]); assertEquals('\n', modifiedUtf8Line[1]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder)); assertEquals(27, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(1, modifiedUtf8Line.length); assertEquals('?', modifiedUtf8Line[0]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder)); assertEquals(buffer.limit(), buffer.position()); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(27, (byte) 'c'); buffer.put(28, (byte) 0xc0); buffer.put(29, (byte) 0x8a); // '\n' buffer.put(30, (byte) 'D'); buffer.put(31, (byte) 'e'); buffer.put(32, (byte) 'F'); buffer.put(33, (byte) 0xe0); buffer.put(34, (byte) 0x80); buffer.put(35, (byte) 0x8a); // '\n' buffer.limit(36); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder)); assertEquals(30, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(2, modifiedUtf8Line.length); assertEquals('c', modifiedUtf8Line[0]); assertEquals('\n', modifiedUtf8Line[1]); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder)); assertEquals(buffer.limit(), buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(4, modifiedUtf8Line.length); assertEquals('D', modifiedUtf8Line[0]); assertEquals('e', modifiedUtf8Line[1]); assertEquals('F', modifiedUtf8Line[2]); assertEquals('\n', modifiedUtf8Line[3]); // test with empty buffer builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder)); assertTrue(builder.toString().isEmpty()); } public void testReadModifiedUtf8LineWithReplacement() { final ByteBuffer buffer = ByteBuffer.allocate(40); buffer.put((byte) '\n'); buffer.put((byte) '\n'); buffer.put((byte) 0xa00); // '\0' buffer.put((byte) '\n'); buffer.put((byte) 'a'); // 'a' buffer.put((byte) 'B'); // 'B' buffer.put((byte) 0xf89); // replacement char buffer.put((byte) 0xaa1); // replacement char buffer.put((byte) '\n'); buffer.put((byte) 0xd9); // partial char info buffer.flip(); StringBuilder builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 500)); assertEquals(1, buffer.position()); char[] modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(1, modifiedUtf8Line.length); assertEquals('\n', modifiedUtf8Line[0]); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 501)); assertEquals(2, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(1, modifiedUtf8Line.length); assertEquals('\n', modifiedUtf8Line[0]); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 502)); assertEquals(4, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(2, modifiedUtf8Line.length); assertEquals('\0', modifiedUtf8Line[0]); assertEquals('\n', modifiedUtf8Line[1]); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 503)); assertEquals(9, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(5, modifiedUtf8Line.length); assertEquals('a', modifiedUtf8Line[0]); assertEquals('B', modifiedUtf8Line[1]); assertEquals((char) 503, modifiedUtf8Line[2]); assertEquals((char) 503, modifiedUtf8Line[3]); assertEquals('\n', modifiedUtf8Line[4]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder, (char) 504)); assertEquals(9, buffer.position()); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(10, (byte) 0xc1); // replacement char buffer.put(11, (byte) 0xd5); buffer.put(12, (byte) 0x88); // (0xd5 & 0x1f) << 6 | 0x88 & 0x3f) buffer.put(13, (byte) 0xe2); // partial char info buffer.limit(14); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder, (char) 505)); assertEquals(13, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(2, modifiedUtf8Line.length); assertEquals((char) 505, modifiedUtf8Line[0]); assertEquals((char) (0xd5 & 0x1f) << 6 | (0x88 & 0x3f), modifiedUtf8Line[1]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder, (char) 506)); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(14, (byte) 0xcc); // replacement char buffer.put(15, (byte) '\n'); buffer.put(16, (byte) 0xfee); buffer.put(17, (byte) 0x81); // partial char info buffer.limit(18); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 507)); assertEquals(16, buffer.position()); modifiedUtf8Line= builder.toString().toCharArray(); assertEquals(2, modifiedUtf8Line.length); assertEquals((char) 507, modifiedUtf8Line[0]); assertEquals('\n', modifiedUtf8Line[1]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder, (char) 508)); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(18, (byte) 0x8ca); // replacement char buffer.put(19, (byte) 0xef); buffer.put(20, (byte) 0xc8a); buffer.put(21, (byte) 0xc8b); // (0xef & 0x0f) << 12 | (0x8a & 0x3f) << 6 | 0x8b & 0x3f buffer.put(22, (byte) 0xfff); // replacement char buffer.put(23, (byte) '\n'); buffer.put(24, (byte) 0xffa); // replacement char buffer.put(25, (byte) '\n'); buffer.put(26, (byte) 0xff6); // replacement char buffer.limit(27); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 509)); assertEquals(24, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(4, modifiedUtf8Line.length); assertEquals((char) 509, modifiedUtf8Line[0]); assertEquals((char) (0xef & 0x0f) << 12 | (0x8a & 0x3f) << 6 | 0x8b & 0x3f, modifiedUtf8Line[1]); assertEquals((char) 509, modifiedUtf8Line[2]); assertEquals('\n', modifiedUtf8Line[3]); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 510)); assertEquals(26, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(2, modifiedUtf8Line.length); assertEquals((char) 510, modifiedUtf8Line[0]); assertEquals('\n', modifiedUtf8Line[1]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder, (char) 511)); assertEquals(27, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(1, modifiedUtf8Line.length); assertEquals((char) 511, modifiedUtf8Line[0]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder, (char) 512)); assertEquals(buffer.limit(), buffer.position()); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(27, (byte) 'c'); buffer.put(28, (byte) 0xc0); buffer.put(29, (byte) 0x8a); // '\n' buffer.put(30, (byte) 'D'); buffer.put(31, (byte) 'e'); buffer.put(32, (byte) 'F'); buffer.put(33, (byte) 0xe0); buffer.put(34, (byte) 0x80); buffer.put(35, (byte) 0x8a); // '\n' buffer.limit(36); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 513)); assertEquals(30, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(2, modifiedUtf8Line.length); assertEquals('c', modifiedUtf8Line[0]); assertEquals('\n', modifiedUtf8Line[1]); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 514)); assertEquals(buffer.limit(), buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(4, modifiedUtf8Line.length); assertEquals('D', modifiedUtf8Line[0]); assertEquals('e', modifiedUtf8Line[1]); assertEquals('F', modifiedUtf8Line[2]); assertEquals('\n', modifiedUtf8Line[3]); // test with empty buffer builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder, (char) 515)); assertTrue(builder.toString().isEmpty()); } public void testReadModifiedUtf8LineWithReplacementAndDelimiter() { final ByteBuffer buffer = ByteBuffer.allocate(40); buffer.put((byte) '!'); buffer.put((byte) '@'); buffer.put((byte) 0xa00); // '\0' buffer.put((byte) '#'); buffer.put((byte) 'a'); // 'a' buffer.put((byte) 'B'); // 'B' buffer.put((byte) 0xf89); // replacement char buffer.put((byte) 0xaa1); // replacement char buffer.put((byte) '$'); buffer.put((byte) 0xd9); // partial char info buffer.flip(); StringBuilder builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 14, '!')); assertEquals(1, buffer.position()); char[] modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(1, modifiedUtf8Line.length); assertEquals('!', modifiedUtf8Line[0]); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 13, '@')); assertEquals(2, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(1, modifiedUtf8Line.length); assertEquals('@', modifiedUtf8Line[0]); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 12, '#')); assertEquals(4, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(2, modifiedUtf8Line.length); assertEquals('\0', modifiedUtf8Line[0]); assertEquals('#', modifiedUtf8Line[1]); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 11, '$')); assertEquals(9, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(5, modifiedUtf8Line.length); assertEquals('a', modifiedUtf8Line[0]); assertEquals('B', modifiedUtf8Line[1]); assertEquals((char) 11, modifiedUtf8Line[2]); assertEquals((char) 11, modifiedUtf8Line[3]); assertEquals('$', modifiedUtf8Line[4]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder, (char) 10, '*')); assertEquals(9, buffer.position()); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(10, (byte) 0xc1); // replacement char buffer.put(11, (byte) 0xd5); buffer.put(12, (byte) 0x88); // (0xd5 & 0x1f) << 6 | 0x88 & 0x3f) buffer.put(13, (byte) 0xe2); // partial char info buffer.limit(14); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder, (char) 9, '(')); assertEquals(13, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(2, modifiedUtf8Line.length); assertEquals((char) 9, modifiedUtf8Line[0]); assertEquals((char) (0xd5 & 0x1f) << 6 | (0x88 & 0x3f), modifiedUtf8Line[1]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder, (char) 8, ')')); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(14, (byte) 0xcc); // replacement char buffer.put(15, (byte) '_'); buffer.put(16, (byte) 0xfee); buffer.put(17, (byte) 0x81); // partial char info buffer.limit(18); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 7, '_')); assertEquals(16, buffer.position()); modifiedUtf8Line= builder.toString().toCharArray(); assertEquals(2, modifiedUtf8Line.length); assertEquals((char) 7, modifiedUtf8Line[0]); assertEquals('_', modifiedUtf8Line[1]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder, (char) 6, '+')); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(18, (byte) 0x8ca); // replacement char buffer.put(19, (byte) 0xef); buffer.put(20, (byte) 0xc8a); buffer.put(21, (byte) 0xc8b); // (0xef & 0x0f) << 12 | (0x8a & 0x3f) << 6 | 0x8b & 0x3f buffer.put(22, (byte) 0xfff); // replacement char buffer.put(23, (byte) '{'); buffer.put(24, (byte) 0xffa); // replacement char buffer.put(25, (byte) '}'); buffer.put(26, (byte) 0xff6); // replacement char buffer.limit(27); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 5, '{')); assertEquals(24, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(4, modifiedUtf8Line.length); assertEquals((char) 5, modifiedUtf8Line[0]); assertEquals((char) (0xef & 0x0f) << 12 | (0x8a & 0x3f) << 6 | 0x8b & 0x3f, modifiedUtf8Line[1]); assertEquals((char) 5, modifiedUtf8Line[2]); assertEquals('{', modifiedUtf8Line[3]); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 4, '}')); assertEquals(26, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(2, modifiedUtf8Line.length); assertEquals((char) 4, modifiedUtf8Line[0]); assertEquals('}', modifiedUtf8Line[1]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder, (char) 3, '[')); assertEquals(27, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(1, modifiedUtf8Line.length); assertEquals((char) 3, modifiedUtf8Line[0]); builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder, (char) 2, ']')); assertEquals(buffer.limit(), buffer.position()); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(27, (byte) 'c'); buffer.put(28, (byte) 0xc1); buffer.put(29, (byte) 0x9d); // ']' buffer.put(30, (byte) 'D'); buffer.put(31, (byte) 'e'); buffer.put(32, (byte) 'F'); buffer.put(33, (byte) 0xe0); buffer.put(34, (byte) 0x81); buffer.put(35, (byte) 0xbc); // '|' buffer.limit(36); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 1, ']')); assertEquals(30, buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(2, modifiedUtf8Line.length); assertEquals('c', modifiedUtf8Line[0]); assertEquals(']', modifiedUtf8Line[1]); builder = new StringBuilder(); assertTrue(Buffers.readModifiedUtf8Line(buffer, builder, (char) 0, '|')); assertEquals(buffer.limit(), buffer.position()); modifiedUtf8Line = builder.toString().toCharArray(); assertEquals(4, modifiedUtf8Line.length); assertEquals('D', modifiedUtf8Line[0]); assertEquals('e', modifiedUtf8Line[1]); assertEquals('F', modifiedUtf8Line[2]); assertEquals('|', modifiedUtf8Line[3]); // test with empty buffer builder = new StringBuilder(); assertFalse(Buffers.readModifiedUtf8Line(buffer, builder, (char) -1, '=')); assertTrue(builder.toString().isEmpty()); } public void testReadLine() { final ByteBuffer buffer = ByteBuffer.allocate(15); buffer.put((byte) 'a'); buffer.put((byte) 'b'); buffer.put((byte) 'c'); buffer.put((byte) '\n'); buffer.put((byte) 'd'); buffer.put((byte) 'e'); buffer. put((byte) 'f'); buffer.put((byte) '\n'); buffer.put((byte) 'g'); buffer.put((byte) 'h'); buffer.put((byte) 'i'); buffer.flip(); StringBuilder builder = new StringBuilder(); assertTrue(Buffers.readLine(buffer, builder, Charset.defaultCharset().newDecoder())); assertEquals(4, buffer.position()); char[] line = builder.toString().toCharArray(); assertEquals(4, line.length); assertEquals('a', line[0]); assertEquals('b', line[1]); assertEquals('c', line[2]); assertEquals('\n', line[3]); builder = new StringBuilder(); assertTrue(Buffers.readLine(buffer, builder, Charset.defaultCharset().newDecoder())); assertEquals(8, buffer.position()); line = builder.toString().toCharArray(); assertEquals(4, line.length); assertEquals('d', line[0]); assertEquals('e', line[1]); assertEquals('f', line[2]); assertEquals('\n', line[3]); builder = new StringBuilder(); assertFalse(Buffers.readLine(buffer, builder, Charset.defaultCharset().newDecoder())); assertEquals(buffer.limit(), buffer.position()); line = builder.toString().toCharArray(); assertEquals(3, line.length); assertEquals('g', line[0]); assertEquals('h', line[1]); assertEquals('i', line[2]); builder = new StringBuilder(); assertFalse(Buffers.readLine(buffer, builder, Charset.defaultCharset().newDecoder())); assertEquals(buffer.limit(), buffer.position()); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(buffer.position(), (byte) '\n'); buffer.put(buffer.position() + 1, (byte) '\n'); buffer.limit(buffer.position() + 2); assertTrue(Buffers.readLine(buffer, builder, Charset.defaultCharset().newDecoder())); assertEquals(12, buffer.position()); line = builder.toString().toCharArray(); assertEquals(1, line.length); assertEquals('\n', line[0]); builder = new StringBuilder(); assertTrue(Buffers.readLine(buffer, builder, Charset.defaultCharset().newDecoder())); assertEquals(buffer.limit(), buffer.position()); line = builder.toString().toCharArray(); assertEquals(1, line.length); assertEquals('\n', line[0]); builder = new StringBuilder(); assertFalse(Buffers.readLine(buffer, builder, Charset.defaultCharset().newDecoder())); assertEquals(buffer.limit(), buffer.position()); assertTrue(builder.toString().isEmpty()); } public void testReadLineWithDelimiter() { final ByteBuffer buffer = ByteBuffer.allocate(15); buffer.put((byte) 'a'); buffer.put((byte) 'b'); buffer.put((byte) 'c'); buffer.put((byte) '\\'); buffer.put((byte) 'd'); buffer.put((byte) 'e'); buffer. put((byte) 'f'); buffer.put((byte) '/'); buffer.put((byte) 'g'); buffer.put((byte) 'h'); buffer.put((byte) 'i'); buffer.flip(); StringBuilder builder = new StringBuilder(); assertTrue(Buffers.readLine(buffer, builder, Charset.defaultCharset().newDecoder(), '\\')); assertEquals(4, buffer.position()); char[] line = builder.toString().toCharArray(); assertEquals(4, line.length); assertEquals('a', line[0]); assertEquals('b', line[1]); assertEquals('c', line[2]); assertEquals('\\', line[3]); builder = new StringBuilder(); assertTrue(Buffers.readLine(buffer, builder, Charset.defaultCharset().newDecoder(), '/')); assertEquals(8, buffer.position()); line = builder.toString().toCharArray(); assertEquals(4, line.length); assertEquals('d', line[0]); assertEquals('e', line[1]); assertEquals('f', line[2]); assertEquals('/', line[3]); builder = new StringBuilder(); assertFalse(Buffers.readLine(buffer, builder, Charset.defaultCharset().newDecoder(), '|')); assertEquals(buffer.limit(), buffer.position()); line = builder.toString().toCharArray(); assertEquals(3, line.length); assertEquals('g', line[0]); assertEquals('h', line[1]); assertEquals('i', line[2]); builder = new StringBuilder(); assertFalse(Buffers.readLine(buffer, builder, Charset.defaultCharset().newDecoder(), '|')); assertEquals(buffer.limit(), buffer.position()); assertTrue(builder.toString().isEmpty()); buffer.limit(buffer.capacity()); buffer.put(buffer.position(), (byte) '|'); buffer.put(buffer.position() + 1, (byte) '_'); buffer.limit(buffer.position() + 2); assertTrue(Buffers.readLine(buffer, builder, Charset.defaultCharset().newDecoder(), '|')); assertEquals(12, buffer.position()); line = builder.toString().toCharArray(); assertEquals(1, line.length); assertEquals('|', line[0]); builder = new StringBuilder(); assertTrue(Buffers.readLine(buffer, builder, Charset.defaultCharset().newDecoder(), '_')); assertEquals(buffer.limit(), buffer.position()); line = builder.toString().toCharArray(); assertEquals(1, line.length); assertEquals('_', line[0]); builder = new StringBuilder(); assertFalse(Buffers.readLine(buffer, builder, Charset.defaultCharset().newDecoder(), '_')); assertEquals(buffer.limit(), buffer.position()); assertTrue(builder.toString().isEmpty()); } private void assertPooledBuffers(Pooled pooledBuffer1, Pooled pooledBuffer2) { assertNotNull(pooledBuffer1.toString()); assertNotNull(pooledBuffer1.getResource()); assertNotNull(pooledBuffer2.toString()); assertNotNull(pooledBuffer2.getResource()); pooledBuffer1.discard(); IllegalStateException expected = null; try { pooledBuffer1.getResource(); } catch (IllegalStateException e) { expected = e; } assertNotNull(expected); assertNotNull(pooledBuffer1.toString()); pooledBuffer1.free(); expected = null; try { pooledBuffer1.getResource(); } catch (IllegalStateException e) { expected = e; } assertNotNull(expected); assertNotNull(pooledBuffer1.toString()); pooledBuffer2.free(); expected = null; try { pooledBuffer2.getResource(); } catch (IllegalStateException e) { expected = e; } assertNotNull(expected); assertNotNull(pooledBuffer2.toString()); pooledBuffer2.discard(); expected = null; try { pooledBuffer2.getResource(); } catch (IllegalStateException e) { expected = e; } assertNotNull(expected); assertNotNull(pooledBuffer2.toString()); } public void testPooledWrapper() { final ByteBuffer buffer = ByteBuffer.allocate(10); final Pooled pooledBuffer1 = Buffers.pooledWrapper(buffer); final Pooled pooledBuffer2 = Buffers.pooledWrapper(buffer); assertNotNull(pooledBuffer1); assertSame(buffer, pooledBuffer1.getResource()); assertNotNull(pooledBuffer2); assertSame(buffer, pooledBuffer2.getResource()); assertPooledBuffers(pooledBuffer1, pooledBuffer2); } private void assertFlippedBufferContent(ByteBuffer buffer, String content) { buffer.position(buffer.limit()); assertBufferContent(buffer, content); } public void testSliceAllocator() { final ByteBuffer buffer = ByteBuffer.allocate(30); buffer.put("abcdefghijklmnopqrstuvwxyz1234".getBytes()).flip(); final BufferAllocator allocator = Buffers.sliceAllocator(buffer); final ByteBuffer slice1 = allocator.allocate(5); final ByteBuffer slice2 = allocator.allocate(10); final ByteBuffer slice3 = allocator.allocate(15); assertEquals(5, slice1.limit()); assertEquals(5, slice1.capacity()); assertEquals(0, slice1.position()); assertFlippedBufferContent(slice1, "abcde"); slice1.put(0, (byte) '5'); buffer.put(1, (byte) '6'); assertEquals('5', buffer.get(0)); assertEquals('6', slice1.get(1)); assertEquals(10, slice2.limit()); assertEquals(10, slice2.capacity()); assertFlippedBufferContent(slice2, "fghijklmno"); slice2.put(0, (byte) '7'); buffer.put(6, (byte) '8'); assertEquals('7', buffer.get(5)); assertEquals('8', slice2.get(1)); assertEquals(15, slice3.limit()); assertEquals(15, slice3.capacity()); assertFlippedBufferContent(slice3, "pqrstuvwxyz1234"); slice3.put(0, (byte) '9'); buffer.put(16, (byte) '0'); assertEquals('9', buffer.get(15)); assertEquals('0', slice3.get(1)); } public void testSliceAllocatorWithAllocatedBufferPool() { final ByteBuffer buffer = ByteBuffer.allocate(12); buffer.put("abcdefghijkl".getBytes()).flip(); final BufferAllocator allocator = Buffers.sliceAllocator(buffer); final Pool slice1Pool = Buffers.allocatedBufferPool(allocator, 5); final ByteBuffer slice1 = slice1Pool.allocate().getResource(); final Pool slice2Pool = Buffers.allocatedBufferPool(allocator, 7); final ByteBuffer slice2 = slice2Pool.allocate().getResource(); assertEquals(5, slice1.limit()); assertEquals(5, slice1.capacity()); assertEquals(0, slice1.position()); assertFlippedBufferContent(slice1, "abcde"); slice1.put(0, (byte) '5'); buffer.put(1, (byte) '6'); assertEquals('5', buffer.get(0)); assertEquals('6', slice1.get(1)); assertEquals(7, slice2.limit()); assertEquals(7, slice2.capacity()); assertFlippedBufferContent(slice2, "fghijkl"); slice2.put(0, (byte) '7'); buffer.put(6, (byte) '8'); assertEquals('7', buffer.get(5)); assertEquals('8', slice2.get(1)); } public void testSecureBufferPool() { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 17000, 17000 * 16); final Pool securePool = Buffers.secureBufferPool(pool); assertNotNull(securePool); assertTrue(Buffers.isSecureBufferPool(securePool)); assertFalse(Buffers.isSecureBufferPool(pool)); Pooled pooledBuffer1 = securePool.allocate(); Pooled pooledBuffer2 = securePool.allocate(); assertNotNull(pooledBuffer1); assertNotNull(pooledBuffer2); assertPooledBuffers(pooledBuffer1, pooledBuffer2); } public void testZeroByteBuffer() { final ByteBuffer buffer1 = ByteBuffer.allocate(23); final ByteBuffer buffer2 = ByteBuffer.allocate(24); for (int i = 0; i < 23; i++) { buffer1.put((byte) i); buffer2.put((byte) i); } buffer2.put((byte) 23); Buffers.zero(buffer1); Buffers.zero(buffer2); assertEquals(0, buffer1.position()); assertEquals(0, buffer2.position()); assertEquals(buffer1.capacity(), buffer1.limit()); assertEquals(buffer2.capacity(), buffer2.limit()); while(buffer1.hasRemaining()) { assertEquals(0, buffer1.get()); } while(buffer2.hasRemaining()) { assertEquals(0, buffer2.get()); } } public void testZeroCharBuffer() { final CharBuffer buffer1 = CharBuffer.allocate(95); final CharBuffer buffer2 = CharBuffer.allocate(96); for (int i = 0; i < 23; i++) { buffer1.put((char) i); buffer2.put((char) i); } buffer2.put((char) 23); Buffers.zero(buffer1); Buffers.zero(buffer2); assertEquals(0, buffer1.position()); assertEquals(0, buffer2.position()); assertEquals(buffer1.capacity(), buffer1.limit()); assertEquals(buffer2.capacity(), buffer2.limit()); while(buffer1.hasRemaining()) { assertEquals(0, buffer1.get()); } while(buffer2.hasRemaining()) { assertEquals(0, buffer2.get()); } } public void testIsDirect() { final ByteBuffer buffer1 = ByteBuffer.allocate(5); final ByteBuffer buffer2 = ByteBuffer.allocateDirect(10); final ByteBuffer buffer3 = ByteBuffer.allocateDirect(15); final ByteBuffer buffer4 = ByteBuffer.allocateDirect(15); final ByteBuffer buffer5 = ByteBuffer.allocate(15); final ByteBuffer buffer6 = ByteBuffer.allocate(15); final ByteBuffer[] buffers = new ByteBuffer[] {buffer1, buffer2, buffer3, buffer4, buffer5, buffer6}; assertFalse(Buffers.isDirect(new ByteBuffer[] {buffer1})); assertTrue(Buffers.isDirect(new ByteBuffer[] {buffer2})); IllegalArgumentException expected = null; try { assertFalse(Buffers.isDirect(buffers)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); assertTrue(Buffers.isDirect(buffers, 1, 3)); expected = null; try { Buffers.isDirect(buffers, 1, 4); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); assertFalse(Buffers.isDirect(buffers, 4, 2)); expected = null; try { Buffers.isDirect(new ByteBuffer[] {null}); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); ByteBuffer[] buffersWithNull = new ByteBuffer[] {buffer2, buffer3, buffer4, null}; assertTrue(Buffers.isDirect(buffersWithNull, 0, 3)); expected = null; try { Buffers.isDirect(buffersWithNull, 0, 4); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } public void testAssertWritable() { final ByteBuffer buffer = ByteBuffer.allocate(10); final ByteBuffer readOnlyBuffer = buffer.asReadOnlyBuffer(); Buffers.assertWritable(new ByteBuffer[] {buffer}); Buffers.assertWritable(new ByteBuffer[] {buffer, buffer, buffer, buffer}); Buffers.assertWritable(new ByteBuffer[] {buffer, buffer, buffer}, 0, 2); Buffers.assertWritable(new ByteBuffer[] {readOnlyBuffer, readOnlyBuffer, buffer, buffer, buffer, buffer, buffer, readOnlyBuffer}, 2, 5); ReadOnlyBufferException expected = null; try { Buffers.assertWritable(new ByteBuffer[] {readOnlyBuffer}); } catch (ReadOnlyBufferException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.assertWritable(new ByteBuffer[] {buffer, buffer, buffer, readOnlyBuffer}); } catch (ReadOnlyBufferException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.assertWritable(new ByteBuffer[] {readOnlyBuffer, readOnlyBuffer, readOnlyBuffer}, 1, 1); } catch (ReadOnlyBufferException e) { expected = e; } assertNotNull(expected); expected = null; try { Buffers.assertWritable(new ByteBuffer[] {readOnlyBuffer, readOnlyBuffer, buffer, readOnlyBuffer}, 2, 2); } catch (ReadOnlyBufferException e) { expected = e; } assertNotNull(expected); } public void testAddRandom() { final ByteBuffer buffer = ByteBuffer.allocate(20); final Random random = new Random(); Buffers.addRandom(buffer); Buffers.addRandom(buffer, 2 <= buffer.remaining()? 2: buffer.remaining()); Buffers.addRandom(buffer, random); Buffers.addRandom(buffer, random, buffer.remaining()); assertEquals(buffer.limit(), buffer.position()); byte randomValue = 0; buffer.flip(); int count = 0; while(buffer.hasRemaining()) { byte currentValue = buffer.get(); if (currentValue == randomValue) { if (++count > 2) { fail("3 bytes in a row with the same random value " + currentValue); } } else { count = 0; randomValue = currentValue; } } assertEquals(buffer.limit(), buffer.position()); // nothing should happen on an already full buffer Buffers.addRandom(buffer); assertEquals(buffer.limit(), buffer.position()); Buffers.addRandom(buffer, 0); assertEquals(buffer.limit(), buffer.position()); Buffers.addRandom(buffer, random); assertEquals(buffer.limit(), buffer.position()); Buffers.addRandom(buffer, random, 0); assertEquals(buffer.limit(), buffer.position()); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ByteStringTestCase.java000066400000000000000000000242521257016060700251320ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.charset.Charset; import org.junit.Test; /** * Test for {@link ByteString}. * * @author Flavia Rainone * */ public class ByteStringTestCase { @Test public void outOfBoundsByteString() { final byte[] bytes = "illegal".getBytes(); Exception exception = null; try { ByteString.copyOf(bytes, 2, 6); } catch (IndexOutOfBoundsException e) { exception = e; } assertNull(exception); exception = null; try { ByteString.copyOf(bytes, -2, 5); } catch (IndexOutOfBoundsException e) { exception = e; } assertNotNull(exception); exception = null; try { ByteString.copyOf(bytes, 2, -5); } catch (IllegalArgumentException e) { exception = e; } assertNotNull(exception); } @Test public void bytesRetrieval() { final ByteString byteString = ByteString.of("bytes retrieval".getBytes()); final byte[] bytes1 = byteString.getBytes(); assertEquals(15, bytes1.length); checkEqual("bytes retrieval", bytes1); final byte[] bytes2 = new byte[byteString.length()]; byteString.getBytes(bytes2); checkEqual("bytes retrieval", bytes2); final byte[] bytes3 = new byte[5]; byteString.getBytes(bytes3); checkEqual("bytes", bytes3); final byte[] bytes4 = new byte[0]; byteString.getBytes(bytes4); final byte[] bytes5 = new byte[20]; byteString.getBytes(bytes5); checkEqual("bytes retrieval", bytes5, 0); final byte[] bytes6 = new byte[10]; byteString.getBytes(bytes6, 9); assertEquals('b', bytes6[9]); final byte[] bytes7 = new byte[30]; byteString.getBytes(bytes7, 10); checkEqual("bytes retrieval", bytes7, 10); final byte[] bytes8 = new byte[15]; byteString.getBytes(bytes8, 3, 6); checkEqual("bytes ", bytes8, 3); } @Test public void substring() throws UnsupportedEncodingException { final ByteString byteString = ByteString.getBytes("abcdeftextghijk", Charset.defaultCharset()); assertEquals("abcdeftextghijk", byteString.toString("UTF-8")); assertEquals(15, byteString.length()); final ByteString byteStringSuffix = byteString.substring(6); assertEquals("textghijk", byteStringSuffix.toString("UTF-8")); assertEquals(9, byteStringSuffix.length()); final ByteString byteStringInnerText = byteString.substring(6, 4); assertEquals("text", byteStringInnerText.toString("UTF-8")); assertEquals(4, byteStringInnerText.length()); IndexOutOfBoundsException expected = null; try { byteString.substring(5, 11); } catch (IndexOutOfBoundsException e) { expected = e; } assertNotNull(expected); } @Test public void compareTo() { final ByteString byteString1 = ByteString.getBytes("abcde", Charset.defaultCharset()); final ByteString byteString2 = ByteString.getBytes("abcde", Charset.defaultCharset()); assertEquals(0, byteString1.compareTo(byteString1)); assertEquals(0, byteString2.compareTo(byteString2)); assertEquals(0, byteString1.compareTo(byteString2)); assertEquals(0, byteString2.compareTo(byteString1)); final ByteString byteString3 = ByteString.getBytes("abcdefgh", Charset.defaultCharset()); assertTrue(byteString3.compareTo(byteString1) > 0); assertTrue(byteString1.compareTo(byteString3) < 0); final ByteString byteString4 = ByteString.getBytes("fghij", Charset.defaultCharset()); assertTrue(byteString4.compareTo(byteString1) > 0); assertTrue(byteString1.compareTo(byteString4) < 0); assertTrue(byteString3.compareTo(byteString4) < 0); assertTrue(byteString4.compareTo(byteString3) > 0); } @Test public void equality() throws UnsupportedEncodingException { final ByteBuffer byteBuffer = ByteBuffer.allocate(5); byteBuffer.put("abcde".getBytes()).flip(); final ByteString[] equalByteStrings = { ByteString.of("abcde".getBytes()), ByteString.copyOf("abcde".getBytes(), 0, 5), ByteString.copyOf("#@$abcde".getBytes(), 3, 5), ByteString.copyOf("abcdefghij".getBytes(), 0, 5), ByteString.copyOf("12345abcde67890".getBytes(), 5, 5), ByteString.getBytes("abcde", "UTF-8"), ByteString.getBytes("abcde", Charset.defaultCharset()), ByteString.getBytes(byteBuffer), null, null, null}; byteBuffer.limit(4); byteBuffer.position(0); final ByteString[] differentByteStrings = {ByteString.of("abcdef".getBytes()), ByteString.of("xyzabcde".getBytes()), ByteString.of("yzabcdefg".getBytes()), ByteString.copyOf(new byte[0], 0, 0), ByteString.getBytes("12345", "UTF-8"), ByteString.getBytes("abcda", Charset.defaultCharset()), ByteString.getBytes(byteBuffer)}; // "abcd" equalByteStrings[8] = differentByteStrings[0].substring(0, 5); equalByteStrings[9] = differentByteStrings[1].substring(3); equalByteStrings[10] = differentByteStrings[2].substring(2, 5); checkAllAreEqual(equalByteStrings); for (ByteString byteString: differentByteStrings) { checkAllAreNotEqual(byteString, differentByteStrings); } assertFalse(equalByteStrings[0].equals("abcde")); } @Test public void readAndWriteByteString() throws IOException, ClassNotFoundException { final ByteString byteString1 = ByteString.getBytes("", Charset.defaultCharset()); final ByteString byteString2 = ByteString.getBytes("read me", Charset.defaultCharset()); final ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); final ObjectOutput output = new ObjectOutputStream(new BufferedOutputStream(byteOutputStream)); try{ output.writeObject(byteString1); output.writeObject(byteString2); } finally{ output.close(); } final ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteOutputStream.toByteArray()); final ObjectInput input = new ObjectInputStream(new BufferedInputStream(byteInputStream)); final ByteString recoveredByteString1, recoveredByteString2; try{ recoveredByteString1 = (ByteString) input.readObject(); recoveredByteString2 = (ByteString) input.readObject(); } finally{ input.close(); } assertEquals(byteString1, recoveredByteString1); assertEquals(byteString2, recoveredByteString2); } private static void checkEqual(String message, byte[] bytes) { assertArrayEquals(bytes, message.getBytes()); } private static void checkEqual(String message, byte[] bytes, int offset) { String finalMessage = ""; for (int i = 0; i < offset; i++) { finalMessage += '\0'; } finalMessage += message; for (int i = offset + message.length(); i < bytes.length; i++) { finalMessage += '\0'; } checkEqual(finalMessage, bytes); } private void checkAllAreEqual(ByteString...byteStrings) { for (ByteString byteString: byteStrings) { for (ByteString compareTo: byteStrings) { assertEquals(byteString, compareTo); // two calls to hashCode must return the same result assertEquals(byteString.hashCode(), byteString.hashCode()); assertEquals(compareTo.hashCode(), compareTo.hashCode()); // if byteString equals to compareTo, they must have the same hashCode assertEquals(byteString.hashCode(), compareTo.hashCode()); } } } private void checkAllAreNotEqual(ByteString firstByteString, ByteString...byteStrings) { ByteString byteString = firstByteString; int i = -1; do { for (ByteString compareTo: byteStrings) { if (byteString != compareTo) { assertFalse(byteString.toString() + " is equal to " + compareTo, byteString.equals((Object)compareTo)); assertFalse(byteString.toString() + " is equal to " + compareTo, byteString.equals(compareTo)); // two calls to hashCode must return the same result assertEquals(byteString.hashCode(), byteString.hashCode()); assertEquals(compareTo.hashCode(), compareTo.hashCode()); } } } while(++i < byteStrings.length && (byteString = byteStrings[i]) != null); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ChannelListenersTestCase.java000066400000000000000000001374411257016060700263060ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.xnio.AssertReadWrite.assertReadMessage; import static org.xnio.AssertReadWrite.assertWrittenMessage; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.Channel; import java.nio.channels.FileChannel; import java.nio.channels.FileLock; import java.nio.channels.ReadableByteChannel; import java.nio.channels.WritableByteChannel; import java.util.concurrent.Executor; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.atomic.AtomicReference; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import org.jmock.lib.concurrent.DeterministicExecutor; import org.junit.Test; import org.xnio.channels.AcceptingChannel; import org.xnio.mock.AcceptingChannelMock; import org.xnio.mock.ConnectedStreamChannelMock; import org.xnio.mock.MessageChannelMock; import org.xnio.mock.StreamConnectionMock; /** * Test for {@link ChannelListeners}. * * @author Flavia Rainone * */ public class ChannelListenersTestCase { @Test public void invokeChannelListener() { final ConnectedStreamChannelMock channel = new ConnectedStreamChannelMock(); final TestChannelListener listener = new TestChannelListener(); assertTrue(ChannelListeners.invokeChannelListener(channel, listener)); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); } @Test public void invokeChannelListenerWithException() { final ConnectedStreamChannelMock channel = new ConnectedStreamChannelMock(); final TestChannelListener listener = new TestChannelListener(); listener.throwExceptionOnHandle(); assertFalse(ChannelListeners.invokeChannelListener(channel, listener)); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); } @Test public void invokeNullChannelListener() { final ConnectedStreamChannelMock channel = new ConnectedStreamChannelMock(); assertTrue(ChannelListeners.invokeChannelListener(channel, null)); } @Test public void invokeChannelListenerWithExecutor() { final DeterministicExecutor executor = new DeterministicExecutor(); final ConnectedStreamChannelMock channel = new ConnectedStreamChannelMock(); final TestChannelListener listener = new TestChannelListener(); ChannelListeners.invokeChannelListener(executor, channel, listener); assertFalse(listener.isInvoked()); executor.runPendingCommands(); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); } @Test public void invokeChannelListenerWithExecutorAndException() { final DeterministicExecutor executor = new DeterministicExecutor(); final ConnectedStreamChannelMock channel = new ConnectedStreamChannelMock(); final TestChannelListener listener = new TestChannelListener(); listener.throwExceptionOnHandle(); ChannelListeners.invokeChannelListener(executor, channel, listener); assertFalse(listener.isInvoked()); executor.runPendingCommands(); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); } @Test public void invokeNullChannelListenerWithExecutor() { final DeterministicExecutor executor = new DeterministicExecutor(); final ConnectedStreamChannelMock channel = new ConnectedStreamChannelMock(); ChannelListeners.invokeChannelListener(executor, channel, null); executor.runPendingCommands(); } @Test public void invokeChannelListenerWithRejectedExecution() { final ExecutionRejector executor = new ExecutionRejector(); final ConnectedStreamChannelMock channel = new ConnectedStreamChannelMock(); final TestChannelListener listener = new TestChannelListener(); ChannelListeners.invokeChannelListener(executor, channel, listener); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); } @Test public void invokeChannelListenerWithRejectedExecutionAndListenerException() { final ExecutionRejector executor = new ExecutionRejector(); final ConnectedStreamChannelMock channel = new ConnectedStreamChannelMock(); final TestChannelListener listener = new TestChannelListener(); listener.throwExceptionOnHandle(); ChannelListeners.invokeChannelListener(executor, channel, listener); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); } @Test public void invokeNullChannelListenerWithRejectedExecution() { final ExecutionRejector executor = new ExecutionRejector(); final ConnectedStreamChannelMock channel = new ConnectedStreamChannelMock(); ChannelListeners.invokeChannelListener(executor, channel, null); } @Test public void closingChannelListener() { final ChannelListener closingListener = ChannelListeners.closingChannelListener(); assertNotNull(closingListener); final ConnectedStreamChannelMock channel = new ConnectedStreamChannelMock(); assertTrue(channel.isOpen()); closingListener.handleEvent(channel); assertFalse(channel.isOpen()); // nothing happens closingListener.handleEvent(null); } @Test public void nullChannelListener() { final ChannelListener nullListener = ChannelListeners.nullChannelListener(); assertNotNull(nullListener); final ConnectedStreamChannelMock channel = new ConnectedStreamChannelMock(); assertTrue(channel.getWrittenText().isEmpty()); assertTrue(channel.isOpen()); // nothing happens nullListener.handleEvent(channel); assertTrue(channel.getWrittenText().isEmpty()); assertTrue(channel.isOpen()); nullListener.handleEvent(null); } @Test public void openListenerAdapter() { final AcceptingChannelMock acceptingChannelMock = new AcceptingChannelMock(); IllegalArgumentException expected = null; try { ChannelListeners.openListenerAdapter(null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); final TestChannelListener testListener = new TestChannelListener(); final ChannelListener> acceptingListener = ChannelListeners.openListenerAdapter(testListener); assertNotNull(acceptingListener); assertNotNull(acceptingListener.toString()); assertFalse(testListener.isInvoked()); acceptingChannelMock.enableAcceptance(false); acceptingListener.handleEvent(acceptingChannelMock); assertFalse(testListener.isInvoked()); acceptingChannelMock.enableAcceptance(true); acceptingListener.handleEvent(acceptingChannelMock); assertTrue(testListener.isInvoked()); assertNotNull(testListener.getTargetChannel()); final AcceptingChannelMock failingAcceptingChannel = new AcceptingChannelMock() { @Override public StreamConnectionMock accept() throws IOException { throw new IOException("Test exception"); } }; // nothing should happen acceptingListener.handleEvent(failingAcceptingChannel); } @Test public void channelListenerSetterByFieldUpdater() { final ListenerSetterTesterChannel channel = new ListenerSetterTesterChannel(); @SuppressWarnings("rawtypes") final AtomicReferenceFieldUpdater fieldUpdater = channel.getFieldUpdater(); final TestChannelListener listener1 = new TestChannelListener(); final TestChannelListener listener2 = new TestChannelListener(); final TestChannelListener listener3 = new TestChannelListener(); @SuppressWarnings("deprecation") final ChannelListener.Setter setter = ChannelListeners.getSetter(channel, fieldUpdater); setter.set(listener1); assertSame(listener1, channel.getListener()); setter.set(listener2); assertSame(listener2, channel.getListener()); setter.set(listener3); assertSame(listener3, channel.getListener()); setter.set(null); assertSame(null, channel.getListener()); } @Test public void channelListenerSetterByAtomicReference() { final AtomicReference> atomicReference = new AtomicReference>(); final TestChannelListener listener1 = new TestChannelListener(); final TestChannelListener listener2 = new TestChannelListener(); final TestChannelListener listener3 = new TestChannelListener(); final ChannelListener.Setter setter = ChannelListeners. getSetter(atomicReference); setter.set(listener1); assertSame(listener1, atomicReference.get()); setter.set(listener2); assertSame(listener2, atomicReference.get()); setter.set(listener3); assertSame(listener3, atomicReference.get()); setter.set(null); assertSame(null, atomicReference.get()); } @Test public void channelListenerDelegatingSetter() { final AtomicReference> atomicReference = new AtomicReference>(); final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final TestChannelListener listener1 = new TestChannelListener(); final TestChannelListener listener2 = new TestChannelListener(); final TestChannelListener listener3 = new TestChannelListener(); final ChannelListener.Setter setter = ChannelListeners. getSetter(atomicReference); final ChannelListener.Setter delegatingSetter = ChannelListeners.getDelegatingSetter(setter, channelMock); delegatingSetter.set(listener1); final ChannelListener delegatingListener1 = atomicReference.get(); assertNotNull(delegatingListener1); delegatingSetter.set(listener2); final ChannelListener delegatingListener2 = atomicReference.get(); assertNotNull(delegatingListener2); delegatingSetter.set(listener3); final ChannelListener delegatingListener3 = atomicReference.get(); assertNotNull(delegatingListener2); delegatingSetter.set(null); assertSame(null, atomicReference.get()); assertFalse(listener1.isInvoked()); delegatingListener1.handleEvent(null); assertTrue(listener1.isInvoked()); assertSame(channelMock, listener1.getTargetChannel()); assertFalse(listener2.isInvoked()); delegatingListener2.handleEvent(new ConnectedStreamChannelMock()); assertTrue(listener2.isInvoked()); assertSame(channelMock, listener2.getTargetChannel()); assertFalse(listener3.isInvoked()); delegatingListener3.handleEvent(channelMock); assertTrue(listener3.isInvoked()); assertSame(channelMock, listener3.getTargetChannel()); assertNull(ChannelListeners.getDelegatingSetter(null, channelMock)); } @Test public void nullSetter() { final ChannelListener.Setter nullSetter = ChannelListeners.nullSetter(); assertNotNull(nullSetter); // nothing should happen nullSetter.set(null); nullSetter.set(new TestChannelListener()); } @Test public void executorChanneListener() { final TestChannelListener listener = new TestChannelListener(); final DeterministicExecutor executor = new DeterministicExecutor(); final ConnectedStreamChannelMock channel = new ConnectedStreamChannelMock(); final ChannelListener executorListener = ChannelListeners.executorChannelListener(listener, executor); assertNotNull(executorListener); executorListener.handleEvent(channel); assertFalse(listener.isInvoked()); executor.runPendingCommands(); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); final Executor failingExecutor = new ExecutionRejector(); final ChannelListener failingExecutorListener = ChannelListeners.executorChannelListener(listener, failingExecutor); assertNotNull(failingExecutor); listener.clear(); assertTrue(channel.isOpen()); failingExecutorListener.handleEvent(channel); assertFalse(listener.isInvoked()); assertFalse(channel.isOpen()); } @Test public void flushingChannelListener() throws IOException { final TestChannelListener listener = new TestChannelListener(); final FailingChannel channel = new FailingChannel(); final TestExceptionHandler exceptionHandler = new TestExceptionHandler(); final ChannelListener flushingListener = ChannelListeners. flushingChannelListener(listener, exceptionHandler); assertNotNull(flushingListener); assertNotNull(flushingListener.toString()); final ByteBuffer tempBuffer = ByteBuffer.allocate(10); tempBuffer.put("anything".getBytes()).flip(); channel.write(tempBuffer); assertFalse(channel.isFlushed()); channel.enableFlush(false); // try to flush, but flush will return false assertFalse(channel.isWriteResumed()); assertNull(channel.getWriteListener()); flushingListener.handleEvent(channel); assertSame(flushingListener, channel.getWriteListener()); assertTrue(channel.isWriteResumed()); assertFalse(channel.isFlushed()); // try to flush again, this time flush will throw an IOException final IOException flushFailure = new IOException("Test exception"); channel.throwExceptionOnFlush(flushFailure); assertFalse(exceptionHandler.isInvoked()); flushingListener.handleEvent(channel); assertFalse(channel.isWriteResumed()); assertTrue(exceptionHandler.isInvoked()); assertSame(channel, exceptionHandler.getFailingChannel()); assertSame(flushFailure, exceptionHandler.getFailure()); // try to flush again, this time flush will return true channel.enableFlush(true); flushingListener.handleEvent(channel); assertSame(listener, channel.getWriteListener()); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); } @Test public void writeShutdownListener() { final FailingChannel channel = new FailingChannel(); final TestChannelListener listener = new TestChannelListener(); final TestExceptionHandler exceptionHandler = new TestExceptionHandler(); final ChannelListener writeShutdownListener = ChannelListeners.writeShutdownChannelListener(listener, exceptionHandler); assertNotNull(writeShutdownListener); // try to handle event, shutdownWrites will throw an exception final IOException exception = new IOException("Test exception"); channel.throwExceptionOnShutdownWrites(exception); writeShutdownListener.handleEvent(channel); assertFalse(listener.isInvoked()); assertTrue(exceptionHandler.isInvoked()); assertSame(channel, exceptionHandler.getFailingChannel()); assertSame(exception, exceptionHandler.getFailure()); // try again, this time no exception will be thrown assertFalse(channel.isShutdownWrites()); writeShutdownListener.handleEvent(channel); assertTrue(channel.isShutdownWrites()); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); } @Test public void writingChannelListener() { final Pool pool = new ByteBufferSlicePool(15, 15); final Pooled pooledBuffer1 = pool.allocate(); final TestChannelListener listener = new TestChannelListener(); final FailingChannel channel = new FailingChannel(); final TestExceptionHandler exceptionHandler = new TestExceptionHandler(); final ChannelListener writingListener1 = ChannelListeners.writingChannelListener(pooledBuffer1, listener, exceptionHandler); assertNotNull(writingListener1); assertNotNull(writingListener1.toString()); // attempt to write will fail final IOException writeException = new IOException("Test exception"); channel.throwExceptionOnWrite(writeException); channel.resumeWrites(); writingListener1.handleEvent(channel); assertFalse(channel.isWriteResumed()); assertTrue(exceptionHandler.isInvoked()); assertSame(channel, exceptionHandler.getFailingChannel()); assertSame(writeException, exceptionHandler.getFailure()); IllegalStateException expected = null; try { pooledBuffer1.getResource(); } catch (IllegalStateException e) { expected = e; } assertNotNull(expected); final Pooled pooledBuffer2 = pool.allocate(); pooledBuffer2.getResource().put("abc".getBytes()).flip(); final ChannelListener writingListener2 = ChannelListeners.writingChannelListener(pooledBuffer2, listener, exceptionHandler); assertNotNull(writingListener2); assertNotNull(writingListener2.toString()); // attempt again to write... this time channel will refuse to perform write channel.enableWrite(false); writingListener2.handleEvent(channel); assertSame(writingListener2, channel.getWriteListener()); assertTrue(channel.isWriteResumed()); assertFalse(listener.isInvoked()); // attempt again to write... this time channel will perform the write channel.getWriteSetter().set(null); channel.suspendWrites(); channel.enableWrite(true); assertWrittenMessage(channel); writingListener2.handleEvent(channel); assertWrittenMessage(channel, "abc"); assertNull(channel.getWriteListener()); assertFalse(channel.isWriteResumed()); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); final Pooled pooledBuffer3 = pool.allocate(); pooledBuffer3.getResource().put("defghij".getBytes()).flip(); listener.clear(); final ChannelListener writingListener3 = ChannelListeners.writingChannelListener(pooledBuffer3, listener, exceptionHandler); assertNotNull(writingListener3); assertNotNull(writingListener3.toString()); // attempt again to write... this time channel will perform a write of part of the bytes and listener // will have to make several requests to write, in order to write the 7 bytes channel.limitWrite(3); assertWrittenMessage(channel, "abc"); writingListener3.handleEvent(channel); assertWrittenMessage(channel, "abc", "defghij"); assertNull(channel.getWriteListener()); assertFalse(channel.isWriteResumed()); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); } @Test public void sendingChannelListener() { final Pool pool = new ByteBufferSlicePool(15, 15); final Pooled pooledBuffer1 = pool.allocate(); final TestChannelListener listener = new TestChannelListener(); final FailingChannel connectedChannel = new FailingChannel(); final MessageChannelMock channel = new MessageChannelMock(connectedChannel); final TestExceptionHandler exceptionHandler = new TestExceptionHandler(); final ChannelListener sendingListener1 = ChannelListeners. sendingChannelListener(pooledBuffer1, listener, exceptionHandler); assertNotNull(sendingListener1); assertNotNull(sendingListener1.toString()); // attempt to write will fail final IOException writeException = new IOException("Test exception"); connectedChannel.throwExceptionOnWrite(writeException); connectedChannel.resumeWrites(); channel.resumeWrites(); sendingListener1.handleEvent(channel); assertFalse(channel.isWriteResumed()); assertTrue(exceptionHandler.isInvoked()); assertSame(channel, exceptionHandler.getFailingChannel()); assertSame(writeException, exceptionHandler.getFailure()); IllegalStateException expected = null; try { pooledBuffer1.getResource(); } catch (IllegalStateException e) { expected = e; } assertNotNull(expected); final Pooled pooledBuffer2 = pool.allocate(); final ChannelListener sendingListener2 = ChannelListeners. sendingChannelListener(pooledBuffer2, listener, exceptionHandler); assertNotNull(sendingListener2); assertNotNull(sendingListener2.toString()); // attempt to write will fail again, this time with a runtime exception final RuntimeException runtimeWriteException = new RuntimeException("Test exception"); connectedChannel.throwExceptionOnWrite(runtimeWriteException); connectedChannel.resumeWrites(); channel.resumeWrites(); exceptionHandler.clear(); RuntimeException expectedWriteException = null; try { sendingListener2.handleEvent(channel); } catch (RuntimeException e) { expectedWriteException = e; } assertSame(runtimeWriteException, expectedWriteException); assertTrue(channel.isWriteResumed()); assertFalse(exceptionHandler.isInvoked()); expected = null; try { pooledBuffer2.getResource(); } catch (IllegalStateException e) { expected = e; } assertNotNull(expected); final Pooled pooledBuffer3 = pool.allocate(); pooledBuffer3.getResource().put("abc".getBytes()).flip(); final ChannelListener sendingListener3 = ChannelListeners. sendingChannelListener(pooledBuffer3, listener, exceptionHandler); assertNotNull(sendingListener3); assertNotNull(sendingListener3.toString()); // attempt again to write... this time channel will refuse to perform write connectedChannel.enableWrite(false); sendingListener3.handleEvent(channel); assertSame(sendingListener3, channel.getWriteListener()); assertTrue(channel.isWriteResumed()); assertFalse(listener.isInvoked()); // attempt again to write... this time channel will perform the write channel.getWriteSetter().set(null); channel.suspendWrites(); connectedChannel.enableWrite(true); assertWrittenMessage(connectedChannel); sendingListener3.handleEvent(channel); assertWrittenMessage(connectedChannel, "abc"); assertNull(channel.getWriteListener()); assertFalse(channel.isWriteResumed()); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); } @Test public void fileSendingChannelListener() throws IOException { final TestChannelListener listener = new TestChannelListener(); final TestExceptionHandler exceptionHandler = new TestExceptionHandler(); final FailingChannel channel = new FailingChannel(); final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); final FileChannel fileChannel = randomAccessFile.getChannel(); try { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("test".getBytes("UTF-8")).flip(); assertEquals(4, fileChannel.write(buffer)); fileChannel.position(0); final ChannelListener fileSendingChannelListener1 = ChannelListeners. fileSendingChannelListener(fileChannel, 0, 4, listener, exceptionHandler); // attempt to transfer, it will fail because writing is disabled on the channel channel.enableWrite(false); assertNull(channel.getWriteListener()); assertFalse(channel.isWriteResumed()); fileSendingChannelListener1.handleEvent(channel); assertSame(fileSendingChannelListener1, channel.getWriteListener()); assertTrue(channel.isWriteResumed()); // attempt again, this time with write enabled channel.enableWrite(true); assertFalse(listener.isInvoked()); assertTrue(channel.getWrittenText().isEmpty()); fileSendingChannelListener1.handleEvent(channel); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); assertWrittenMessage(channel, "test"); listener.clear(); final ChannelListener fileSendingChannelListener2 = ChannelListeners. fileSendingChannelListener(fileChannel, 0, 0, listener, exceptionHandler); fileSendingChannelListener2.handleEvent(channel); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); final ChannelListener fileSendingChannelListener3 = ChannelListeners. fileSendingChannelListener(fileChannel, 0, 10, listener, exceptionHandler); buffer.clear(); buffer.put("1234567890".getBytes()).flip(); assertEquals(10, fileChannel.write(buffer)); final IOException writeFailure = new IOException("Test exception"); channel.throwExceptionOnWrite(writeFailure); assertFalse(exceptionHandler.isInvoked()); fileSendingChannelListener3.handleEvent(channel); assertTrue(exceptionHandler.isInvoked()); assertSame(channel, exceptionHandler.getFailingChannel()); assertSame(writeFailure, exceptionHandler.getFailure()); channel.limitWrite(3); listener.clear(); assertWrittenMessage(channel, "test"); fileSendingChannelListener3.handleEvent(channel); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); assertWrittenMessage(channel, "test", "1234567890"); } finally { randomAccessFile.close(); fileChannel.close(); } } @Test public void fileReceivingChannelListener() throws IOException { final TestChannelListener listener = new TestChannelListener(); final TestExceptionHandler exceptionHandler = new TestExceptionHandler(); final FailingChannel channel = new FailingChannel(); channel.setReadData("test"); final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); final FileChannelWrapper fileChannel = new FileChannelWrapper(randomAccessFile.getChannel()); try { final ChannelListener fileReceivingChannelListener1 = ChannelListeners. fileReceivingChannelListener(fileChannel, 0, 4, listener, exceptionHandler); // attempt to transfer, it will fail because reading is disabled on the channel channel.enableRead(false); assertNull(channel.getReadListener()); assertFalse(channel.isReadResumed()); fileReceivingChannelListener1.handleEvent(channel); assertSame(fileReceivingChannelListener1, channel.getReadListener()); assertTrue(channel.isReadResumed()); // attempt again, this time with read enabled channel.enableRead(true); assertFalse(listener.isInvoked()); final ByteBuffer buffer = ByteBuffer.allocate(15); fileChannel.read(buffer); assertReadMessage(buffer); fileReceivingChannelListener1.handleEvent(channel); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); buffer.clear(); fileChannel.read(buffer); assertReadMessage(buffer, "test"); listener.clear(); final ChannelListener fileReceivingChannelListener2 = ChannelListeners. fileReceivingChannelListener(fileChannel, 0, 0, listener, exceptionHandler); fileReceivingChannelListener2.handleEvent(channel); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); final ChannelListener fileReceivingChannelListener3 = ChannelListeners. fileReceivingChannelListener(fileChannel, 4, 10, listener, exceptionHandler); channel.setReadData("1234567890"); final IOException readFailure = new IOException("Test exception"); channel.throwExceptionOnRead(readFailure); assertFalse(exceptionHandler.isInvoked()); fileReceivingChannelListener3.handleEvent(channel); assertTrue(exceptionHandler.isInvoked()); assertSame(channel, exceptionHandler.getFailingChannel()); assertSame(readFailure, exceptionHandler.getFailure()); fileChannel.limitTransfer(3); listener.clear(); buffer.clear(); fileChannel.position(0); fileChannel.read(buffer); assertReadMessage(buffer, "test"); fileReceivingChannelListener3.handleEvent(channel); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); buffer.clear(); fileChannel.position(0); fileChannel.read(buffer); assertReadMessage(buffer, "test", "1234567890"); } finally { randomAccessFile.close(); fileChannel.close(); } } @Test public void delegatingChannelListener() { final TestChannelListener listener = new TestChannelListener(); final ConnectedStreamChannelMock channel = new ConnectedStreamChannelMock(); final ChannelListener delegatingListener = ChannelListeners. delegatingChannelListener(listener); assertNotNull(delegatingListener); assertFalse(listener.isInvoked()); delegatingListener.handleEvent(channel); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); } @Test public void writeSuspendingChannelListener() { final TestChannelListener listener = new TestChannelListener(); final ConnectedStreamChannelMock channel = new ConnectedStreamChannelMock(); final ChannelListener writeSuspendingListener = ChannelListeners. writeSuspendingChannelListener(listener); assertNotNull(writeSuspendingListener); assertFalse(listener.isInvoked()); channel.resumeWrites(); writeSuspendingListener.handleEvent(channel); assertFalse(channel.isWriteResumed()); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); } @Test public void readSuspendingChannelListener() { final TestChannelListener listener = new TestChannelListener(); final ConnectedStreamChannelMock channel = new ConnectedStreamChannelMock(); final ChannelListener readSuspendingListener = ChannelListeners. readSuspendingChannelListener(listener); assertNotNull(readSuspendingListener); assertFalse(listener.isInvoked()); channel.resumeReads(); readSuspendingListener.handleEvent(channel); assertFalse(channel.isReadResumed()); assertTrue(listener.isInvoked()); assertSame(channel, listener.getTargetChannel()); } private static class TestChannelListener implements ChannelListener { private boolean invoked = false; private Channel channel = null; private boolean throwException = false; public void throwExceptionOnHandle() { throwException = true; } @Override public void handleEvent(C c) { invoked = true; channel = c; if (throwException) { throw new RuntimeException("Test exception"); } } public boolean isInvoked() { return invoked; } public Channel getTargetChannel() { return channel; } public void clear() { invoked = false; channel = null; } } private static class ExecutionRejector implements Executor { @Override public void execute(Runnable command) { throw new RejectedExecutionException("Test execption"); } } private static class ListenerSetterTesterChannel extends ConnectedStreamChannelMock { private volatile ChannelListener listener = null; @SuppressWarnings("rawtypes") public AtomicReferenceFieldUpdater getFieldUpdater() { return AtomicReferenceFieldUpdater.newUpdater(ListenerSetterTesterChannel.class, ChannelListener.class, "listener"); } public ChannelListener getListener() { return listener; } } private static class FailingChannel extends ConnectedStreamChannelMock { private IOException flushException = null; private IOException writeShutdownException = null; private IOException writeException = null; private RuntimeException runtimeWriteException = null; private IOException readException = null; private int writeLimit = -1; public void throwExceptionOnFlush(IOException exception) { flushException = exception; } @Override public boolean flush() throws IOException { if (flushException != null) { try { throw flushException; } finally { flushException = null; } } return super.flush(); } public void throwExceptionOnShutdownWrites(IOException exception) { writeShutdownException = exception; } @Override public void shutdownWrites() throws IOException { if (writeShutdownException != null) { try { throw writeShutdownException; } finally { writeShutdownException = null; } } super.shutdownWrites(); } public void throwExceptionOnWrite(IOException exception) { writeException = exception; } public void throwExceptionOnWrite(RuntimeException exception) { runtimeWriteException = exception; } @Override public synchronized int write(ByteBuffer src) throws IOException { if (writeException != null) { try { throw writeException; } finally { writeException = null; } } if (runtimeWriteException != null) { try { throw runtimeWriteException; } finally { runtimeWriteException = null; } } if (writeLimit == -1) { return super.write(src); } int originalLimit = src.limit(); if (src.remaining() > writeLimit) { src.limit(originalLimit - src.remaining() + writeLimit); } try { return super.write(src); } finally { src.limit(originalLimit); } } @Override public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { if (writeException != null) { try { throw writeException; } finally { writeException = null; } } if (runtimeWriteException != null) { try { throw runtimeWriteException; } finally { runtimeWriteException = null; } } if (writeLimit == -1) { return super.write(srcs, offset, length); } int extraByteLength = (int) Buffers.remaining(srcs, offset, length) - writeLimit; int originalLimit = -1; if (extraByteLength > 0) { for (int i = offset + length - 1; extraByteLength > 0; i--) { if (srcs[i].remaining() > extraByteLength) { extraByteLength -= srcs[i].remaining(); } else { length = i - offset + 1; originalLimit = srcs[i].limit(); srcs[i].limit(originalLimit - extraByteLength); extraByteLength = 0; } } } try { return super.write(srcs, offset, length); } finally { if (originalLimit != -1) { srcs[length + offset - 1].limit(originalLimit); } } } @Override public long write(ByteBuffer[] srcs) throws IOException { if (writeException != null) { try { throw writeException; } finally { writeException = null; } } if (runtimeWriteException != null) { try { throw runtimeWriteException; } finally { runtimeWriteException = null; } } if (writeLimit == -1) { return super.write(srcs); } int extraByteLength = (int) Buffers.remaining(srcs) - writeLimit; int originalLimit = -1; int length = srcs.length; if (extraByteLength > 0) { for (int i = srcs.length - 1; extraByteLength > 0; i--) { if (srcs[i].remaining() > extraByteLength) { extraByteLength -= srcs[i].remaining(); } else { length = i + 1; originalLimit = srcs[i].limit(); srcs[i].limit(originalLimit - extraByteLength); extraByteLength = 0; } } } try { return super.write(srcs, 0, length); } finally { if (originalLimit != -1) { srcs[length - 1].limit(originalLimit); } } } public void limitWrite(int limit) { writeLimit = limit; } public void throwExceptionOnRead(IOException exception) { readException = exception; } @Override public synchronized int read(ByteBuffer dst) throws IOException { if (readException != null) { try { throw readException; } finally { readException = null; } } return super.read(dst); } @Override public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { if (readException != null) { try { throw readException; } finally { readException = null; } } return super.read(dsts, offset, length); } @Override public long read(ByteBuffer[] dsts) throws IOException { if (readException != null) { try { throw readException; } finally { readException = null; } } return super.read(dsts); } } private static class TestExceptionHandler implements ChannelExceptionHandler { private boolean invoked = false; private C channel; private IOException exception; @Override public void handleException(C c, IOException e) { invoked = true; channel = c; exception = e; } public boolean isInvoked() { return invoked; } public C getFailingChannel() { return channel; } public IOException getFailure() { return exception; } public void clear() { invoked = false; channel = null; exception = null; } } private static class FileChannelWrapper extends FileChannel { private final FileChannel delegate; private int transferLimit = -1; public FileChannelWrapper(FileChannel d) { delegate = d; } public void limitTransfer(int limit) { transferLimit = limit; } @Override public int read(ByteBuffer dst) throws IOException { return delegate.read(dst); } @Override public long read(ByteBuffer[] dsts, int offset, int length) throws IOException { return delegate.read(dsts, offset, length); } @Override public int write(ByteBuffer src) throws IOException { return delegate.write(src); } @Override public long write(ByteBuffer[] srcs, int offset, int length) throws IOException { return delegate.write(srcs, offset, length); } @Override public long position() throws IOException { return delegate.position(); } @Override public FileChannel position(long newPosition) throws IOException { return delegate.position(newPosition); } @Override public long size() throws IOException { return delegate.size(); } @Override public FileChannel truncate(long size) throws IOException { return delegate.truncate(size); } @Override public void force(boolean metaData) throws IOException { delegate.force(metaData); } @Override public long transferTo(long position, long count, WritableByteChannel target) throws IOException { if (transferLimit != -1 && count > transferLimit) { count = transferLimit; } return delegate.transferTo(position, count, target); } @Override public long transferFrom(ReadableByteChannel src, long position, long count) throws IOException { if (transferLimit != -1 && count > transferLimit) { count = transferLimit; } return delegate.transferFrom(src, position, count); } @Override public int read(ByteBuffer dst, long position) throws IOException { return delegate.read(dst, position); } @Override public int write(ByteBuffer src, long position) throws IOException { return delegate.write(src, position); } @Override public MappedByteBuffer map(MapMode mode, long position, long size) throws IOException { return delegate.map(mode, position, size); } @Override public FileLock lock(long position, long size, boolean shared) throws IOException { return delegate.lock(position, size, shared); } @Override public FileLock tryLock(long position, long size, boolean shared) throws IOException { return delegate.tryLock(position, size, shared); } @Override protected void implCloseChannel() throws IOException {} } } xnio-3.3.2.Final/api/src/test/java/org/xnio/CloserTestCase.java000066400000000000000000000032271257016060700242660ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import org.junit.Test; import org.xnio.mock.ConnectedStreamChannelMock; /** * Test for {@link Closer}. * * @author Flavia Rainone * */ public class CloserTestCase { @Test public void close() { final ConnectedStreamChannelMock channel = new ConnectedStreamChannelMock(); final Closer closer = new Closer(channel); assertTrue(channel.isOpen()); closer.run(); assertFalse(channel.isOpen()); } @Test public void closeNullChannel() { final Closer closer = new Closer(null); NullPointerException notExpected = null; try { closer.run(); } catch (NullPointerException e) { notExpected = e; } assertNull(notExpected); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/FailedIoFutureTestCase.java000066400000000000000000000064311257016060700257060ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.concurrent.TimeUnit; import org.junit.Test; import org.xnio.IoFuture.Notifier; import org.xnio.IoFuture.Status; /** * Test for {@link FailedIoFuture}. * * @author Flavia Rainone * */ public class FailedIoFutureTestCase { @Test public void test() throws Exception { final IOException exception = new IOException("Test exception"); final FailedIoFuture future = new FailedIoFuture(exception); future.addCancelHandler(new Cancellable() { @Override public Cancellable cancel() { throw new RuntimeException("This Cancellable should never be called!"); } }); final TestNotifier notifier = new TestNotifier(); final Object attachment = new Object(); future.addNotifier(notifier, attachment); assertTrue(notifier.isInvoked()); assertSame(future, notifier.getFuture()); assertSame(attachment, notifier.getAttachment()); assertSame(Status.FAILED, future.await()); assertSame(Status.FAILED, future.await(10, TimeUnit.SECONDS)); assertSame(Status.FAILED, future.awaitInterruptibly()); assertSame(Status.FAILED, future.awaitInterruptibly(1, TimeUnit.MINUTES)); assertSame(future, future.cancel()); IOException expected = null; try { future.get(); } catch (IOException e) { expected = e; } assertSame(exception, expected); expected = null; try { future.getInterruptibly(); } catch (IOException e) { expected = e; } assertSame(exception, expected); assertSame(exception, future.getException()); assertSame(Status.FAILED, future.getStatus()); } private static class TestNotifier implements Notifier { private boolean invoked = false; private IoFuture ioFuture; private Object attachment; @Override public void notify(IoFuture f, Object a) { invoked = true; ioFuture = f; attachment = a; } public boolean isInvoked() { return invoked; } public IoFuture getFuture() { return ioFuture; } public Object getAttachment() { return attachment; } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/FileSystemWatcherTestCase.java000066400000000000000000000152241257016060700264410ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.ConnectedStreamChannel; import org.xnio.mock.XnioMock; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.Collection; import java.util.concurrent.BlockingDeque; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; /** * Test file system watcher, poll based * * @author Stuart Douglas */ public class FileSystemWatcherTestCase { public static final String DIR_NAME = "/fileSystemWatcherTest"; public static final String EXISTING_FILE_NAME = "a.txt"; public static final String EXISTING_DIR = "existingDir"; private final BlockingDeque> results = new LinkedBlockingDeque>(); private final BlockingDeque> secondResults = new LinkedBlockingDeque>(); File rootDir; File existingSubDir; protected AcceptingChannel server; private Xnio createXnio() { return XnioMock.getInstance(); } @Before public void setup() throws Exception { rootDir = new File(System.getProperty("java.io.tmpdir") + DIR_NAME); deleteRecursive(rootDir); rootDir.mkdirs(); File existing = new File(rootDir, EXISTING_FILE_NAME); touchFile(existing); existingSubDir = new File(rootDir, EXISTING_DIR); existingSubDir.mkdir(); existing = new File(existingSubDir, EXISTING_FILE_NAME); touchFile(existing); } private static void touchFile(File existing) throws IOException { FileOutputStream out = new FileOutputStream(existing); try { out.write(("data" + System.currentTimeMillis()).getBytes()); out.flush(); } finally { IoUtils.safeClose(out); } } @After public void after() { deleteRecursive(rootDir); } @Test public void testFileSystemWatcher() throws Exception { FileSystemWatcher watcher = createXnio().createFileSystemWatcher("testWatcher", OptionMap.create(Options.WATCHER_POLL_INTERVAL, 10)); try { watcher.watchPath(rootDir, new FileChangeCallback() { @Override public void handleChanges(Collection changes) { results.add(changes); } }); watcher.watchPath(rootDir, new FileChangeCallback() { @Override public void handleChanges(Collection changes) { secondResults.add(changes); } }); //first add a file File added = new File(rootDir, "newlyAddedFile.txt").getAbsoluteFile(); touchFile(added); checkResult(added, FileChangeEvent.Type.ADDED); added.setLastModified(500); checkResult(added, FileChangeEvent.Type.MODIFIED); added.delete(); Thread.sleep(1); checkResult(added, FileChangeEvent.Type.REMOVED); added = new File(existingSubDir, "newSubDirFile.txt"); touchFile(added); checkResult(added, FileChangeEvent.Type.ADDED); added.setLastModified(500); checkResult(added, FileChangeEvent.Type.MODIFIED); added.delete(); Thread.sleep(1); checkResult(added, FileChangeEvent.Type.REMOVED); File existing = new File(rootDir, EXISTING_FILE_NAME); existing.delete(); Thread.sleep(1); checkResult(existing, FileChangeEvent.Type.REMOVED); File newDir = new File(rootDir, "newlyCreatedDirectory"); newDir.mkdir(); checkResult(newDir, FileChangeEvent.Type.ADDED); added = new File(newDir, "newlyAddedFileInNewlyAddedDirectory.txt").getAbsoluteFile(); touchFile(added); checkResult(added, FileChangeEvent.Type.ADDED); added.setLastModified(500); checkResult(added, FileChangeEvent.Type.MODIFIED); added.delete(); Thread.sleep(1); checkResult(added, FileChangeEvent.Type.REMOVED); } finally { watcher.close(); } } private void checkResult(File file, FileChangeEvent.Type type) throws InterruptedException { Collection results = this.results.poll(10, TimeUnit.SECONDS); Collection secondResults = this.secondResults.poll(10, TimeUnit.SECONDS); Assert.assertNotNull(results); Assert.assertEquals(1, results.size()); Assert.assertEquals(1, secondResults.size()); FileChangeEvent res = results.iterator().next(); FileChangeEvent res2 = secondResults.iterator().next(); if (type == FileChangeEvent.Type.REMOVED && res.getType() == FileChangeEvent.Type.MODIFIED) { //sometime OS's will give a MODIFIED event before the REMOVED one results = this.results.poll(10, TimeUnit.SECONDS); secondResults = this.secondResults.poll(10, TimeUnit.SECONDS); Assert.assertNotNull(results); Assert.assertNotNull(secondResults); Assert.assertEquals(1, results.size()); Assert.assertEquals(1, secondResults.size()); res = results.iterator().next(); } Assert.assertEquals(file, res.getFile()); Assert.assertEquals(type, res.getType()); Assert.assertEquals(file, res2.getFile()); Assert.assertEquals(type, res2.getType()); } public static void deleteRecursive(final File file) { File[] files = file.listFiles(); if (files != null) { for (File f : files) { deleteRecursive(f); } } file.delete(); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/FinishedIoFutureTestCase.java000066400000000000000000000056461257016060700262620ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.util.concurrent.TimeUnit; import org.junit.Test; import org.xnio.IoFuture.Notifier; import org.xnio.IoFuture.Status; /** * Test for {@link FinishedIoFuture}. * * @author Flavia Rainone * */ public class FinishedIoFutureTestCase { @Test public void test() throws Exception { final FinishedIoFuture future = new FinishedIoFuture("future result"); final TestNotifier notifier = new TestNotifier(); final Object attachment = new Object(); future.addNotifier(notifier, attachment); assertTrue(notifier.isInvoked()); assertSame(future, notifier.getFuture()); assertSame(attachment, notifier.getAttachment()); assertSame(Status.DONE, future.await()); assertSame(Status.DONE, future.await(10, TimeUnit.SECONDS)); assertSame(Status.DONE, future.awaitInterruptibly()); assertSame(Status.DONE, future.awaitInterruptibly(1, TimeUnit.MINUTES)); assertSame(future, future.cancel()); assertSame("future result", future.get()); assertSame("future result", future.getInterruptibly()); IllegalStateException expected = null; try { future.getException(); } catch (IllegalStateException e) { expected = e; } assertNotNull(expected); assertSame(Status.DONE, future.getStatus()); } private static class TestNotifier implements Notifier { private boolean invoked = false; private IoFuture ioFuture; private Object attachment; @Override public void notify(IoFuture f, Object a) { invoked = true; ioFuture = f; attachment = a; } public boolean isInvoked() { return invoked; } public IoFuture getFuture() { return ioFuture; } public Object getAttachment() { return attachment; } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/FutureResultTestCase.java000066400000000000000000000075061257016060700255140ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.concurrent.Executor; import org.junit.Test; import org.xnio.IoFuture.Status; /** * Test for {@link FutureResult}. * * @author Flavia Rainone * */ public class FutureResultTestCase { @Test public void setFutureResult() throws Exception { final FutureResult futureResult = new FutureResult(new Executor() { @Override public void execute(Runnable command) { command.run(); } }); // getIoFuture returns consistently the same value always final IoFuture ioFuture = futureResult.getIoFuture(); assertSame(ioFuture, futureResult.getIoFuture()); assertSame(Status.WAITING, ioFuture.getStatus()); assertTrue(futureResult.setResult("result")); assertSame(Status.DONE, ioFuture.getStatus()); assertEquals("result", ioFuture.get()); } @Test public void cancelFutureResult() throws Exception { final FutureResult futureResult = new FutureResult(); // getIoFuture returns consistently the same value always final IoFuture ioFuture = futureResult.getIoFuture(); assertSame(ioFuture, futureResult.getIoFuture()); final TestCancellable cancelHandler = new TestCancellable(); futureResult.addCancelHandler(cancelHandler); assertFalse(cancelHandler.isCancelled()); ioFuture.cancel(); assertTrue(cancelHandler.isCancelled()); assertSame(Status.WAITING, ioFuture.getStatus()); assertTrue(futureResult.setCancelled()); assertSame(Status.CANCELLED, ioFuture.getStatus()); futureResult.setResult("can't set result after cancelled"); } @Test public void failFutureResult() throws Exception { final IOException exception = new IOException("Test exception"); final FutureResult futureResult = new FutureResult(); // getIoFuture returns consistently the same value always final IoFuture ioFuture = futureResult.getIoFuture(); assertSame(ioFuture, futureResult.getIoFuture()); assertSame(Status.WAITING, ioFuture.getStatus()); assertTrue(futureResult.setException(exception)); assertSame(Status.FAILED, ioFuture.getStatus()); assertSame(exception, ioFuture.getException()); assertFalse(futureResult.setResult("can't set result after cancelled")); assertFalse(futureResult.setException(new IOException())); assertFalse(futureResult.setCancelled()); } private static class TestCancellable implements Cancellable { private boolean cancelled = false; @Override public Cancellable cancel() { cancelled = true; return this; } public boolean isCancelled() { return cancelled; } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/IoUtilsTestCase.java000066400000000000000000001251771257016060700244400ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.xnio.AssertReadWrite.assertWrittenMessage; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.net.DatagramSocket; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketException; import java.nio.ByteBuffer; import java.nio.channels.Channel; import java.nio.channels.Channels; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.spi.SelectorProvider; import java.util.Random; import java.util.Set; import java.util.concurrent.CancellationException; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import java.util.logging.Handler; import java.util.logging.LogRecord; import java.util.zip.ZipFile; import java.util.zip.ZipOutputStream; import junit.framework.TestCase; import org.xnio.AbstractIoFuture; import org.xnio.Cancellable; import org.xnio.ChannelListener; import org.xnio.ChannelSource; import org.xnio.FailedIoFuture; import org.xnio.FinishedIoFuture; import org.xnio.FutureResult; import org.xnio.IoFuture; import org.xnio.IoFuture.Status; import org.xnio.IoUtils; import org.xnio.channels.ConnectedStreamChannel; import org.xnio.mock.ConnectedStreamChannelMock; /** * Test for {@link IoUtils}. * * @author David M. Lloyd * @author Flavia Rainone * */ public final class IoUtilsTestCase extends TestCase { public void testDirectExecutor() { final Thread t = Thread.currentThread(); final boolean ok[] = new boolean[1]; IoUtils.directExecutor().execute(new Runnable() { public void run() { assertSame(t, Thread.currentThread()); ok[0] = true; } }); assertTrue(ok[0]); assertNotNull(IoUtils.directExecutor().toString()); } public void testNullExecutor() { IoUtils.nullExecutor().execute(new Runnable() { public void run() { fail("null executor ran task"); } }); assertNotNull(IoUtils.nullExecutor().toString()); } public void testNullCloseable() throws IOException { //nothing should happen IoUtils.nullCloseable().close(); IoUtils.nullCloseable().close(); IoUtils.nullCloseable().close(); IoUtils.nullCloseable().close(); IoUtils.nullCloseable().close(); assertNotNull(IoUtils.nullCloseable().toString()); } public void testNullCancellable() throws IOException { //nothing should happen assertSame(IoUtils.nullCancellable(), IoUtils.nullCancellable().cancel()); assertSame(IoUtils.nullCancellable(), IoUtils.nullCancellable().cancel()); assertSame(IoUtils.nullCancellable(), IoUtils.nullCancellable().cancel()); assertSame(IoUtils.nullCancellable(), IoUtils.nullCancellable().cancel()); assertNotNull(IoUtils.nullCancellable().toString()); } public void testSafeClose() { IoUtils.safeClose(new Closeable() { public void close() throws IOException { throw new RuntimeException("This error should be consumed but logged"); } }); IoUtils.safeClose(new Closeable() { public void close() throws IOException { throw new Error("This error should be consumed but logged"); } }); IoUtils.safeClose(new Closeable() { public void close() throws IOException { throw new IOException("This error should be consumed but logged"); } }); IoUtils.safeClose(new Closeable() { public void close() throws IOException { throw new ClosedChannelException(); // this error should be ignored } }); IoUtils.safeClose((Closeable) null); // should do nothing if target is null } public void testSafeCloseSocket() { IoUtils.safeClose(new Socket() { public void close() throws IOException { throw new RuntimeException("This error should be consumed but logged"); } }); IoUtils.safeClose(new Socket() { public void close() throws IOException { throw new Error("This error should be consumed but logged"); } }); IoUtils.safeClose(new Socket() { public void close() throws IOException { throw new IOException("This error should be consumed but logged"); } }); IoUtils.safeClose(new Socket() { public void close() throws IOException { throw new ClosedChannelException(); // this error should be ignored } }); IoUtils.safeClose((Socket) null); // should do nothing if target is null } public void testSafeCloseDatagramSocket() throws SocketException { IoUtils.safeClose(new DatagramSocket() { public void close() { throw new RuntimeException("This error should be consumed but logged"); } }); IoUtils.safeClose(new DatagramSocket() { public void close() { throw new Error("This error should be consumed but logged"); } }); IoUtils.safeClose((DatagramSocket) null); // should do nothing if target is null } public void testSafeCloseSelector() { IoUtils.safeClose(new TestSelector() { public void close() throws IOException { throw new RuntimeException("This error should be consumed but logged"); } }); IoUtils.safeClose(new TestSelector() { public void close() throws IOException { throw new Error("This error should be consumed but logged"); } }); IoUtils.safeClose(new TestSelector() { public void close() throws IOException { throw new IOException("This error should be consumed but logged"); } }); IoUtils.safeClose(new TestSelector() { public void close() throws IOException { throw new ClosedChannelException(); // this error should be ignored } }); IoUtils.safeClose((Selector) null); // should do nothing if target is null } public void testSafeCloseServerSocket() throws IOException { IoUtils.safeClose(new ServerSocket() { public void close() throws IOException { throw new RuntimeException("This error should be consumed but logged"); } }); IoUtils.safeClose(new ServerSocket() { public void close() throws IOException { throw new Error("This error should be consumed but logged"); } }); IoUtils.safeClose(new ServerSocket() { public void close() throws IOException { throw new IOException("This error should be consumed but logged"); } }); IoUtils.safeClose(new ServerSocket() { public void close() throws IOException { throw new ClosedChannelException(); // this error should be ignored } }); IoUtils.safeClose((ServerSocket) null); // should do nothing if target is null } public void testSafeCloseZipFile() throws IOException { final File file = File.createTempFile("foo", ".zip"); file.deleteOnExit(); final ZipOutputStream zipOutput = new ZipOutputStream(new FileOutputStream(file)); zipOutput.close(); IoUtils.safeClose(new ZipFile(file) { public void close() throws IOException { throw new RuntimeException("This error should be consumed but logged"); } }); IoUtils.safeClose(new ZipFile(file) { public void close() throws IOException { throw new Error("This error should be consumed but logged"); } }); IoUtils.safeClose(new ZipFile(file) { public void close() throws IOException { throw new IOException("This error should be consumed but logged"); } }); IoUtils.safeClose((ZipFile) null); // should do nothing if target is null } public void testSafeCloseHandler() throws IOException { IoUtils.safeClose(new Handler() { public void close() { throw new RuntimeException("This error should be consumed but logged"); } @Override public void publish(LogRecord record) {} @Override public void flush() {} }); IoUtils.safeClose(new Handler() { public void close() { throw new Error("This error should be consumed but logged"); } @Override public void publish(LogRecord record) {} @Override public void flush() {} }); IoUtils.safeClose(new Handler() { public void close() throws SecurityException { throw new SecurityException("This error should be consumed but logged"); } @Override public void publish(LogRecord record) {} @Override public void flush() {} }); IoUtils.safeClose((Handler) null); // should do nothing if target is null } public void testSafeCloseIoFuture() { final TestIoFuture future1 = new TestIoFuture(); IoUtils.safeClose(future1); assertEquals(IoFuture.Status.CANCELLED, future1.getStatus()); final TestIoFuture future2 = new TestIoFuture(); final TestCloseable closeable = new TestCloseable(); assertTrue(future2.setResult(closeable)); assertTrue(closeable.isOpen()); IoUtils.safeClose(future2); assertEquals(IoFuture.Status.DONE, future2.getStatus()); assertFalse(closeable.isOpen()); // should do nothing if target is null IoUtils.safeClose((IoFuture) null); } public void testAttachmentClosingNotifier() { final TestCloseable closeable = new TestCloseable(); assertTrue(closeable.isOpen()); IoUtils.attachmentClosingNotifier().notify(null, closeable); assertFalse(closeable.isOpen()); } public void testClosingNotifier() { final TestCloseable closeable = new TestCloseable(); final TestIoFuture future = new TestIoFuture(); future.addNotifier(IoUtils.closingNotifier(), null); assertTrue(closeable.isOpen()); future.setResult(closeable); assertFalse(closeable.isOpen()); } public void testRunnableNotifier() { final TestRunnable testRunnable = new TestRunnable(); final IoFuture.Notifier notifier = IoUtils.runnableNotifier(testRunnable); assertFalse(testRunnable.isInvoked()); notifier.notify(null, null); assertTrue(testRunnable.isInvoked()); } public void testResultNotifier() throws Exception { final FutureResult futureResult1 = new FutureResult(); final FutureResult futureResult2 = new FutureResult(); final FutureResult futureResult3 = new FutureResult(); final TestIoFuture future1 = new TestIoFuture(); final TestIoFuture future2 = new TestIoFuture(); final TestIoFuture future3 = new TestIoFuture(); future1.addNotifier(IoUtils.resultNotifier(), futureResult1); future2.addNotifier(IoUtils.resultNotifier(), futureResult2); future3.addNotifier(IoUtils.resultNotifier(), futureResult3); future1.cancel(); assertSame(Status.CANCELLED, futureResult1.getIoFuture().getStatus()); final IOException exception = new IOException("Test exception"); future2.setException(exception); assertSame(Status.FAILED, futureResult2.getIoFuture().getStatus()); assertSame(exception, futureResult2.getIoFuture().getException()); final Closeable result = new TestCloseable(); future3.setResult(result); assertSame(Status.DONE, futureResult3.getIoFuture().getStatus()); assertSame(result, futureResult3.getIoFuture().get()); } public void testChannelListenerNotifier() { final ConnectedStreamChannelMock channel = new ConnectedStreamChannelMock(); final TestChannelListener channelListener = new TestChannelListener(); final TestIoFuture future1 = new TestIoFuture(); future1.>addNotifier( IoUtils.channelListenerNotifier(), channelListener); final TestIoFuture future2 = new TestIoFuture(); future2.>addNotifier( IoUtils.channelListenerNotifier(), channelListener); final TestIoFuture future3 = new TestIoFuture(); future3.>addNotifier( IoUtils.channelListenerNotifier(), channelListener); future1.cancel(); future2.setException(new IOException()); assertFalse(channelListener.isInvoked()); future3.setResult(channel); assertTrue(channelListener.isInvoked()); assertSame(channel, channelListener.getChannel()); } public void testIoFutureWrapper() throws Exception { // test future wrapper with ioFuture1, which will have a value successfully set final TestIoFuture ioFuture1 = new TestIoFuture(); final Future future1 = IoUtils.getFuture(ioFuture1); assertFalse(future1.isCancelled()); assertFalse(future1.isDone()); assertNotNull(future1.toString()); final FutureValueRetriever futureValueRetriever1 = new FutureValueRetriever(future1); final FutureValueRetriever futureValueRetriever2 = new FutureValueRetriever(future1, 50, TimeUnit.MILLISECONDS); final Thread retrieverThread1 = new Thread(futureValueRetriever1); final Thread retrieverThread2 = new Thread(futureValueRetriever2); retrieverThread1.start(); retrieverThread2.start(); retrieverThread1.join(60); retrieverThread2.join(60); assertTrue(retrieverThread1.isAlive()); assertFalse(retrieverThread2.isAlive());; assertNotNull(futureValueRetriever2.getTimeoutException()); ioFuture1.setResult("future1"); retrieverThread1.join(); assertSame("future1", futureValueRetriever1.getFutureValue()); assertFalse(future1.isCancelled()); assertTrue(future1.isDone()); assertFalse(future1.cancel(true)); // test future wrapper with ioFuture2, which will be canceled, by a call to ioFuture2.cancel() final TestIoFuture ioFuture2 = new TestIoFuture(); final Future future2 = IoUtils.getFuture(ioFuture2); assertFalse(future2.isCancelled()); assertFalse(future2.isDone()); assertNotNull(future2.toString()); final FutureValueRetriever futureValueRetriever3 = new FutureValueRetriever(future2); final FutureValueRetriever futureValueRetriever4 = new FutureValueRetriever(future2, 1, TimeUnit.DAYS); final Thread retrieverThread3 = new Thread(futureValueRetriever3); final Thread retrieverThread4 = new Thread(futureValueRetriever4); retrieverThread3.start(); retrieverThread4.start(); retrieverThread3.join(60); retrieverThread4.join(60); assertTrue(retrieverThread3.isAlive()); assertTrue(retrieverThread4.isAlive()); ioFuture2.cancel(); retrieverThread3.join(); retrieverThread4.join(); assertNotNull(futureValueRetriever3.getCancellationException()); assertNotNull(futureValueRetriever4.getCancellationException()); assertTrue(future2.isCancelled()); assertFalse(future2.isDone()); assertTrue(future2.cancel(false)); // test future wrapper with ioFuture3, which will be canceled, by a call to the future wrapper final TestIoFuture ioFuture3 = new TestIoFuture(); final Future future3 = IoUtils.getFuture(ioFuture3); assertFalse(future3.isCancelled()); assertFalse(future3.isDone()); assertNotNull(future3.toString()); final FutureValueRetriever futureValueRetriever5 = new FutureValueRetriever(future3); final FutureValueRetriever futureValueRetriever6 = new FutureValueRetriever(future3, 10, TimeUnit.NANOSECONDS); final Thread retrieverThread5 = new Thread(futureValueRetriever5); final Thread retrieverThread6 = new Thread(futureValueRetriever6); retrieverThread5.start(); retrieverThread6.start(); retrieverThread5.join(60); retrieverThread6.join(60); assertTrue(retrieverThread5.isAlive()); assertFalse(retrieverThread6.isAlive()); assertNotNull(futureValueRetriever6.getTimeoutException()); assertTrue(future3.cancel(true)); retrieverThread5.join(); assertNotNull(futureValueRetriever5.getCancellationException()); assertTrue(future3.isCancelled()); assertFalse(future3.isDone()); assertTrue(future3.cancel(true)); // test future wrapper with ioFuture3, which will be canceled, by a call to the future wrapper final TestIoFuture ioFuture4 = new TestIoFuture(); final Future future4 = IoUtils.getFuture(ioFuture4); assertFalse(future4.isCancelled()); assertFalse(future4.isDone()); assertNotNull(future4.toString()); final FutureValueRetriever futureValueRetriever7 = new FutureValueRetriever(future4); final FutureValueRetriever futureValueRetriever8 = new FutureValueRetriever(future4, 1, TimeUnit.MINUTES); final Thread retrieverThread7 = new Thread(futureValueRetriever7); final Thread retrieverThread8 = new Thread(futureValueRetriever8); retrieverThread7.start(); retrieverThread8.start(); retrieverThread7.join(60); retrieverThread8.join(60); assertTrue(retrieverThread7.isAlive()); assertTrue(retrieverThread8.isAlive()); final IOException failure = new IOException("Test exception"); ioFuture4.setException(failure); retrieverThread7.join(); retrieverThread8.join(); assertSame(failure, futureValueRetriever7.getFailure()); assertSame(failure, futureValueRetriever8.getFailure()); assertFalse(future4.isCancelled()); assertFalse(future4.isDone()); assertFalse(future4.cancel(false)); } public void testAwaitAll() throws InterruptedException { final TestIoFuture future1 = new TestIoFuture(); final TestIoFuture future2 = new TestIoFuture(); final TestIoFuture future3 = new TestIoFuture(); final TestIoFuture future4 = new TestIoFuture(); final TestIoFuture future5 = new TestIoFuture(); final Awaiter awaiterTask1 = new Awaiter(future1, future2, future3, future4, future5); final Awaiter awaiterTask2 = new Awaiter(future1, future3, future4); final Awaiter awaiterTask3 = new Awaiter(future1, future2, future4, future5); final Awaiter awaiterTask4 = new Awaiter(true, future1, future3, future4); final Awaiter awaiterTask5 = new Awaiter(); final Thread awaiterThread1 = new Thread(awaiterTask1); final Thread awaiterThread2 = new Thread(awaiterTask2); final Thread awaiterThread3 = new Thread(awaiterTask3); final Thread awaiterThread4 = new Thread(awaiterTask4); final Thread awaiterThread5 = new Thread(awaiterTask5); awaiterThread1.start(); awaiterThread2.start(); awaiterThread3.start(); awaiterThread4.start(); awaiterThread5.start(); awaiterThread1.join(100); awaiterThread2.join(100); awaiterThread3.join(100); awaiterThread4.join(100); awaiterThread5.join(); assertTrue(awaiterThread1.isAlive()); assertTrue(awaiterThread2.isAlive()); assertTrue(awaiterThread3.isAlive()); assertTrue(awaiterThread4.isAlive()); future2.setResult(null); future3.cancel(); awaiterThread1.join(100); awaiterThread2.join(100); awaiterThread3.join(100); awaiterThread4.join(100); assertTrue(awaiterThread1.isAlive()); assertTrue(awaiterThread2.isAlive()); assertTrue(awaiterThread3.isAlive()); assertTrue(awaiterThread4.isAlive()); awaiterThread3.interrupt(); awaiterThread4.interrupt(); awaiterThread4.join(); assertNotNull(awaiterTask4.getInterruptedException()); future1.setResult(null); future4.setException(new IOException()); awaiterThread1.join(100); awaiterThread3.join(100); awaiterThread2.join(); assertTrue(awaiterThread1.isAlive()); assertTrue(awaiterThread3.isAlive()); future5.setResult(null); awaiterThread1.join(); awaiterThread3.join(); assertNull(awaiterTask3.getInterruptedException()); } public void testCast() throws Exception { // future with result set final TestIoFuture future1 = new TestIoFuture(); final IoFuture castFuture1 = IoUtils.cast(future1, String.class); assertSame(Status.WAITING, castFuture1.getStatus()); assertSame(Status.WAITING, castFuture1.await(10, TimeUnit.MICROSECONDS)); assertSame(Status.WAITING, castFuture1.awaitInterruptibly(1, TimeUnit.MICROSECONDS)); future1.setResult("test"); assertSame(Status.DONE, castFuture1.getStatus()); assertSame(Status.DONE, castFuture1.await(10, TimeUnit.MICROSECONDS)); assertSame(Status.DONE, castFuture1.awaitInterruptibly(1, TimeUnit.MICROSECONDS)); assertSame(Status.DONE, castFuture1.await()); assertSame(Status.DONE, castFuture1.awaitInterruptibly()); assertSame("test", castFuture1.get()); assertSame("test", castFuture1.getInterruptibly()); final TestCloseable closeable1 = new TestCloseable(); castFuture1.addNotifier(IoUtils.attachmentClosingNotifier(), closeable1); assertFalse(closeable1.isOpen()); // cancelled future final TestIoFuture future2 = new TestIoFuture(); final IoFuture castFuture2 = IoUtils.cast(future2, String.class); final TestCloseable closeable2 = new TestCloseable(); castFuture2.addNotifier(IoUtils.attachmentClosingNotifier(), closeable2); assertTrue(closeable2.isOpen()); assertSame(Status.WAITING, castFuture2.getStatus()); assertSame(Status.WAITING, castFuture2.await(10, TimeUnit.MICROSECONDS)); assertSame(Status.WAITING, castFuture2.awaitInterruptibly(1, TimeUnit.MICROSECONDS)); castFuture2.cancel(); assertSame(Status.CANCELLED, castFuture2.getStatus()); assertSame(Status.CANCELLED, castFuture2.await(10, TimeUnit.MICROSECONDS)); assertSame(Status.CANCELLED, castFuture2.awaitInterruptibly(1, TimeUnit.MICROSECONDS)); assertSame(Status.CANCELLED, castFuture2.await()); assertSame(Status.CANCELLED, castFuture2.awaitInterruptibly()); assertFalse(closeable2.isOpen()); CancellationException expected = null; try { castFuture2.get(); } catch (CancellationException e) { expected = e; } assertNotNull(expected); expected = null; try { castFuture2.getInterruptibly(); } catch (CancellationException e) { expected = e; } assertNotNull(expected); // failed future final TestIoFuture future3 = new TestIoFuture(); final IoFuture castFuture3 = IoUtils.cast(future3, String.class); assertSame(Status.WAITING, castFuture3.getStatus()); assertSame(Status.WAITING, castFuture3.await(10, TimeUnit.MICROSECONDS)); assertSame(Status.WAITING, castFuture3.awaitInterruptibly(1, TimeUnit.MICROSECONDS)); final IOException failure = new IOException("Test exception"); future3.setException(failure); assertSame(Status.FAILED, castFuture3.getStatus()); assertSame(Status.FAILED, castFuture3.await(10, TimeUnit.MICROSECONDS)); assertSame(Status.FAILED, castFuture3.awaitInterruptibly(1, TimeUnit.MICROSECONDS)); assertSame(Status.FAILED, castFuture3.await()); assertSame(Status.FAILED, castFuture3.awaitInterruptibly()); assertSame(failure, castFuture3.getException()); } public void testSafeShutdownReads() { final ChannelMock channel1 = new ChannelMock(); final ChannelMock channel2 = new ChannelMock(); IoUtils.safeShutdownReads(channel1); assertTrue(channel1.isShutdownReads()); channel2.throwExceptionOnShutdownReads(); IoUtils.safeShutdownReads(channel2); assertFalse(channel2.isShutdownReads()); IoUtils.safeShutdownReads(null); // should just ignore } public void testTransfer() throws IOException { final ConnectedStreamChannelMock sourceChannel = new ConnectedStreamChannelMock(); final ConnectedStreamChannelMock sinkChannel = new ConnectedStreamChannelMock(); sinkChannel.enableWrite(false); sourceChannel.setReadData("a kinda big text to transfer from source to sink"); sourceChannel.enableRead(true); final ByteBuffer throughBuffer = ByteBuffer.allocate(10); assertEquals(0, IoUtils.transfer(sourceChannel, 50, throughBuffer, sinkChannel)); assertWrittenMessage(sinkChannel); sinkChannel.enableWrite(true); sinkChannel.write(throughBuffer); assertEquals(38, IoUtils.transfer(sourceChannel, 60, throughBuffer, sinkChannel)); assertWrittenMessage(sinkChannel, "a kinda big text to transfer from source to sink"); } public void testManagerNotifier() throws Exception { // add manager notifier to a future that will be cancelled final TestIoFuture future1 = new TestIoFuture(); final FutureResult manager1 = new FutureResult(); final FutureResult manager2 = new FutureResult(); final IoFuture.Notifier> notifier1 = IoUtils.getManagerNotifier(); final IoFuture.Notifier> notifier2 = IoUtils.getManagerNotifier(); future1.addNotifier(notifier1, manager1); future1.cancel(); future1.addNotifier(notifier2, manager2); assertSame(Status.CANCELLED, manager1.getIoFuture().getStatus()); assertSame(Status.CANCELLED, manager2.getIoFuture().getStatus()); // add manager notifier to a future that will fail final IOException exception = new IOException("Test exception"); final TestIoFuture future2 = new TestIoFuture(); final FutureResult manager3 = new FutureResult(); final FutureResult manager4 = new FutureResult(); final IoFuture.Notifier> notifier3 = IoUtils.getManagerNotifier(); final IoFuture.Notifier> notifier4 = IoUtils.getManagerNotifier(); future2.addNotifier(notifier3, manager3); future2.setException(exception); future2.addNotifier(notifier4, manager4); assertSame(Status.FAILED, manager3.getIoFuture().getStatus()); assertSame(exception, manager3.getIoFuture().getException()); assertSame(Status.FAILED, manager4.getIoFuture().getStatus()); assertSame(exception, manager4.getIoFuture().getException()); // add manager notifier to a future that will have its value set final Channel result = new ConnectedStreamChannelMock(); final TestIoFuture future3 = new TestIoFuture(); final FutureResult manager5 = new FutureResult(); final FutureResult manager6 = new FutureResult(); final IoFuture.Notifier> notifier5 = IoUtils.getManagerNotifier(); final IoFuture.Notifier> notifier6 = IoUtils.getManagerNotifier(); future3.addNotifier(notifier5, manager5); future3.setResult(result); future3.addNotifier(notifier6, manager6); assertSame(Status.DONE, manager5.getIoFuture().getStatus()); assertSame(result, manager5.getIoFuture().get()); assertSame(Status.DONE, manager6.getIoFuture().getStatus()); assertSame(result, manager6.getIoFuture().get()); } public void testRetryingChannelSource() throws Exception { final TestChannelSource testChannelSource1 = new TestChannelSource(0); final TestChannelSource testChannelSource2 = new TestChannelSource(3); final TestChannelSource testChannelSource3 = new TestChannelSource(8); final ChannelSource testChannelSource4 = new ChannelSource() { @Override public IoFuture open(ChannelListener openListener) { return new TestIoFuture().cancel(); } }; final ChannelSource retryingChannelSource1 = IoUtils.getRetryingChannelSource(testChannelSource1, 5); final ChannelSource retryingChannelSource2 = IoUtils.getRetryingChannelSource(testChannelSource2, 5); final ChannelSource retryingChannelSource3 = IoUtils.getRetryingChannelSource(testChannelSource3, 5); final ChannelSource retryingChannelSource4 = IoUtils.getRetryingChannelSource(testChannelSource4, 5); final TestOpenListener openListener1 = new TestOpenListener(); final TestOpenListener openListener2 = new TestOpenListener(); final TestOpenListener openListener3 = new TestOpenListener(); final TestOpenListener openListener4 = new TestOpenListener(); final IoFuture future1 = retryingChannelSource1.open(openListener1); final IoFuture future2 = retryingChannelSource2.open(openListener2); final IoFuture future3 = retryingChannelSource3.open(openListener3); final IoFuture future4 = retryingChannelSource4.open(openListener4); assertSame(Status.DONE, future1.getStatus()); assertNotNull(future1.get()); assertTrue(openListener1.isInvoked()); assertSame(future1.get(), openListener1.getChannel()); assertSame(Status.DONE, future2.getStatus()); assertNotNull(future2.get()); assertTrue(openListener2.isInvoked()); assertSame(future2.get(), openListener2.getChannel()); assertSame(Status.FAILED, future3.getStatus()); assertNotNull(future3.getException()); assertFalse(openListener3.isInvoked()); assertSame(Status.CANCELLED, future4.getStatus()); assertFalse(openListener3.isInvoked()); IllegalArgumentException expected = null; try { IoUtils.getRetryingChannelSource(testChannelSource1, 0); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { IoUtils.getRetryingChannelSource(testChannelSource1, -1); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { IoUtils.getRetryingChannelSource(testChannelSource1, -9); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } public void testClosingCancellable() { final TestCloseable closeable = new TestCloseable(); final Cancellable closingCancellable = IoUtils.closingCancellable(closeable); assertNotNull(closingCancellable); assertTrue(closeable.isOpen()); assertSame(closingCancellable, closingCancellable.cancel()); assertFalse(closeable.isOpen()); } public void testThreadLocalRandom() throws Exception { final Random random = IoUtils.getThreadLocalRandom(); random.nextFloat(); random.nextInt(); final FutureResult expectedExceptionFuture = new FutureResult(); final Thread thread = new Thread(new Runnable() { public void run() { try { random.nextInt(); expectedExceptionFuture.setResult(null); } catch (IllegalStateException e) { expectedExceptionFuture.setResult(e); } } }); thread.start(); thread.join(); assertNotNull(expectedExceptionFuture.getIoFuture().get()); final ByteArrayOutputStream byteOutput = new ByteArrayOutputStream(); final ObjectOutput objectOutput = new ObjectOutputStream(new BufferedOutputStream(byteOutput)); objectOutput.writeObject(random); objectOutput.close(); final ObjectInput objectInput = new ObjectInputStream(new BufferedInputStream(new ByteArrayInputStream(byteOutput.toByteArray()))); final Random deserializedRandom = (Random) objectInput.readObject(); assertNotNull(deserializedRandom); } public void testTransferThroughBuffer() throws IOException{ byte[] bytes = "This bytes".getBytes(); ByteArrayInputStream in = new ByteArrayInputStream(bytes); ByteArrayOutputStream out = new ByteArrayOutputStream(); ByteBuffer buffer = ByteBuffer.allocate(16); assertEquals(bytes.length, IoUtils.transfer(Channels.newChannel(in), bytes.length, buffer, Channels.newChannel(out))); assertFalse(buffer.hasRemaining()); } private static abstract class TestSelector extends Selector { @Override public boolean isOpen() { return false; } @Override public SelectorProvider provider() { return null; } @Override public Set keys() { return null; } @Override public Set selectedKeys() { return null; } @Override public int selectNow() throws IOException { return 0; } @Override public int select(long timeout) throws IOException { return 0; } @Override public int select() throws IOException { return 0; } @Override public Selector wakeup() { return null; } } private static class TestIoFuture extends AbstractIoFuture { @Override public boolean setResult(T result) { return super.setResult(result); } @Override public boolean setException(IOException exception) { return super.setException(exception); } @Override public TestIoFuture cancel() { super.cancel(); setCancelled(); return this; } } private static class TestCloseable implements Closeable { private boolean open = true; public void close() { open = false; } public boolean isOpen() { return open; } } private static class TestRunnable implements Runnable { private boolean invoked = false; public void run() { invoked = true; } public boolean isInvoked() { return invoked; } } private static class TestChannelListener implements ChannelListener { private boolean invoked = false; private ConnectedStreamChannel channel; @Override public void handleEvent(ConnectedStreamChannel c) { invoked = true; channel = c; } public boolean isInvoked() { return invoked; } public ConnectedStreamChannel getChannel() { return channel; } } private static class FutureValueRetriever implements Runnable { private final Future future; private final long timeout; private final TimeUnit timeoutUnit; private volatile T result; private TimeoutException timeoutException = null; private CancellationException cancellationException = null; private IOException failure; public FutureValueRetriever(Future f) { this(f, -1, null); } public FutureValueRetriever(Future f, long t, TimeUnit tu) { future = f; timeout = t; timeoutUnit = tu; } public void run() { try { if (timeoutUnit == null) { result = future.get(); } else { result = future.get(timeout, timeoutUnit); } } catch (InterruptedException e) { throw new RuntimeException(e); } catch (ExecutionException e) { if (e.getCause() instanceof IOException) { failure = (IOException) e.getCause(); } else { throw new RuntimeException(e); } } catch (TimeoutException e) { timeoutException = e; } catch (CancellationException e) { cancellationException = e; } } public T getFutureValue() { return result; } public TimeoutException getTimeoutException() { return timeoutException; } public CancellationException getCancellationException() { return cancellationException; } public IOException getFailure() { return failure; } } private class Awaiter implements Runnable { private boolean interruptibly; private IoFuture[] futures; private InterruptedException exception; public Awaiter(IoFuture... f) { this(false, f); } public Awaiter(boolean i, IoFuture... f) { futures = f; interruptibly = i; } public void run() { try { if (interruptibly) { IoUtils.awaitAllInterruptibly(futures); } else { IoUtils.awaitAll(futures); } } catch (InterruptedException e) { e.printStackTrace(); exception = e; } finally {} } public InterruptedException getInterruptedException() { return exception; } } private static class ChannelMock extends ConnectedStreamChannelMock { private boolean throwExceptionOnShutdownReads = false; public void throwExceptionOnShutdownReads() { throwExceptionOnShutdownReads = true; } @Override public void shutdownReads() throws IOException { if (throwExceptionOnShutdownReads) { throw new IOException("Test exception"); } super.shutdownReads(); } } private static class TestChannelSource implements ChannelSource { public int count; public TestChannelSource(int numberOfFailures) { count = numberOfFailures; } @Override public IoFuture open(ChannelListener openListener) { if (count == 0) { IoFuture future = new FinishedIoFuture(new ConnectedStreamChannelMock()); try { openListener.handleEvent(future.get()); } catch (CancellationException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } return future; } count --; return new FailedIoFuture(new IOException("Test exception")); } } private static class TestOpenListener implements ChannelListener { private boolean invoked; private ConnectedStreamChannelMock channel; @Override public void handleEvent(ConnectedStreamChannelMock c) { invoked = true; channel = c; } public boolean isInvoked() { return invoked; } public ConnectedStreamChannelMock getChannel() { return channel; } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/LocalSocketAddressTestCase.java000066400000000000000000000034621257016060700265510ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import org.junit.Test; /** * Test for {@link LocalSocketAddress}. * * @author Flavia Rainone * */ public class LocalSocketAddressTestCase { @Test public void test1() { final LocalSocketAddress socketAddress = new LocalSocketAddress("name"); assertEquals("name", socketAddress.getName()); assertTrue(socketAddress.toString().contains("name")); } @Test public void test2() { final LocalSocketAddress socketAddress = new LocalSocketAddress("address"); assertEquals("address", socketAddress.getName()); assertTrue(socketAddress.toString().contains("address")); } @Test public void testNull() { IllegalArgumentException expected = null; try { new LocalSocketAddress(null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/OptionMapTestCase.java000066400000000000000000000545111257016060700247470ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.Map; import java.util.Properties; import java.util.Set; import org.junit.Test; /** * Test for {@link OptionMap}. * * @author Flavia Rainone * */ public class OptionMapTestCase { // a few extra options that will be used with options contained in Options, for testing OptionMap public static final Option LONG_OPTION = Option.simple(OptionMapTestCase.class, "LONG_OPTION", Long.class); public static final Option ABSENT_LONG_OPTION = Option.simple(OptionMapTestCase.class, "ABSENT_LONG_OPTION", Long.class); public static final Option> BOOLEAN_SEQUENCE_OPTION = Option.sequence(OptionMapTestCase.class, "BOOLEAN_SEQUENCE_OPTION", Boolean.class); public static final Option> INT_SEQUENCE_OPTION = Option.sequence(OptionMapTestCase.class, "INT_SEQUENCE_OPTION", Integer.class); public static final Option> LONG_SEQUENCE_OPTION = Option.sequence(OptionMapTestCase.class, "LONG_SEQUENCE_OPTION", Long.class); @Test public void emptyOptionMap() { // check size assertEquals(0, OptionMap.EMPTY.size()); // check iterator final Iterator> iterator = OptionMap.EMPTY.iterator(); assertNotNull(iterator); assertFalse(iterator.hasNext()); assertNotNull(OptionMap.EMPTY.toString()); } // call only if map does not contain ALLOW_BLOCKING, FILE_ACCESS, MAX_INBOUND_MESSAGE_SIZE, and STACK_SIZE private void checkAbsentOptions(final OptionMap optionMap) { assertNull(optionMap.get(Options.ALLOW_BLOCKING)); assertEquals(false, optionMap.get(Options.ALLOW_BLOCKING, false)); assertEquals(true, optionMap.get(Options.ALLOW_BLOCKING, true)); assertNull(optionMap.get(Options.FILE_ACCESS)); assertSame(FileAccess.READ_ONLY, optionMap.get(Options.FILE_ACCESS, FileAccess.READ_ONLY)); assertSame(FileAccess.READ_WRITE, optionMap.get(Options.FILE_ACCESS, FileAccess.READ_WRITE)); assertNull(optionMap.get(Options.MAX_INBOUND_MESSAGE_SIZE)); assertEquals(30000, optionMap.get(Options.MAX_INBOUND_MESSAGE_SIZE, 30000)); assertEquals(150, optionMap.get(Options.MAX_INBOUND_MESSAGE_SIZE, 150)); assertNull(optionMap.get(Options.STACK_SIZE)); assertEquals(100, optionMap.get(Options.STACK_SIZE, 100)); assertEquals(200, optionMap.get(Options.STACK_SIZE, 200)); } @Test public void unitaryOptionMap() { final OptionMap optionMap = OptionMap.create(Options.WORKER_ESTABLISH_WRITING, true); assertNotNull(optionMap); // check size assertEquals(1, optionMap.size()); // check iterator final Iterator> iterator = optionMap.iterator(); assertNotNull(iterator); assertTrue(iterator.hasNext()); assertEquals(Options.WORKER_ESTABLISH_WRITING, iterator.next()); assertFalse(iterator.hasNext()); // check get methods assertEquals(true, optionMap.get(Options.WORKER_ESTABLISH_WRITING)); assertEquals(true, optionMap.get(Options.WORKER_ESTABLISH_WRITING, false)); assertEquals(true, optionMap.get(Options.WORKER_ESTABLISH_WRITING, true)); checkAbsentOptions(optionMap); // check toString String optionMapToString = optionMap.toString(); assertNotNull(optionMapToString); assertTrue(optionMapToString.contains("Options.WORKER_ESTABLISH_WRITING")); assertTrue(optionMapToString.contains("true")); } @Test public void optionMapWithTwoOptions() { final OptionMap optionMap = OptionMap.create(Options.WORKER_ESTABLISH_WRITING, false, Options.WORKER_NAME, "WORKER1"); assertNotNull(optionMap); // check size assertEquals(2, optionMap.size()); // check iterator final Iterator> iterator = optionMap.iterator(); assertNotNull(iterator); assertTrue(iterator.hasNext()); final Option firstOption = iterator.next(); assertTrue(iterator.hasNext()); if (firstOption == Options.WORKER_ESTABLISH_WRITING) { assertEquals(Options.WORKER_NAME, iterator.next()); } else if (firstOption == Options.WORKER_NAME) { assertEquals(Options.WORKER_ESTABLISH_WRITING, iterator.next()); } else { fail("Unexpected option found in map: "+ firstOption); } assertFalse(iterator.hasNext()); // check get methods assertEquals(false, optionMap.get(Options.WORKER_ESTABLISH_WRITING)); assertEquals(false, optionMap.get(Options.WORKER_ESTABLISH_WRITING, false)); assertEquals(false, optionMap.get(Options.WORKER_ESTABLISH_WRITING, true)); assertEquals("WORKER1", optionMap.get(Options.WORKER_NAME)); assertEquals("WORKER1", optionMap.get(Options.WORKER_NAME, "")); assertEquals("WORKER1", optionMap.get(Options.WORKER_NAME, "WORKER3")); checkAbsentOptions(optionMap); // check toString String optionMapToString = optionMap.toString(); assertNotNull(optionMapToString); assertTrue(optionMapToString.contains("Options.WORKER_ESTABLISH_WRITING")); assertTrue(optionMapToString.contains("false")); assertTrue(optionMapToString.contains("Options.WORKER_NAME")); assertTrue(optionMapToString.contains("WORKER1")); } @SuppressWarnings("deprecation") @Test public void checkOptionMapCreatedByBuilder() throws Exception { final OptionMap.Builder optionMapBuilder = OptionMap.builder(); assertNotNull(optionMapBuilder); optionMapBuilder.parse(Options.STACK_SIZE, "900"); optionMapBuilder.parse(Options.ALLOW_BLOCKING, "false", getClass().getClassLoader()); final Properties properties = new Properties(); properties.put("+ADD+." + Options.CLOSE_ABORT, "true"); properties.put("--."+ Options.RECEIVE_BUFFER, "50000"); properties.put("--." + Options.SSL_PEER_PORT, "989"); properties.put("+ADD." + Options.SEND_BUFFER, "20000"); properties.put("+ADD+." + Options.SSL_PEER_PORT, 990); // numbers are not parsed, only strings! properties.put("--." + Options.CLOSE_ABORT, "false"); properties.put("+ADD+." + Options.CORK, "ture"); // typo that will cause an illegal argument exception on parsing properties.put("+ADD+." + Options.SSL_APPLICATION_BUFFER_REGION_SIZE, "cant parse this"); // won't be able to read this value properties.put("--." + Options.SSL_APPLICATION_BUFFER_SIZE, "cant parse this"); // won't be able to read this value optionMapBuilder.parseAll(properties, "--"); optionMapBuilder.parseAll(properties, "+ADD+.", getClass().getClassLoader()); optionMapBuilder.parseAll(properties, "-ADD-."); optionMapBuilder.parseAll(properties, "ADD", getClass().getClassLoader()); optionMapBuilder.set(Options.FILE_ACCESS, FileAccess.READ_ONLY); optionMapBuilder.set(Options.MULTICAST, true); optionMapBuilder.set(Options.THREAD_PRIORITY, 5); optionMapBuilder.set(LONG_OPTION, 24352436); optionMapBuilder.setSequence(Options.SASL_DISALLOWED_MECHANISMS, "FooMechanism"); optionMapBuilder.setSequence(BOOLEAN_SEQUENCE_OPTION, new boolean[]{ (Boolean) true, (Boolean) false, (Boolean) true, (Boolean) false}); optionMapBuilder.setSequence(INT_SEQUENCE_OPTION, new int[]{11, 13, 17, 19, 23}); optionMapBuilder.setSequence(LONG_SEQUENCE_OPTION, new long[]{300l, 400l, 500l}); final Map, Integer> map = new HashMap, Integer>(); map.put(Options.WORKER_READ_THREADS, 10); map.put(Options.WORKER_WRITE_THREADS, 10); optionMapBuilder.add(map); // use builder to create option map final OptionMap optionMap = optionMapBuilder.getMap(); assertNotNull(optionMap); assertEquals(optionMap, optionMapBuilder.getMap()); assertEquals(optionMapBuilder.getMap(), optionMap); // check size assertEquals(16, optionMap.size()); // check iterator final Set> options = new HashSet>(); options.add(Options.STACK_SIZE); options.add(Options.ALLOW_BLOCKING); options.add(Options.CLOSE_ABORT); options.add(Options.RECEIVE_BUFFER); options.add(Options.SSL_PEER_PORT); options.add(Options.CORK); options.add(Options.FILE_ACCESS); options.add(Options.MULTICAST); options.add(Options.THREAD_PRIORITY); options.add(LONG_OPTION); options.add(Options.SASL_DISALLOWED_MECHANISMS); options.add(BOOLEAN_SEQUENCE_OPTION); options.add(INT_SEQUENCE_OPTION); options.add(LONG_SEQUENCE_OPTION); options.add(Options.WORKER_READ_THREADS); options.add(Options.WORKER_WRITE_THREADS); final Set> optionsCopy = new HashSet>(options); final Iterator> iterator = optionMap.iterator(); assertNotNull(iterator); assertTrue(iterator.hasNext()); while(iterator.hasNext()) { Option option = iterator.next(); assertFalse("Unexpected option found: " + option, optionsCopy.isEmpty()); assertTrue("Unexpected option found: " + option, optionsCopy.remove(option)); } assertTrue(optionsCopy.isEmpty()); assertFalse(iterator.hasNext()); // check get methods assertEquals(900l, (long) optionMap.get(Options.STACK_SIZE)); assertEquals(900l, (long) optionMap.get(Options.STACK_SIZE), 800l); assertEquals(false, optionMap.get(Options.ALLOW_BLOCKING)); assertEquals(false, optionMap.get(Options.ALLOW_BLOCKING, true)); assertEquals(true, optionMap.get(Options.CLOSE_ABORT)); assertEquals(true, optionMap.get(Options.CLOSE_ABORT, true)); assertEquals(50000,(int) optionMap.get(Options.RECEIVE_BUFFER)); assertEquals(50000,(int) optionMap.get(Options.RECEIVE_BUFFER, 0)); assertEquals(989,(int) optionMap.get(Options.SSL_PEER_PORT)); assertEquals(989,(int) optionMap.get(Options.SSL_PEER_PORT, 200)); assertFalse(optionMap.get(Options.CORK)); assertFalse(optionMap.get(Options.CORK, true)); assertEquals(FileAccess.READ_ONLY, optionMap.get(Options.FILE_ACCESS)); assertEquals(FileAccess.READ_ONLY, optionMap.get(Options.FILE_ACCESS, FileAccess.READ_WRITE)); assertEquals(true, optionMap.get(Options.MULTICAST)); assertEquals(true, optionMap.get(Options.MULTICAST, false)); assertEquals(5, (int) optionMap.get(Options.THREAD_PRIORITY)); assertEquals(5, optionMap.get(Options.THREAD_PRIORITY, 2)); assertEquals(24352436, (long) optionMap.get(LONG_OPTION)); assertEquals(24352436, optionMap.get(LONG_OPTION, Long.MAX_VALUE)); assertEquals(Sequence.of("FooMechanism"), optionMap.get(Options.SASL_DISALLOWED_MECHANISMS)); assertEquals(Sequence.of("FooMechanism"), optionMap.get(Options.SASL_DISALLOWED_MECHANISMS, Sequence.empty())); assertEquals(Sequence.of(true, false, true, false), optionMap.get(BOOLEAN_SEQUENCE_OPTION)); assertEquals(Sequence.of(true, false, true, false), optionMap.get(BOOLEAN_SEQUENCE_OPTION, Sequence.of(true, true))); assertEquals(Sequence.of(11, 13, 17, 19, 23), optionMap.get(INT_SEQUENCE_OPTION)); assertEquals(Sequence.of(11, 13, 17, 19, 23), optionMap.get(INT_SEQUENCE_OPTION, Sequence.of(1, 2, 3, 4, 5))); assertEquals(Sequence.of(300l, 400l, 500l), optionMap.get(LONG_SEQUENCE_OPTION)); assertEquals(Sequence.of(300l, 400l, 500l), optionMap.get(LONG_SEQUENCE_OPTION, Sequence.empty())); assertEquals(10, (int) optionMap.get(Options.WORKER_READ_THREADS)); assertEquals(10, optionMap.get(Options.WORKER_READ_THREADS, 30)); assertEquals(10, (int) optionMap.get(Options.WORKER_WRITE_THREADS)); assertEquals(10, optionMap.get(Options.WORKER_WRITE_THREADS, 20)); // check absent options assertNull(optionMap.get(Options.BROADCAST)); assertEquals(false, optionMap.get(Options.BROADCAST, false)); assertEquals(true, optionMap.get(Options.BROADCAST, true)); assertNull(optionMap.get(Options.WORKER_NAME)); assertSame("1", optionMap.get(Options.WORKER_NAME, "1")); assertSame("MAIN_HOST", optionMap.get(Options.WORKER_NAME, "MAIN_HOST")); assertNull(optionMap.get(Options.MAX_OUTBOUND_MESSAGE_SIZE)); assertEquals(1000, optionMap.get(Options.MAX_OUTBOUND_MESSAGE_SIZE, 1000)); assertEquals(7890, optionMap.get(Options.MAX_OUTBOUND_MESSAGE_SIZE, 7890)); assertNull(optionMap.get(ABSENT_LONG_OPTION)); assertEquals(1l, optionMap.get(ABSENT_LONG_OPTION, 1l)); assertEquals(0l, optionMap.get(ABSENT_LONG_OPTION, 0l)); assertNull(optionMap.get(Options.SSL_APPLICATION_BUFFER_REGION_SIZE)); assertEquals(500, optionMap.get(Options.SSL_APPLICATION_BUFFER_REGION_SIZE, 500)); assertEquals(700, optionMap.get(Options.SSL_APPLICATION_BUFFER_REGION_SIZE, 700)); assertNull(optionMap.get(Options.SSL_APPLICATION_BUFFER_SIZE)); assertEquals(570, optionMap.get(Options.SSL_APPLICATION_BUFFER_SIZE, 570)); assertEquals(880, optionMap.get(Options.SSL_APPLICATION_BUFFER_SIZE, 880)); // check toString String optionMapToString = optionMap.toString(); assertNotNull(optionMapToString); for (Option option: options){ assertTrue(optionMapToString.contains(option.toString())); assertTrue(optionMapToString.contains(optionMap.get(option).toString())); } } @Test public void invalidCreations() { IllegalArgumentException expected = null; try { OptionMap.create(null, true); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { OptionMap.create(Options.SASL_POLICY_NOACTIVE, null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { OptionMap.create(null, null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { OptionMap.create(null, true, Options.BROADCAST, false); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { OptionMap.create(Options.SASL_POLICY_NOACTIVE, null, Options.BROADCAST, false); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { OptionMap.create(Options.SASL_POLICY_NOACTIVE, true, null, false); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { OptionMap.create(Options.SASL_POLICY_NOACTIVE, true, Options.BROADCAST, null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void invalidBuilderOperations() { final OptionMap.Builder builder = OptionMap.builder(); assertNotNull(builder); Exception expected = null; try { builder.set(null, "foo"); } catch(IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { builder.set(Options.WORKER_NAME, null); } catch(IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { builder.set(null, false); } catch(IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { builder.set((Option) null, 1); } catch(IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { builder.set(null, 10l); } catch(IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { builder.setSequence((Option>)null); } catch(IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { builder.setSequence((Option>)null, new int[]{1}); } catch(IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { builder.setSequence((Option>)null, new long[]{1}); } catch(IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { builder.setSequence((Option>)null, new boolean[]{false}); } catch(IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void optionMapEquality() { final OptionMap emptyMap1 = OptionMap.EMPTY, emptyMap2 = OptionMap.builder().getMap(); assertEquals(emptyMap1, emptyMap2); assertEquals(emptyMap1, emptyMap1); assertEquals(emptyMap2, emptyMap1); assertEquals(emptyMap2, emptyMap2); assertEquals(emptyMap1.hashCode(), emptyMap1.hashCode()); assertEquals(emptyMap2.hashCode(), emptyMap2.hashCode()); assertEquals(emptyMap1.hashCode(), emptyMap2.hashCode()); final OptionMap optionMap1 = OptionMap.create(LONG_OPTION, 20l), optionMap2 = OptionMap.create(LONG_OPTION, 10l, LONG_OPTION, 20l), // first option value will be ignored optionMap3 = OptionMap.create(LONG_OPTION, 30l); assertEquals(optionMap1, optionMap2); assertTrue(optionMap1.equals((Object) optionMap2)); assertEquals(optionMap2, optionMap1); assertTrue(optionMap2.equals((Object) optionMap1)); assertEquals(optionMap1, optionMap1); assertTrue(optionMap1.equals((Object) optionMap1)); assertEquals(optionMap2, optionMap2); assertTrue(optionMap2.equals((Object) optionMap2)); assertEquals(optionMap1.hashCode(), optionMap2.hashCode()); assertEquals(optionMap2.hashCode(), optionMap1.hashCode()); assertEquals(optionMap1.hashCode(), optionMap1.hashCode()); assertEquals(optionMap2.hashCode(), optionMap2.hashCode()); assertFalse(optionMap1.equals(emptyMap1)); assertFalse(optionMap1.equals((Object) emptyMap1)); assertFalse(optionMap2.equals(emptyMap1)); assertFalse(optionMap2.equals((Object) emptyMap1)); assertFalse(optionMap3.equals(emptyMap1)); assertFalse(optionMap3.equals((Object) emptyMap1)); assertFalse(emptyMap1.equals(optionMap1)); assertFalse(emptyMap1.equals((Object) optionMap1)); assertFalse(emptyMap1.equals(optionMap2)); assertFalse(emptyMap1.equals((Object) optionMap2)); assertFalse(emptyMap1.equals(optionMap3)); assertFalse(emptyMap1.equals((Object) optionMap3)); assertFalse(optionMap1.equals(emptyMap2)); assertFalse(optionMap1.equals((Object) emptyMap2)); assertFalse(optionMap2.equals(emptyMap2)); assertFalse(optionMap2.equals((Object) emptyMap2)); assertFalse(optionMap3.equals(emptyMap2)); assertFalse(optionMap3.equals((Object) emptyMap2)); assertFalse(emptyMap2.equals(optionMap1)); assertFalse(emptyMap2.equals((Object) optionMap1)); assertFalse(emptyMap2.equals(optionMap2)); assertFalse(emptyMap2.equals((Object) optionMap2)); assertFalse(emptyMap2.equals(optionMap3)); assertFalse(emptyMap2.equals((Object) optionMap3)); assertFalse(optionMap1.equals(optionMap3)); assertFalse(optionMap1.equals((Object) optionMap3)); assertFalse(optionMap2.equals(optionMap3)); assertFalse(optionMap2.equals((Object) optionMap3)); assertFalse(optionMap3.equals(optionMap1)); assertFalse(optionMap3.equals((Object) optionMap1)); assertFalse(optionMap3.equals(optionMap2)); assertFalse(optionMap3.equals((Object) optionMap2)); assertFalse(emptyMap1.equals(null)); assertFalse(emptyMap1.equals((OptionMap) null)); assertFalse(emptyMap2.equals(null)); assertFalse(emptyMap2.equals((OptionMap) null)); assertFalse(optionMap1.equals(null)); assertFalse(optionMap1.equals((OptionMap) null)); assertFalse(optionMap2.equals(null)); assertFalse(optionMap2.equals((OptionMap) null)); assertFalse(optionMap3.equals(null)); assertFalse(optionMap3.equals((OptionMap) null)); assertFalse(emptyMap1.equals(new Object())); assertFalse(emptyMap2.equals(new Object())); assertFalse(optionMap1.equals(new Object())); assertFalse(optionMap2.equals(new Object())); assertFalse(optionMap3.equals(new Object())); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/OptionTestCase.java000066400000000000000000001117171257016060700243130ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.BufferedWriter; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileWriter; import java.io.InvalidObjectException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.Writer; import java.lang.reflect.Member; import java.text.DateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; import org.junit.Test; /** * Test for {@link Option} and subclasses. * * @author Flavia Rainone * */ public class OptionTestCase { public static enum Color {WHITE, YELLOW, BLUE, RED, GREEN, BLACK}; // simple options public static final Option SIMPLE_BOOLEAN_OPTION = Option.simple(OptionTestCase.class, "SIMPLE_BOOLEAN_OPTION", Boolean.class); public static final Option SIMPLE_BYTE_OPTION = Option.simple(OptionTestCase.class, "SIMPLE_BYTE_OPTION", Byte.class); public static final Option SIMPLE_CHAR_OPTION = Option.simple(OptionTestCase.class, "SIMPLE_CHAR_OPTION", Character.class); public static final Option SIMPLE_SHORT_OPTION = Option.simple(OptionTestCase.class, "SIMPLE_SHORT_OPTION", Short.class); public static final Option SIMPLE_INT_OPTION = Option.simple(OptionTestCase.class, "SIMPLE_INT_OPTION", Integer.class); public static final Option SIMPLE_LONG_OPTION = Option.simple(OptionTestCase.class, "SIMPLE_LONG_OPTION", Long.class); public static final Option SIMPLE_STRING_OPTION = Option.simple(OptionTestCase.class, "SIMPLE_STRING_OPTION", String.class); public static final Option SIMPLE_PROPERTY_OPTION = Option.simple(OptionTestCase.class, "SIMPLE_PROPERTY_OPTION", Property.class); public static final Option SIMPLE_CALENDAR_OPTION = Option.simple(OptionTestCase.class, "SIMPLE_CALENDAR_OPTION", Calendar.class); public static final Option SIMPLE_COLOR_OPTION = Option.simple(OptionTestCase.class, "SIMPLE_COLOR_OPTION", Color.class); // invalid simple options static final Option NON_PUBLIC_SIMPLE_OPTION = Option.simple(OptionTestCase.class, "NON_PUBLIC_SIMPLE_OPTION", Short.class); public Option NON_STATIC_SIMPLE_OPTION = Option.simple(OptionTestCase.class, "NON_STATIC_SIMPLE_OPTION", Boolean.class); // sequence option public static final Option> STRING_SEQUENCE_OPTION = Option.sequence(OptionTestCase.class, "STRING_SEQUENCE_OPTION", String.class); // invalid sequence options private static final Option> PRIVATE_SEQUENCE_OPTION = Option.sequence(OptionTestCase.class, "PRIVATE_SEQUENCE_OPTION", Integer.class); public final Option> NON_STATIC_SEQUENCE_OPTION = Option.sequence(OptionTestCase.class, "NON_STATIC_SE_OPTION", Byte.class); // type option @SuppressWarnings("rawtypes") public static final Option> COLLECTION_TYPE_OPTION = Option.type(OptionTestCase.class, "COLLECTION_TYPE_OPTION", Collection.class); // invalid type options static final Option> NON_PUBLIC_TYPE_OPTION = Option.type(OptionTestCase.class, "NON_PUBLIC_TYPE_OPTION", Member.class); public final Option> NON_STATIC_TYPE_OPTION = Option.type(OptionTestCase.class, "NON_STATIC_TYPE_OPTION", OutputStream.class); // type sequence option public static final Option>> WRITER_TYPE_SEQUENCE_OPTION = Option.typeSequence(OptionTestCase.class, "WRITER_TYPE_SEQUENCE_OPTION", Writer.class); // invalid type sequence options private static final Option>> PRIVATE_TYPE_SEQUENCE_OPTION = Option.typeSequence(OptionTestCase.class, "PRIVATE_TYPE_SEQUENCE_OPTION", Writer.class); public final Option>> NON_STATIC_TYPE_SEQUENCE_OPTION = Option.typeSequence(OptionTestCase.class, "NON_STATIC_TYPE_SEQUENCE_OPTION", Writer.class); // null option public static final Option NULL_OPTION = null; @Test public void simpleBooleanOption() throws Exception { final Option option = SIMPLE_BOOLEAN_OPTION; // test cast assertSame(Boolean.TRUE, option.cast(true)); assertSame(Boolean.FALSE, option.cast(false)); ClassCastException expected = null; try { option.cast(new Object()); } catch (ClassCastException e) { expected = e; } assertNotNull(expected); // test getName() assertEquals("SIMPLE_BOOLEAN_OPTION", option.getName()); // test hashCode() assertEquals(option.hashCode(), option.hashCode()); // test parsing assertSame(Boolean.TRUE, option.parseValue("true", getClass().getClassLoader())); assertSame(Boolean.FALSE, option.parseValue("false", getClass().getClassLoader())); assertSame(Boolean.FALSE, option.parseValue("nothing", getClass().getClassLoader())); // test serialization Option recoveredOption = this.>checkSerialization(option); assertEquals(option.getName(), recoveredOption.getName()); // test toString() assertNotNull(option.toString()); } @Test public void simpleByteOption() throws Exception { final Option option = SIMPLE_BYTE_OPTION; // test cast assertEquals(Byte.valueOf((byte) 10), option.cast((byte) 10)); assertEquals(Byte.valueOf((byte) 0), option.cast((byte) 0)); Exception expected = null; try { option.cast(new Object()); } catch (ClassCastException e) { expected = e; } assertNotNull(expected); // test getName() assertEquals("SIMPLE_BYTE_OPTION", option.getName()); // test hashCode() assertEquals(option.hashCode(), option.hashCode()); // test parsing assertEquals(Byte.valueOf((byte) 25), option.parseValue("25", getClass().getClassLoader())); assertEquals(Byte.valueOf((byte) -15), option.parseValue("-15", getClass().getClassLoader())); expected = null; try { option.parseValue("nothing", getClass().getClassLoader()); } catch (NumberFormatException e) { expected = e; } assertNotNull(expected); // test serialization Option recoveredOption = this.>checkSerialization(option); assertEquals(option.getName(), recoveredOption.getName()); // test toString() assertNotNull(option.toString()); } @Test public void simpleCharOption() throws Exception { final Option option = SIMPLE_CHAR_OPTION; // test cast assertEquals(Character.valueOf('1'), option.cast('1')); assertEquals(Character.valueOf('a'), option.cast('a')); Exception expected = null; try { option.cast(new Object()); } catch (ClassCastException e) { expected = e; } assertNotNull(expected); // test getName() assertEquals("SIMPLE_CHAR_OPTION", option.getName()); // test hashCode() assertEquals(option.hashCode(), option.hashCode()); // no parsing of chars for this test // test serialization Option recoveredOption = this.>checkSerialization(option); assertEquals(option.getName(), recoveredOption.getName()); // test toString() assertNotNull(option.toString()); } @Test public void simpleShortOption() throws Exception { final Option option = SIMPLE_SHORT_OPTION; // test cast assertEquals(Short.valueOf((short) 50), option.cast((short) 50)); assertEquals(Short.valueOf((short) -1), option.cast((short) -1)); Exception expected = null; try { option.cast(new Object()); } catch (ClassCastException e) { expected = e; } assertNotNull(expected); // test getName() assertEquals("SIMPLE_SHORT_OPTION", option.getName()); // test hashCode() assertEquals(option.hashCode(), option.hashCode()); // test parsing assertEquals(Short.valueOf((short) 37), option.parseValue("37", getClass().getClassLoader())); assertEquals(Short.valueOf((short) 1000), option.parseValue("1000", getClass().getClassLoader())); expected = null; try { option.parseValue("anything", getClass().getClassLoader()); } catch (NumberFormatException e) { expected = e; } assertNotNull(expected); // test serialization Option recoveredOption = this.>checkSerialization(option); assertEquals(option.getName(), recoveredOption.getName()); // test toString() assertNotNull(option.toString()); } @Test public void simpleIntegerOption() throws Exception { final Option option = SIMPLE_INT_OPTION; // test cast assertEquals(Integer.valueOf(25987), option.cast(25987)); assertEquals(Integer.valueOf(-10345), option.cast(-10345)); Exception expected = null; try { option.cast(new Object()); } catch (ClassCastException e) { expected = e; } assertNotNull(expected); // test getName() assertEquals("SIMPLE_INT_OPTION", option.getName()); // test hashCode() assertEquals(option.hashCode(), option.hashCode()); // test parsing assertEquals(Integer.valueOf(-10), option.parseValue("-10", getClass().getClassLoader())); assertEquals(Integer.valueOf(1), option.parseValue("1", getClass().getClassLoader())); expected = null; try { option.parseValue("foo", getClass().getClassLoader()); } catch (NumberFormatException e) { expected = e; } assertNotNull(expected); // test serialization Option recoveredOption = this.>checkSerialization(option); assertEquals(option.getName(), recoveredOption.getName()); // test toString() assertNotNull(option.toString()); } @Test public void simpleLongOption() throws Exception { final Option option = SIMPLE_LONG_OPTION; // test cast assertEquals(Long.valueOf(30l), option.cast(30l)); assertEquals(Long.valueOf(-10345024546l), option.cast(-10345024546l)); Exception expected = null; try { option.cast(new Object()); } catch (ClassCastException e) { expected = e; } assertNotNull(expected); // test getName() assertEquals("SIMPLE_LONG_OPTION", option.getName()); // test hashCode() assertEquals(option.hashCode(), option.hashCode()); // test parsing assertEquals(Long.valueOf(-10), option.parseValue("-10", getClass().getClassLoader())); assertEquals(Long.valueOf(25987000000l), option.parseValue("25987000000", getClass().getClassLoader())); expected = null; try { option.parseValue("zip", getClass().getClassLoader()); } catch (NumberFormatException e) { expected = e; } assertNotNull(expected); // test serialization Option recoveredOption = this.>checkSerialization(option); assertEquals(option.getName(), recoveredOption.getName()); // test toString() assertNotNull(option.toString()); } @Test public void simpleStringOption() throws Exception { final Option option = SIMPLE_STRING_OPTION; // test cast assertEquals("any text", option.cast("any text")); assertEquals("do", option.cast("do")); Exception expected = null; try { option.cast(new Object()); } catch (ClassCastException e) { expected = e; } assertNotNull(expected); // test getName() assertEquals("SIMPLE_STRING_OPTION", option.getName()); // test hashCode() assertEquals(option.hashCode(), option.hashCode()); // test parsing assertEquals("parse this", option.parseValue("parse this", getClass().getClassLoader())); assertEquals("", option.parseValue("", getClass().getClassLoader())); // test serialization Option recoveredOption = this.>checkSerialization(option); assertEquals(option.getName(), recoveredOption.getName()); // test toString() assertNotNull(option.toString()); } @Test public void simplePropertyOption() throws Exception { final Option option = SIMPLE_PROPERTY_OPTION; // test cast assertEquals(Property.of("KEY", "value"), option.cast(Property.of("KEY", "value"))); assertEquals(Property.of("key", "VALUE"), option.cast(Property.of("key", "VALUE"))); Exception expected = null; try { option.cast(new Object()); } catch (ClassCastException e) { expected = e; } assertNotNull(expected); // test getName() assertEquals("SIMPLE_PROPERTY_OPTION", option.getName()); // tet hashCode() assertEquals(option.hashCode(), option.hashCode()); // test parsing assertEquals(Property.of("1", "1"), option.parseValue("1=1", getClass().getClassLoader())); assertEquals(Property.of("key", "value"), option.parseValue("key=value", getClass().getClassLoader())); expected = null; try { option.parseValue("-", getClass().getClassLoader()); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); // test serialization Option recoveredOption = this.>checkSerialization(option); assertEquals(option.getName(), recoveredOption.getName()); // test toString() assertNotNull(option.toString()); } @Test public void simpleObjectOption() throws Exception { // check how would it be like to create an option of any type that not String, Property, byte, short, etc. final Option option = SIMPLE_CALENDAR_OPTION; // test cast final Calendar calendar1 = Calendar.getInstance(), calendar2 = Calendar.getInstance(); calendar2.setTimeInMillis(0); assertSame(calendar1, option.cast(calendar1)); assertSame(calendar2, option.cast(calendar2)); Exception expected = null; try { option.cast(new Object()); } catch (ClassCastException e) { expected = e; } assertNotNull(expected); // test getName() assertEquals("SIMPLE_CALENDAR_OPTION", option.getName()); // test hashCode() assertEquals(option.hashCode(), option.hashCode()); // test parsing expected = null; try { option.parseValue(DateFormat.getInstance().format(calendar1.getTime()), getClass().getClassLoader()); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); // test serialization Option recoveredOption = this.>checkSerialization(option); assertEquals(option.getName(), recoveredOption.getName()); // test toString() assertNotNull(option.toString()); } @Test public void simpleEnumOption() throws Exception { final Option option = SIMPLE_COLOR_OPTION; // test cast assertEquals(Color.WHITE, option.cast(Color.WHITE)); assertEquals(Color.BLUE, option.cast(Color.BLUE)); Exception expected = null; try { option.cast(new Object()); } catch (ClassCastException e) { expected = e; } assertNotNull(expected); // test getName() assertEquals("SIMPLE_COLOR_OPTION", option.getName()); // test hashCode() assertEquals(option.hashCode(), option.hashCode()); // test parsing assertSame(Color.RED, option.parseValue(Color.RED.toString(), getClass().getClassLoader())); assertSame(Color.GREEN, option.parseValue(Color.GREEN.toString(), getClass().getClassLoader())); // test serialization Option recoveredOption = this.>checkSerialization(option); assertEquals(option.getName(), recoveredOption.getName()); // test toString() assertNotNull(option.toString()); } @Test public void invalidSimpleOption() throws Exception { Exception expected = null; try { Option.simple(OptionTestCase.class, null, String.class); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Option.simple(null, "name", String.class); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Option.simple(OptionTestCase.class, "name", null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(Option.simple(OptionTestCase.class, "name", Integer.class)); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(NON_STATIC_SIMPLE_OPTION); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(NON_PUBLIC_SIMPLE_OPTION); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(Option.simple(OptionTestCase.class, "NULL_OPTION", Object.class)); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(Option.simple(OptionTestCase.class, "name", Integer.class)); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); } @Test public void sequenceOption() throws Exception { final Option> option = STRING_SEQUENCE_OPTION; // test cast final Sequence sequence1 = Sequence.empty(); final Sequence sequence2 = Sequence.of("1", "2"); assertEquals(sequence1, option.cast(sequence1)); assertEquals(sequence1, option.cast(new Object[0])); assertEquals(sequence1, option.cast(new ArrayList())); assertEquals(sequence2, option.cast(sequence2)); assertEquals(sequence2, option.cast(new Object[] {"1", "2"})); final Collection collection2 = new ArrayList(); collection2.add("1"); assertFalse(sequence2.equals(option.cast(collection2))); collection2.add("2"); assertEquals(sequence2, option.cast(collection2)); Exception expected = null; try { option.cast(new Object()); } catch (ClassCastException e) { expected = e; } assertNotNull(expected); // test getName() assertEquals("STRING_SEQUENCE_OPTION", option.getName()); // test hashCode() assertEquals(option.hashCode(), option.hashCode()); // test parsing expected = null; assertEquals(sequence1, option.parseValue("", getClass().getClassLoader())); assertEquals(sequence2, option.parseValue("1,2", getClass().getClassLoader())); // test serialization Option> recoveredOption = this.>>checkSerialization(option); assertEquals(option.getName(), recoveredOption.getName()); // test toString() assertNotNull(option.toString()); } @Test public void invalidSequenceOption() throws Exception { Exception expected = null; try { Option.sequence(OptionTestCase.class, null, String.class); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Option.sequence(null, "name", String.class); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Option.sequence(OptionTestCase.class, "name", null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(Option.sequence(OptionTestCase.class, "name", Integer.class)); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(NON_STATIC_SEQUENCE_OPTION); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(PRIVATE_SEQUENCE_OPTION); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(Option.sequence(OptionTestCase.class, "NULL_OPTION", Object.class)); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(Option.sequence(OptionTestCase.class, "name", Integer.class)); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); } @SuppressWarnings("rawtypes") @Test public void typeOption() throws Exception { final Option> option = COLLECTION_TYPE_OPTION; // test cast assertEquals(List.class, option.cast(List.class)); assertEquals(HashSet.class, option.cast(HashSet.class)); Exception expected = null; try { option.cast(new Object()); } catch (ClassCastException e) { expected = e; } assertNotNull(expected); // test getName() assertEquals("COLLECTION_TYPE_OPTION", option.getName()); // test hashCode() assertEquals(option.hashCode(), option.hashCode()); // test parsing assertEquals(Set.class, option.parseValue(Set.class.getName(), getClass().getClassLoader())); assertEquals(ArrayList.class, option.parseValue(ArrayList.class.getName(), getClass().getClassLoader())); expected = null; try { option.parseValue(String.class.getName(), getClass().getClassLoader()); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); try { option.parseValue("nonono", getClass().getClassLoader()); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); // test serialization Option recoveredOption = this.>checkSerialization(option); assertEquals(option.getName(), recoveredOption.getName()); // test toString() assertNotNull(option.toString()); } @Test public void invalidTypeOption() throws Exception { Exception expected = null; try { Option.type(OptionTestCase.class, null, String.class); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Option.type(null, "name", String.class); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Option.type(OptionTestCase.class, "name", null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(Option.type(OptionTestCase.class, "name", Collection.class)); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(NON_STATIC_TYPE_OPTION); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(NON_PUBLIC_TYPE_OPTION); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(Option.type(OptionTestCase.class, "NULL_OPTION", Object.class)); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(Option.type(OptionTestCase.class, "OPTION", Integer.class)); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); } @SuppressWarnings("unchecked") @Test public void typeSequenceOption() throws Exception { final Option>> option = WRITER_TYPE_SEQUENCE_OPTION; // test cast final List> writerList1 = new ArrayList>(); writerList1.add(FileWriter.class); writerList1.add(BufferedWriter.class); final Sequence> sequence1 = Sequence.>of(FileWriter.class, BufferedWriter.class); final Sequence> sequence2 = Sequence.empty(); assertEquals(sequence1, option.cast(sequence1)); assertEquals(sequence1, option.cast(new Object[]{FileWriter.class, BufferedWriter.class})); assertEquals(sequence1, option.cast(writerList1)); assertEquals(sequence2, option.cast(sequence2)); assertEquals(sequence2, option.cast(new Object[0])); assertEquals(sequence2, option.cast(new ArrayList>())); Exception expected = null; try { option.cast(new Object()); } catch (ClassCastException e) { expected = e; } assertNotNull(expected); // test getName() assertEquals("WRITER_TYPE_SEQUENCE_OPTION", option.getName()); // test hashCode() assertEquals(option.hashCode(), option.hashCode()); // test parsing final Sequence> sequence3 = Sequence.> of(OutputStreamWriter.class); assertEquals(sequence3, option.parseValue(OutputStreamWriter.class.getName(), getClass().getClassLoader())); assertEquals(sequence2, option.parseValue("", getClass().getClassLoader())); assertEquals(sequence1, option.parseValue(FileWriter.class.getName() + "," + BufferedWriter.class.getName(), getClass().getClassLoader())); expected = null; try { option.parseValue(String.class.getName(), getClass().getClassLoader()); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); try { option.parseValue("nonono", getClass().getClassLoader()); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); // test serialization Option recoveredOption = this.>checkSerialization(option); assertEquals(option.getName(), recoveredOption.getName()); // test toString() assertNotNull(option.toString()); } @Test public void invalidTypeSequenceOption() throws Exception { Exception expected = null; try { Option.typeSequence(OptionTestCase.class, null, String.class); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Option.typeSequence(null, "name", String.class); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Option.typeSequence(OptionTestCase.class, "name", null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(Option.typeSequence(OptionTestCase.class, "OPTION", Collection.class)); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(NON_STATIC_TYPE_SEQUENCE_OPTION); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(PRIVATE_TYPE_SEQUENCE_OPTION); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(Option.type(OptionTestCase.class, "NULL_OPTION", Object.class)); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); expected = null; try { checkSerialization(Option.type(OptionTestCase.class, "OPTION", Integer.class)); } catch (InvalidObjectException e) { expected = e; } assertNotNull(expected); } @Test public void optionFromString() { String prefix = getClass().getName() + "."; ClassLoader classLoader = getClass().getClassLoader(); assertSame(SIMPLE_BOOLEAN_OPTION, Option.fromString(prefix + "SIMPLE_BOOLEAN_OPTION", classLoader)); assertSame(SIMPLE_BYTE_OPTION, Option.fromString(prefix + "SIMPLE_BYTE_OPTION", classLoader)); assertSame(SIMPLE_CHAR_OPTION, Option.fromString(prefix + "SIMPLE_CHAR_OPTION", classLoader)); assertSame(SIMPLE_SHORT_OPTION, Option.fromString(prefix + "SIMPLE_SHORT_OPTION", classLoader)); assertSame(SIMPLE_INT_OPTION, Option.fromString(prefix + "SIMPLE_INT_OPTION", classLoader)); assertSame(SIMPLE_LONG_OPTION, Option.fromString(prefix + "SIMPLE_LONG_OPTION", classLoader)); assertSame(SIMPLE_STRING_OPTION, Option.fromString(prefix + "SIMPLE_STRING_OPTION", classLoader)); assertSame(SIMPLE_PROPERTY_OPTION, Option.fromString(prefix + "SIMPLE_PROPERTY_OPTION", classLoader)); assertSame(SIMPLE_CALENDAR_OPTION, Option.fromString(prefix + "SIMPLE_CALENDAR_OPTION", classLoader)); assertSame(SIMPLE_COLOR_OPTION, Option.fromString(prefix + "SIMPLE_COLOR_OPTION", classLoader)); assertSame(STRING_SEQUENCE_OPTION, Option.fromString(prefix + "STRING_SEQUENCE_OPTION", classLoader)); assertSame(COLLECTION_TYPE_OPTION, Option.fromString(prefix + "COLLECTION_TYPE_OPTION", classLoader)); assertSame(WRITER_TYPE_SEQUENCE_OPTION, Option.fromString(prefix + "WRITER_TYPE_SEQUENCE_OPTION", classLoader)); IllegalArgumentException expected = null; try { Option.fromString(prefix + "NON_STATIC_SIMPLE_OPTION", classLoader); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Option.fromString(prefix + "NON_PUBLIC_SIMPLE_OPTION", classLoader); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Option.fromString(prefix + "NULL_OPTION", classLoader); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Option.fromString(prefix + "NON_EXISTENT_OPTION", classLoader); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Option.fromString("Foo.OPTION", classLoader); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Option.fromString("NO_DOT", classLoader); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void setBuilder() { Option.SetBuilder setBuilder = Option.setBuilder(); assertTrue(setBuilder.create().isEmpty()); assertSame(setBuilder, setBuilder.add(SIMPLE_BYTE_OPTION)); final Set> set1 = setBuilder.create(); assertNotNull(set1); assertEquals(1, set1.size()); assertTrue(set1.contains(SIMPLE_BYTE_OPTION)); assertSame(setBuilder, setBuilder.add(SIMPLE_COLOR_OPTION)); final Set> set2 = setBuilder.create(); assertNotNull(set2); assertEquals(2, set2.size()); assertTrue(set2.contains(SIMPLE_BYTE_OPTION)); assertTrue(set2.contains(SIMPLE_COLOR_OPTION)); IllegalArgumentException expected = null; try { setBuilder.add(NULL_OPTION); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); final List> options = new ArrayList>(); assertSame(setBuilder, setBuilder.addAll(options)); final Set> set3 = setBuilder.create(); assertNotNull(set3); assertEquals(2, set3.size()); assertTrue(set3.contains(SIMPLE_BYTE_OPTION)); assertTrue(set3.contains(SIMPLE_COLOR_OPTION)); options.add(COLLECTION_TYPE_OPTION); options.add(STRING_SEQUENCE_OPTION); assertSame(setBuilder, setBuilder.addAll(options)); final Set> set4 = setBuilder.create(); assertNotNull(set4); assertEquals(4, set4.size()); assertTrue(set4.contains(SIMPLE_BYTE_OPTION)); assertTrue(set4.contains(SIMPLE_COLOR_OPTION)); assertTrue(set4.contains(COLLECTION_TYPE_OPTION)); assertTrue(set4.contains(STRING_SEQUENCE_OPTION)); options.add(null); expected = null; try { setBuilder.addAll(options); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { setBuilder.addAll(null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @SuppressWarnings("unchecked") private T checkSerialization(T object) throws Exception { final ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); final ObjectOutput output = new ObjectOutputStream(new BufferedOutputStream(byteOutputStream)); try{ output.writeObject(object); } finally{ output.close(); } final ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteOutputStream.toByteArray()); final ObjectInput input = new ObjectInputStream(new BufferedInputStream(byteInputStream)); final T recoveredObject; try{ recoveredObject = (T) input.readObject(); } finally{ input.close(); } assertNotNull(recoveredObject); assertEquals(object, recoveredObject); return recoveredObject; } } xnio-3.3.2.Final/api/src/test/java/org/xnio/OptionsTestCase.java000066400000000000000000000054731257016060700244770ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.BufferedInputStream; import java.io.BufferedOutputStream; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream; import java.lang.reflect.Field; import java.lang.reflect.Modifier; import org.junit.Test; /** * Test for {@link Options}. * * @author Flavia Rainone * */ public class OptionsTestCase { @Test public void testAllOptions() throws Exception { for (Field field: Options.class.getDeclaredFields()) { if (Option.class.isAssignableFrom(field.getType())) { int fieldModifiers = field.getModifiers(); assertTrue(Modifier.isPublic(fieldModifiers)); assertTrue(Modifier.isStatic(fieldModifiers)); // retrieve field value Option option = (Option) field.get(null); assertSame(field.getName(), option.getName()); checkSerialization(option); } } } private void checkSerialization(Option option) throws Exception { final ByteArrayOutputStream byteOutputStream = new ByteArrayOutputStream(); final ObjectOutput output = new ObjectOutputStream(new BufferedOutputStream(byteOutputStream)); try{ output.writeObject(option); } finally{ output.close(); } final ByteArrayInputStream byteInputStream = new ByteArrayInputStream(byteOutputStream.toByteArray()); final ObjectInput input = new ObjectInputStream(new BufferedInputStream(byteInputStream)); final Option recoveredOption; try{ recoveredOption = (Option) input.readObject(); } finally{ input.close(); } assertNotNull(recoveredOption); assertSame(option, recoveredOption); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/PropertyTestCase.java000066400000000000000000000067161257016060700246710ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import org.junit.Test; /** * Test for {@link Property}. * * @author Flavia Rainone * */ public class PropertyTestCase { @Test public void test() { final Property[] properties = new Property[]{ Property.of("PROP_1", "1"), Property.of("PROP_2", "2"), Property.of("PROP_3", "3"), Property.of("PROP_4", "4"), Property.of("PROP_5", "5"), Property.of("PROP_6", "6"), Property.of("PROP_7", "7"), Property.of("PROP_8", "8"), Property.of("PROP_9", "9"), Property.of("PROP_0", "0"), Property.of("PROP_1", "2"), Property.of("PROP", "5"), Property.of("PROP_1", "10"), Property.of("PROP_20", "2")}; assertEquals("PROP_1", properties[0].getKey()); assertEquals("1", properties[0].getValue()); assertEquals("PROP_2", properties[1].getKey()); assertEquals("2", properties[1].getValue()); assertEquals("PROP_3", properties[2].getKey()); assertEquals("3", properties[2].getValue()); assertEquals("PROP_4", properties[3].getKey()); assertEquals("4", properties[3].getValue()); assertEquals("PROP_5", properties[4].getKey()); assertEquals("5", properties[4].getValue()); checkAllAreNotEqual(properties); IllegalArgumentException expected = null; try { Property.of(null, "value"); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Property.of("key", null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } private void checkAllAreNotEqual(Property...properties) { Property property = properties[0]; int i = -1; do { assertEquals(property, property); assertFalse(property.equals(new Object())); for (Property compareTo: properties) { if (property != compareTo) { assertFalse(property.toString() + " is equal to " + compareTo, property.equals((Object)compareTo)); assertFalse(property.toString() + " is equal to " + compareTo, property.equals(compareTo)); // two calls to hashCode must return the same result assertEquals(property.hashCode(), property.hashCode()); assertEquals(compareTo.hashCode(), compareTo.hashCode()); } } } while(++i < properties.length && (property = properties[i]) != null); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/SequenceTestCase.java000066400000000000000000000153541257016060700246130ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import org.junit.Test; /** * Test for {@link Sequence}. * * @author Flavia Rainone * */ public class SequenceTestCase { @Test public void emptySequence() { final Sequence sequence = Sequence.of(); assertNotNull(sequence); assertSame(sequence, Sequence.of(new ArrayList())); assertSame(sequence, Sequence.empty()); Sequence untypedSequence = sequence.cast(Object.class); assertSame(sequence, untypedSequence); assertSame(sequence, untypedSequence.cast(String.class)); assertEquals(sequence, untypedSequence); assertSame(sequence, Sequence.of(sequence)); assertEquals(0, sequence.size()); assertTrue(sequence.isEmpty()); Iterator iterator = sequence.iterator(); assertNotNull(iterator); assertFalse(iterator.hasNext()); assertEquals(0, sequence.toArray().length); assertEquals(sequence.hashCode(), sequence.hashCode()); assertEquals(sequence.hashCode(), Sequence.empty().hashCode()); } @Test public void unitarySequence() { final Sequence sequence = Sequence.of("single"); assertNotNull(sequence); Sequence untypedSequence = sequence.cast(Object.class); assertSame(sequence, untypedSequence); assertSame(sequence, untypedSequence.cast(String.class)); assertEquals(sequence, untypedSequence); assertEquals(sequence, Sequence.of("single")); assertEquals(Sequence.of("single"), sequence); assertSame(sequence, Sequence.of(sequence)); List list = new ArrayList(); list.add("single"); assertEquals(sequence, Sequence.of(list)); assertEquals(Sequence.of(list), sequence); assertEquals(1, sequence.size()); assertFalse(sequence.isEmpty()); Iterator iterator = sequence.iterator(); assertNotNull(iterator); assertTrue(iterator.hasNext()); assertEquals("single", iterator.next()); assertFalse(iterator.hasNext()); Exception expected = null; try { iterator.remove(); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); assertEquals(1, sequence.size()); assertArrayEquals(new String[] {"single"}, sequence.toArray()); assertEquals(sequence.hashCode(), sequence.hashCode()); assertEquals(sequence.hashCode(), Sequence.of("single").hashCode()); } @Test public void simpleSequence() { final Sequence sequence = Sequence.of("a", "b", "c", "d"); assertNotNull(sequence); Sequence untypedSequence = sequence.cast(Object.class); assertSame(sequence, untypedSequence); assertSame(sequence, untypedSequence.cast(String.class)); assertEquals(sequence, untypedSequence); assertEquals(sequence, Sequence.of("a", "b", "c", "d")); assertEquals(Sequence.of("a", "b", "c", "d"), sequence); assertSame(sequence, Sequence.of(sequence)); List list = new ArrayList(); list.add("a"); list.add("b"); list.add("c"); list.add("d"); assertEquals(sequence, Sequence.of(list)); assertEquals(Sequence.of(list), sequence); assertTrue(sequence.equals((Object) Sequence.of(list))); assertFalse(sequence.equals(new Object())); assertFalse(sequence.equals(null)); assertFalse(sequence.equals((Object) Sequence.empty())); assertFalse(sequence.equals((Object) Sequence.of("a", "b", "c", "d", "e"))); assertEquals(4, sequence.size()); assertFalse(sequence.isEmpty()); Iterator iterator = sequence.iterator(); assertNotNull(iterator); assertTrue(iterator.hasNext()); assertEquals("a", iterator.next()); assertTrue(iterator.hasNext()); assertEquals("b", iterator.next()); assertTrue(iterator.hasNext()); assertEquals("c", iterator.next()); assertTrue(iterator.hasNext()); assertEquals("d", iterator.next()); assertFalse(iterator.hasNext()); Exception expected = null; try { iterator.remove(); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); assertEquals(4, sequence.size()); assertArrayEquals(new String[] {"a", "b", "c", "d"}, sequence.toArray()); assertEquals("c", sequence.get(2)); assertEquals("b", sequence.get(1)); assertEquals("d", sequence.get(3)); assertEquals("a", sequence.get(0)); assertEquals(sequence.hashCode(), sequence.hashCode()); assertEquals(sequence.hashCode(), Sequence.of("a", "b", "c", "d").hashCode()); } @Test public void invalidSequence() { IllegalArgumentException expected = null; try { Sequence.of((Object) null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { Sequence.of(new Object(), new Object(), null, new Object()); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; List list = new ArrayList(); list.add("a"); list.add(null); list.add("c"); try { Sequence.of(list); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/XnioFileChannelTestCase.java000066400000000000000000000252621257016060700260500ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.xnio.AssertReadWrite.assertReadMessage; import static org.xnio.AssertReadWrite.assertWrittenMessage; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.FileChannel.MapMode; import java.nio.channels.FileLock; import java.nio.channels.OverlappingFileLockException; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.xnio.channels.BlockingByteChannel; import org.xnio.channels.PushBackStreamChannel; import org.xnio.mock.ConnectedStreamChannelMock; /** * Test for {@link XnioFileChannel}. * * @author Flavia Rainone * */ public class XnioFileChannelTestCase { private RandomAccessFile randomAccessFile; private FileChannel fileChannel; @Before public void initFileChannel() throws IOException { final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); randomAccessFile = new RandomAccessFile(file, "rw"); fileChannel = new XnioFileChannel(randomAccessFile.getChannel()); } @After public void closeFileChannel() throws IOException { fileChannel.close(); randomAccessFile.close(); } @Test public void simpleReadAndWrite() throws IOException { assertEquals(0, fileChannel.size()); final ByteBuffer buffer = ByteBuffer.allocate(5); buffer.put("abcde".getBytes()).flip(); assertEquals(5, fileChannel.write(buffer)); assertEquals(5, fileChannel.size()); assertEquals(5, fileChannel.position()); fileChannel.position(0); assertEquals(0, fileChannel.position()); assertEquals(5, fileChannel.size()); final ByteBuffer readBuffer = ByteBuffer.allocate(10); assertEquals(5, fileChannel.read(readBuffer)); assertEquals(5, fileChannel.position()); assertReadMessage(readBuffer, "abcde"); assertEquals(5, fileChannel.size()); } @Test public void readAndWriteWithOffset() throws IOException { final ByteBuffer[] buffers = new ByteBuffer[] {ByteBuffer.allocate(3), ByteBuffer.allocate(3), ByteBuffer.allocate(3), ByteBuffer.allocate(3), ByteBuffer.allocate(3), ByteBuffer.allocate(3)}; buffers[0].put("#$%".getBytes()).flip(); buffers[1].put("abc".getBytes()).flip(); buffers[2].put("de".getBytes()).flip(); buffers[3].flip(); buffers[4].put("ABC".getBytes()).flip(); buffers[5].put("DEF".getBytes()).flip(); assertEquals(5, fileChannel.write(buffers, 1, 3)); assertEquals(5, fileChannel.position()); fileChannel.position(0); assertEquals(0, fileChannel.position()); final ByteBuffer[] readBuffers = new ByteBuffer[] {ByteBuffer.allocate(1), ByteBuffer.allocate(2), ByteBuffer.allocate(3), ByteBuffer.allocate(4)}; assertEquals(2, fileChannel.read(readBuffers, 1, 1)); assertEquals(2, fileChannel.position()); assertReadMessage(readBuffers[1], "ab"); assertEquals(3, fileChannel.read(readBuffers, 1, 3)); assertEquals(5, fileChannel.position()); assertReadMessage(readBuffers[2], "cde"); } @Test public void readAndWriteWithPosition() throws IOException { assertEquals(0, fileChannel.size()); final ByteBuffer buffer = ByteBuffer.allocate(5); buffer.put("abcde".getBytes()).flip(); assertEquals(5, fileChannel.write(buffer, 3)); assertEquals(8, fileChannel.size()); assertEquals(0, fileChannel.position()); fileChannel.position(3); assertEquals(3, fileChannel.position()); assertEquals(8, fileChannel.size()); final ByteBuffer readBuffer = ByteBuffer.allocate(10); assertEquals(4, fileChannel.read(readBuffer, 4)); assertEquals(3, fileChannel.position()); assertReadMessage(readBuffer, "bcde"); assertEquals(8, fileChannel.size()); } @Test public void truncate() throws IOException { assertEquals(0, fileChannel.size()); final ByteBuffer buffer = ByteBuffer.allocate(20); buffer.put("message to truncate".getBytes()).flip(); assertEquals(19, fileChannel.write(buffer)); assertEquals(19, fileChannel.size()); fileChannel.truncate(10); assertEquals(10, fileChannel.size()); buffer.clear(); fileChannel.position(0); assertEquals(10, fileChannel.read(buffer)); assertReadMessage(buffer, "message to"); buffer.clear(); fileChannel.truncate(15); assertEquals(10, fileChannel.size()); buffer.clear(); fileChannel.position(0); assertEquals(10, fileChannel.read(buffer)); assertReadMessage(buffer, "message to"); buffer.clear(); fileChannel.truncate(7); assertEquals(7, fileChannel.size()); buffer.clear(); fileChannel.position(0); assertEquals(7, fileChannel.read(buffer)); assertReadMessage(buffer, "message"); //test force... nothing noticeable should happen fileChannel.force(true); fileChannel.force(false); } @Test public void transferBlockingToFile1() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); channelMock.setReadData("test"); channelMock.enableRead(true); fileChannel.transferFrom(channelMock, 0, 4); fileChannel.position(0); ByteBuffer buffer = ByteBuffer.allocate(10); fileChannel.read(buffer); assertReadMessage(buffer, "test"); } @Test public void transferBlockingToFile2() throws IOException, InterruptedException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); channelMock.setReadData("test", "12345"); channelMock.enableRead(true); fileChannel.transferFrom(new PushBackStreamChannel(channelMock), 0, 8); fileChannel.position(0); ByteBuffer buffer = ByteBuffer.allocate(10); fileChannel.read(buffer); assertReadMessage(buffer, "test", "1234"); } @Test public void transferBlockingToFile3() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); channelMock.setReadData("test"); channelMock.enableRead(true); fileChannel.transferFrom(new BlockingByteChannel(channelMock), 0, 4); fileChannel.position(0); ByteBuffer buffer = ByteBuffer.allocate(10); fileChannel.read(buffer); assertReadMessage(buffer, "test"); } @Test public void transferBlockingFromFile1() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("test".getBytes("UTF-8")).flip(); assertEquals(4, fileChannel.write(buffer)); fileChannel.position(0); fileChannel.transferTo(0, 4, channelMock); assertWrittenMessage(channelMock, "test"); } @Test public void transferBlockingFromFile2() throws IOException, InterruptedException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); channelMock.enableWrite(false); final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("test12345".getBytes("UTF-8")).flip(); assertEquals(9, fileChannel.write(buffer)); fileChannel.position(0); channelMock.enableWrite(true); fileChannel.transferTo(0, 8, channelMock); assertWrittenMessage(channelMock, "test", "1234"); } @Test public void transferBlockingFromFile3() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("test".getBytes("UTF-8")).flip(); assertEquals(4, fileChannel.write(buffer)); fileChannel.position(0); fileChannel.transferTo(0, 4, new BlockingByteChannel(channelMock)); assertWrittenMessage(channelMock, "test"); } @Test public void map() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("1234567890".getBytes()).flip(); assertEquals(10, fileChannel.write(buffer)); MappedByteBuffer mappedBuffer = fileChannel.map(MapMode.READ_WRITE, 5, 2); assertNotNull(mappedBuffer); assertEquals(2, mappedBuffer.limit()); mappedBuffer.position(2); assertReadMessage(mappedBuffer, "67"); } @Test public void lock() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("1234567890".getBytes()).flip(); assertEquals(10, fileChannel.write(buffer)); FileLock lock = fileChannel.lock(); assertNotNull(lock); OverlappingFileLockException expected = null; try { fileChannel.lock(3, 5, false); } catch (OverlappingFileLockException e) { expected = e; } assertNotNull(expected); lock.release(); lock = fileChannel.lock(3, 5, false); assertNotNull(lock); expected = null; try { fileChannel.tryLock(); } catch (OverlappingFileLockException e) { expected = e; } assertNotNull(expected); lock.release(); lock = fileChannel.tryLock(); assertNotNull(lock); lock.release(); lock = fileChannel.tryLock(1, 3, true); assertNotNull(lock); expected = null; try { fileChannel.tryLock(1, 3, true); } catch (OverlappingFileLockException e) { expected = e; } assertNotNull(expected); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/XnioTestCase.java000066400000000000000000000367041257016060700237620ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.xnio.AssertReadWrite.assertReadMessage; import static org.xnio.AssertReadWrite.assertWrittenMessage; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.nio.channels.NonWritableChannelException; import java.security.AccessControlException; import java.security.AccessController; import java.security.GeneralSecurityException; import java.security.KeyStore; import java.security.Permission; import java.security.PrivilegedAction; import java.util.ServiceConfigurationError; import javax.net.ssl.KeyManagerFactory; import javax.net.ssl.TrustManagerFactory; import org.junit.Test; import org.xnio.channels.Channels; import org.xnio.mock.ConnectedStreamChannelMock; import org.xnio.ssl.XnioSsl; /** * Test for {@link Xnio}. * * @author Flavia Rainone * */ public class XnioTestCase { static { String securityPolicyFile = XnioTestCase.class.getClassLoader().getResource("security.policy").getFile(); AccessController.doPrivileged(new SetSecurityPolicyAction(securityPolicyFile)); } private static final String DEFAULT_KEY_STORE = "keystore.jks"; private static final String DEFAULT_KEY_STORE_PASSWORD = "apiTest"; @Test public void allowBlocking() { assertTrue(Xnio.isBlockingAllowed()); Xnio.checkBlockingAllowed(); Xnio.allowBlocking(true); assertTrue(Xnio.isBlockingAllowed()); Xnio.checkBlockingAllowed(); Xnio.allowBlocking(false); assertFalse(Xnio.isBlockingAllowed()); IllegalStateException expected = null; try { Xnio.checkBlockingAllowed(); } catch (IllegalStateException e) { expected = e; } assertNotNull(expected); Xnio.allowBlocking(false); assertFalse(Xnio.isBlockingAllowed()); expected = null; try { Xnio.checkBlockingAllowed(); } catch (IllegalStateException e) { expected = e; } assertNotNull(expected); Xnio.allowBlocking(true); assertTrue(Xnio.isBlockingAllowed()); Xnio.checkBlockingAllowed(); Xnio.allowBlocking(true); assertTrue(Xnio.isBlockingAllowed()); Xnio.checkBlockingAllowed(); } @Test public void allowBlockingWithSecurity() { final SecurityManager securityManager = new SecurityManager(); System.setSecurityManager(securityManager); assertTrue(Xnio.isBlockingAllowed()); Xnio.checkBlockingAllowed(); AccessControlException expected = null; try { Xnio.allowBlocking(true); } catch (AccessControlException e) { expected = e; } assertNotNull(expected); expected = null; try { Xnio.allowBlocking(false); } catch (AccessControlException e) { expected = e; } assertNotNull(expected); AccessController.doPrivileged(new GrantAllPermissionsAction()); allowBlocking(); AccessController.doPrivileged(new ResetSecurityManagerAction()); } @Test public void retrieveInstance() { final Xnio xnio = Xnio.getInstance(); assertNotNull(xnio); assertSame(xnio, Xnio.getInstance(getClass().getClassLoader())); assertSame(xnio, Xnio.getInstance("xnio-mock")); IllegalArgumentException expectedException = null; try { Xnio.getInstance("xnio"); } catch (IllegalArgumentException e) { expectedException = e; } assertNotNull(expectedException); assertNotNull(xnio.toString()); assertEquals("xnio-mock", xnio.getName()); } @Test public void retrieveSslProvider() throws GeneralSecurityException { final Xnio xnio = Xnio.getInstance(); final OptionMap optionMap = OptionMap.create(Options.SSL_CLIENT_AUTH_MODE, SslClientAuthMode.REQUIRED, Options.SSL_STARTTLS, true); final XnioSsl sslProvider = xnio.getSslProvider(optionMap); assertNotNull(sslProvider); } @Test public void retrieveSslProviderWithTrustAndKeyManagers() throws GeneralSecurityException, FileNotFoundException, IOException { final Xnio xnio = Xnio.getInstance(); final OptionMap optionMap = OptionMap.create(Options.SSL_CLIENT_AUTH_MODE, SslClientAuthMode.REQUIRED, Options.SSL_STARTTLS, true); final KeyStore keyStore = KeyStore.getInstance("JKS"); final String keyStorePath = XnioTestCase.class.getClassLoader().getResource(DEFAULT_KEY_STORE).getFile(); keyStore.load(new FileInputStream(keyStorePath), DEFAULT_KEY_STORE_PASSWORD.toCharArray()); final KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(keyStore, DEFAULT_KEY_STORE_PASSWORD.toCharArray()); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keyStore); final XnioSsl sslProvider = xnio.getSslProvider(keyManagerFactory.getKeyManagers(), trustManagerFactory.getTrustManagers(), optionMap); assertNotNull(sslProvider); } private File createTempFile() throws IOException { final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); return file; } private void checkReadOnlyFileChannel(FileChannel fileChannel) throws IOException { try { assertNotNull(fileChannel); NonWritableChannelException expected = null; try { fileChannel.write(ByteBuffer.allocate(10)); } catch (NonWritableChannelException e) { expected = e; } assertNotNull(expected); fileChannel.position(0); ByteBuffer buffer = ByteBuffer.allocate(10); fileChannel.read(buffer); assertReadMessage(buffer); } finally { fileChannel.close(); } } private void checkReadWriteFileChannel(FileChannel fileChannel) throws IOException { try { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); channelMock.setReadData("test"); channelMock.enableRead(true); assertNotNull(fileChannel); final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("test".getBytes("UTF-8")).flip(); assertEquals(4, fileChannel.write(buffer)); fileChannel.position(0); Channels.transferBlocking(channelMock, fileChannel, 0, 4); assertWrittenMessage(channelMock, "test"); } finally { fileChannel.close(); } } @Test public void openFileWithReadOnlyOption() throws IOException { final File file = createTempFile(); final OptionMap optionMap = OptionMap.create(Options.FILE_ACCESS, FileAccess.READ_ONLY); checkReadOnlyFileChannel(Xnio.getInstance().openFile(file, optionMap)); } @Test public void openFileWithReadWriteOption() throws IOException { final File file = createTempFile(); final OptionMap optionMap = OptionMap.create(Options.FILE_ACCESS, FileAccess.READ_WRITE); checkReadWriteFileChannel(Xnio.getInstance().openFile(file, optionMap)); } @Test public void openFileWithEmptyOptionMap() throws IOException { final File file = createTempFile(); checkReadWriteFileChannel(Xnio.getInstance().openFile(file, OptionMap.EMPTY)); } @Test public void openFileNameWithReadOnlyOption() throws IOException { final File file = createTempFile(); final OptionMap optionMap = OptionMap.create(Options.FILE_ACCESS, FileAccess.READ_ONLY); checkReadOnlyFileChannel(Xnio.getInstance().openFile(file.getAbsolutePath(), optionMap)); } @Test public void openFileNameWithReadWriteOption() throws IOException { final File file = createTempFile(); final OptionMap optionMap = OptionMap.create(Options.FILE_ACCESS, FileAccess.READ_WRITE); checkReadWriteFileChannel(Xnio.getInstance().openFile(file.getAbsolutePath(), optionMap)); } @Test public void openFileNameWithEmptyOptionMap() throws IOException { final File file = createTempFile(); checkReadWriteFileChannel(Xnio.getInstance().openFile(file.getAbsolutePath(), OptionMap.EMPTY)); } @Test public void openFileWithReadOnlyFileAccess() throws IOException { final File file = createTempFile(); checkReadOnlyFileChannel(Xnio.getInstance().openFile(file, FileAccess.READ_ONLY)); } @Test public void openFileWithReadWriteFileAccess() throws IOException { final File file = createTempFile(); checkReadWriteFileChannel(Xnio.getInstance().openFile(file, FileAccess.READ_WRITE)); } @Test public void openFileNameWithReadOnlyFileAccess() throws IOException { final File file = createTempFile(); checkReadOnlyFileChannel(Xnio.getInstance().openFile(file.getAbsolutePath(), FileAccess.READ_ONLY)); } @Test public void openFileNameWithReadWriteFileAccess() throws IOException { final File file = createTempFile(); checkReadWriteFileChannel(Xnio.getInstance().openFile(file.getAbsolutePath(), FileAccess.READ_WRITE)); } @Test public void invalidOpenFileName() throws IOException { final File file = createTempFile(); final Xnio xnio = Xnio.getInstance(); Exception expected = null; try { xnio.openFile(file.getAbsolutePath(), (FileAccess) null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnio.openFile(file.getAbsolutePath(), (OptionMap) null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnio.openFile((String) null, FileAccess.READ_WRITE); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnio.openFile((String) null, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnio.openFile(file, (FileAccess) null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnio.openFile(file, (OptionMap) null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnio.openFile((File) null, FileAccess.READ_WRITE); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnio.openFile((File) null, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void createWorker() throws IllegalArgumentException, IOException { final Xnio xnio = Xnio.getInstance(); final XnioWorker xnioWorker1 = xnio.createWorker(OptionMap.EMPTY); assertNotNull(xnioWorker1); assertSame(xnio, xnioWorker1.getXnio()); assertNull(xnioWorker1.getTerminationTask()); final XnioWorker xnioWorker2 = xnio.createWorker(Thread.currentThread().getThreadGroup(), OptionMap.EMPTY); assertNotNull(xnioWorker2); assertSame(xnio, xnioWorker2.getXnio()); assertNull(xnioWorker2.getTerminationTask()); } @Test public void propertiesRetrieval() { final Xnio xnio = Xnio.getInstance(); assertNull(xnio.getProperty("xnio.test.prop")); assertEquals("foo", xnio.getProperty("xnio.test.prop", "foo")); System.setProperty("xnio.test.prop", "foo2"); assertEquals("foo2", xnio.getProperty("xnio.test.prop")); assertEquals("foo2", xnio.getProperty("xnio.test.prop")); AccessController.doPrivileged(new GrantAllPermissionsAction()); assertNull(xnio.getProperty("xnio.prop.test")); assertEquals("aaa", xnio.getProperty("xnio.prop.test", "aaa")); System.setProperty("xnio.prop.test", "bbb"); assertEquals("bbb", xnio.getProperty("xnio.prop.test")); assertEquals("bbb", xnio.getProperty("xnio.prop.test")); AccessController.doPrivileged(new ResetSecurityManagerAction()); } @Test public void illegalPropertiesRetrieval() { System.setSecurityManager(null); final Xnio xnio = Xnio.getInstance(); SecurityException expected = null; try { xnio.getProperty("any prop that does not start with xnio."); } catch (SecurityException e) { expected = e; } assertNotNull(expected); expected = null; try { xnio.getProperty("xnio - any prop that does not start with xnio.", "default"); } catch (SecurityException e) { expected = e; } assertNotNull(expected); } private static class SetSecurityPolicyAction implements PrivilegedAction { private final String propertyValue; public SetSecurityPolicyAction(String fileName) { propertyValue = fileName; } @Override public Void run() { System.setProperty("java.security.policy", propertyValue); return null; } } private static class GrantAllPermissionsAction implements PrivilegedAction { @Override public Void run() { System.setSecurityManager(new SecurityManager() { @Override public void checkPermission(Permission permission, Object context) {} @Override public void checkPermission(Permission permission) {} }); return null; } } private static class ResetSecurityManagerAction implements PrivilegedAction { @Override public Void run() { System.setSecurityManager(null); return null; } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/XnioWorkerTestCase.java000066400000000000000000001233601257016060700251470ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.lang.reflect.Field; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.channels.Channel; import java.util.List; import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.RejectedExecutionException; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.AssembledConnectedMessageChannel; import org.xnio.channels.AssembledConnectedStreamChannel; import org.xnio.channels.BoundChannel; import org.xnio.channels.ConnectedMessageChannel; import org.xnio.channels.ConnectedStreamChannel; import org.xnio.channels.MulticastMessageChannel; import org.xnio.mock.AcceptingChannelMock; import org.xnio.mock.MessageConnectionMock; import org.xnio.mock.Mock; import org.xnio.mock.MulticastMessageChannelMock; import org.xnio.mock.StreamConnectionMock; import org.xnio.mock.XnioIoThreadMock; import org.xnio.mock.XnioWorkerMock; /** * Test for {@link XnioWorker}. * * @author Flavia Rainone * */ @SuppressWarnings("deprecation") public class XnioWorkerTestCase { private static final SocketAddress unknownSocketAddress = new SocketAddress() {private static final long serialVersionUID = 1L;}; private XnioWorker xnioWorker; @Before public void init() throws IllegalArgumentException, IOException { final Xnio xnio = Xnio.getInstance(); xnioWorker = xnio.createWorker(OptionMap.create(Options.WORKER_NAME, "worker for tests", Options.THREAD_DAEMON, true)); assertNotNull(xnioWorker); assertEquals("worker for tests", xnioWorker.getName()); } private void checkCreateStreamServer(SocketAddress socketAddress, String channelInfo) throws IOException { final TestChannelListener> acceptingChannelListener = new TestChannelListener>();; final OptionMap optionMap = OptionMap.create(Options.BROADCAST, true); // use any option, for test purposes final AcceptingChannel streamServer = xnioWorker.createStreamServer( socketAddress, acceptingChannelListener, optionMap); assertNotNull(streamServer); assertEquals(socketAddress, streamServer.getLocalAddress()); assertEquals(socketAddress, streamServer.getLocalAddress(socketAddress.getClass())); assertNotNull(streamServer.getIoThread()); assertSame(xnioWorker, streamServer.getWorker()); // make sure that acceptance is being delegated to AcceptingChannelMock final AssembledConnectedStreamChannel assembledChannel = (AssembledConnectedStreamChannel) streamServer.accept(); assertNotNull(assembledChannel); // check that acceptance has been correctly delegated to XnioWorkerMock final StreamConnectionMock connection = getConnectedChannel(assembledChannel); assertNotNull(connection); assertSame(streamServer, acceptingChannelListener.getChannel()); assertEquals(optionMap, connection.getOptionMap()); assertEquals(channelInfo, connection.getInfo()); // retrieve actual accepting channel final AcceptingChannelMock acceptingChannel = connection.getServer(); assertEquals(optionMap, acceptingChannel.getOptionMap()); assertEquals(channelInfo, acceptingChannel.getInfo()); assertEquals(socketAddress, acceptingChannel.getLocalAddress()); assertEquals(socketAddress, acceptingChannel.getLocalAddress(socketAddress.getClass())); // check correct delegation between the stream server and actual accepting channel assertFalse(acceptingChannel.isAcceptResumed()); streamServer.resumeAccepts(); assertTrue(acceptingChannel.isAcceptResumed()); streamServer.suspendAccepts(); assertFalse(acceptingChannel.isAcceptResumed()); assertFalse(acceptingChannel.isAcceptWokenUp()); streamServer.wakeupAccepts(); assertTrue(acceptingChannel.isAcceptWokenUp()); assertFalse(acceptingChannel.haveWaitedAcceptable()); streamServer.awaitAcceptable(); assertTrue(acceptingChannel.haveWaitedAcceptable()); acceptingChannel.clearWaitedAcceptable(); streamServer.awaitAcceptable(10, TimeUnit.MILLISECONDS); assertTrue(acceptingChannel.haveWaitedAcceptable()); assertEquals(10, acceptingChannel.getAwaitAcceptableTime()); assertSame(TimeUnit.MILLISECONDS, acceptingChannel.getAwaitAcceptableTimeUnit()); assertSame(acceptingChannel.getAcceptThread(), streamServer.getAcceptThread()); acceptingChannel.setSupportedOptions(Options.KEEP_ALIVE); // use any option, just for testing purposes assertTrue(streamServer.supportsOption(Options.KEEP_ALIVE)); assertFalse(streamServer.supportsOption(Options.BROADCAST)); assertTrue(streamServer.getOption(Options.BROADCAST)); assertTrue(acceptingChannel.getOption(Options.BROADCAST)); assertTrue(streamServer.setOption(Options.BROADCAST, false)); assertFalse(streamServer.getOption(Options.BROADCAST)); assertFalse(acceptingChannel.getOption(Options.BROADCAST)); assertTrue(streamServer.isOpen()); assertTrue(acceptingChannel.isOpen()); streamServer.close(); assertFalse(streamServer.isOpen()); assertFalse(acceptingChannel.isOpen()); ((XnioWorkerMock) xnioWorker).failConnection(); final AcceptingChannel failAcceptanceServer = xnioWorker.createStreamServer(socketAddress, acceptingChannelListener, optionMap); assertNull(failAcceptanceServer.accept()); } @Test public void createTcpStreamServer() throws IOException { checkCreateStreamServer(new InetSocketAddress(1000), XnioWorkerMock.TCP_CHANNEL_INFO); } @Test public void createLocalStreamServer() throws IOException { checkCreateStreamServer(new LocalSocketAddress("server"), XnioWorkerMock.LOCAL_CHANNEL_INFO); } @Test public void createStreamServerWithInvalidAddress() throws IOException { final ChannelListener> acceptingChannelListener = new ChannelListener>() { @Override public void handleEvent(AcceptingChannel channel) {} }; Exception expected = null; try { xnioWorker.createStreamServer(null, acceptingChannelListener, OptionMap.create(Options.BROADCAST, true)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.createStreamServer(new SocketAddress() {private static final long serialVersionUID = 1L;}, acceptingChannelListener, OptionMap.create(Options.BROADCAST, true)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } private void checkConnectStream(SocketAddress socketAddress, SocketAddress localSocketAddress, String channelInfo) throws CancellationException, IOException { final TestChannelListener channelListener = new TestChannelListener(); final OptionMap optionMap = OptionMap.create(Options.MAX_INBOUND_MESSAGE_SIZE, 50000); final IoFuture connectedStreamChannel = xnioWorker.connectStream(socketAddress, channelListener, optionMap); assertNotNull(connectedStreamChannel); final AssembledConnectedStreamChannel assembledChannel = (AssembledConnectedStreamChannel) connectedStreamChannel.get(); assertNotNull(assembledChannel); assertTrue(channelListener.isInvoked()); assertSame(assembledChannel, channelListener.getChannel()); assertEquals(localSocketAddress, assembledChannel.getLocalAddress()); assertEquals(socketAddress, assembledChannel.getPeerAddress()); } @Test public void connectTcpStream() throws CancellationException, IOException { checkConnectStream(new InetSocketAddress(1000), Xnio.ANY_INET_ADDRESS, XnioWorkerMock.TCP_CHANNEL_INFO); } @Test public void connectLocalStream() throws CancellationException, IOException { checkConnectStream(new LocalSocketAddress("server for test"), Xnio.ANY_LOCAL_ADDRESS, XnioWorkerMock.LOCAL_CHANNEL_INFO); } private void checkConnectStreamWithBindListener(SocketAddress socketAddress, SocketAddress localSocketAddress, String channelInfo) throws CancellationException, IOException { final TestChannelListener channelListener = new TestChannelListener(); final TestChannelListener bindListener = new TestChannelListener(); final OptionMap optionMap = OptionMap.create(Options.MAX_OUTBOUND_MESSAGE_SIZE, 50000); final IoFuture connectedStreamChannel = xnioWorker.connectStream(socketAddress, channelListener, bindListener, optionMap); assertNotNull(connectedStreamChannel); final AssembledConnectedStreamChannel assembledConnectionStream = (AssembledConnectedStreamChannel) connectedStreamChannel.get(); assertNotNull(assembledConnectionStream); final StreamConnectionMock connection = getConnectedChannel(assembledConnectionStream); assertNotNull(connection); assertTrue(channelListener.isInvoked()); assertSame(assembledConnectionStream, channelListener.getChannel()); assertTrue(bindListener.isInvoked()); assertSame(connection, bindListener.getChannel()); assertEquals(localSocketAddress, connection.getLocalAddress()); assertEquals(socketAddress, connection.getPeerAddress()); assertEquals(optionMap, connection.getOptionMap()); assertEquals(channelInfo, connection.getInfo()); } @Test public void connectTcpStreamWithBindListener() throws CancellationException, IOException { checkConnectStreamWithBindListener(new InetSocketAddress(1500), Xnio.ANY_INET_ADDRESS, XnioWorkerMock.TCP_CHANNEL_INFO); } @Test public void connectLocalStreamWithBindListener() throws CancellationException, IOException { checkConnectStreamWithBindListener(new LocalSocketAddress("server for test"), Xnio.ANY_LOCAL_ADDRESS, XnioWorkerMock.LOCAL_CHANNEL_INFO); } @Test public void connectStreamWithInvalidAddress() { final ChannelListener channelListener = new TestChannelListener(); final ChannelListener bindListener = new TestChannelListener(); Exception expected = null; try { xnioWorker.connectStream(null, channelListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.connectStream(unknownSocketAddress, channelListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.connectStream(null, channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.connectStream(unknownSocketAddress, channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.connectStream(null, new LocalSocketAddress("local"), channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.connectStream(new LocalSocketAddress("local"), null, channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.connectStream(null, null, channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.connectStream(new InetSocketAddress(800), new LocalSocketAddress("local"), channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.connectStream(new LocalSocketAddress("local"), new InetSocketAddress(800), channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.connectStream(unknownSocketAddress, unknownSocketAddress, channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } private void checkConnectStreamWithBindListenerAndDestination(SocketAddress socketAddress, SocketAddress localSocketAddress, String channelInfo) throws CancellationException, IOException { final TestChannelListener channelListener = new TestChannelListener(); final TestChannelListener bindListener = new TestChannelListener(); final OptionMap optionMap = OptionMap.create(Options.MAX_OUTBOUND_MESSAGE_SIZE, 50000); final IoFuture connectedStreamChannel = xnioWorker.connectStream(localSocketAddress, socketAddress, channelListener, bindListener, optionMap); assertNotNull(connectedStreamChannel); final AssembledConnectedStreamChannel assembledChannel = (AssembledConnectedStreamChannel) connectedStreamChannel.get(); assertNotNull(assembledChannel); final StreamConnectionMock connection = getConnectedChannel(assembledChannel); assertNotNull(connection); assertTrue(channelListener.isInvoked()); assertSame(assembledChannel, channelListener.getChannel()); assertTrue(bindListener.isInvoked()); assertSame(connection, bindListener.getChannel()); assertEquals(localSocketAddress, connection.getLocalAddress()); assertEquals(socketAddress, connection.getPeerAddress()); assertEquals(optionMap, connection.getOptionMap()); assertEquals(channelInfo, connection.getInfo()); } @Test public void connectTcpStreamWithBindListenerAndDestination() throws CancellationException, IOException { checkConnectStreamWithBindListenerAndDestination(new InetSocketAddress(1500), new InetSocketAddress(500), XnioWorkerMock.TCP_CHANNEL_INFO); } @Test public void connectLocalStreamWithBindListenerAndDestination() throws CancellationException, IOException { checkConnectStreamWithBindListenerAndDestination(new LocalSocketAddress("server for test..."), new LocalSocketAddress("one more address"), XnioWorkerMock.LOCAL_CHANNEL_INFO); } private void checkAcceptStream(SocketAddress socketAddress, String channelInfo) throws CancellationException, IOException { final TestChannelListener channelListener = new TestChannelListener(); final TestChannelListener bindListener = new TestChannelListener(); final OptionMap optionMap = OptionMap.create(Options.READ_TIMEOUT, 800000); final IoFuture connectedStreamChannel = xnioWorker.acceptStream(socketAddress, channelListener, bindListener, optionMap); assertNotNull(connectedStreamChannel); final AssembledConnectedStreamChannel assembledChannel = (AssembledConnectedStreamChannel) connectedStreamChannel.get(); assertNotNull(assembledChannel); final StreamConnectionMock connection = getConnectedChannel(assembledChannel); assertNotNull(connection); assertTrue(channelListener.isInvoked()); assertSame(assembledChannel, channelListener.getChannel()); assertTrue(bindListener.isInvoked()); assertSame(connection, bindListener.getChannel()); assertEquals(socketAddress, connection.getPeerAddress()); assertEquals(optionMap, connection.getOptionMap()); assertEquals(channelInfo, connection.getInfo()); } @Test public void acceptTcpStream() throws CancellationException, IOException { checkAcceptStream(new InetSocketAddress(1567), XnioWorkerMock.TCP_CHANNEL_INFO); } @Test public void acceptLocalStream() throws CancellationException, IOException { checkAcceptStream(new LocalSocketAddress("local address"), XnioWorkerMock.LOCAL_CHANNEL_INFO); } @Test public void acceptStreamWithInvalidAddress() { final ChannelListener openListener = new TestChannelListener(); final ChannelListener bindListener = new TestChannelListener(); Exception expected = null; try { xnioWorker.acceptStream(null, openListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.acceptStream(unknownSocketAddress, openListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void connectDatagram() throws CancellationException, IOException { final SocketAddress socketAddress = new LocalSocketAddress("local"); final TestChannelListener channelListener = new TestChannelListener(); final TestChannelListener bindListener = new TestChannelListener(); final OptionMap optionMap = OptionMap.create(Options.WRITE_TIMEOUT, 800000); final IoFuture connectedDatagramFuture = xnioWorker.connectDatagram(socketAddress, channelListener, bindListener, optionMap); assertNotNull(connectedDatagramFuture); final AssembledConnectedMessageChannel assembledChannel = (AssembledConnectedMessageChannel) connectedDatagramFuture.get(); assertTrue(channelListener.isInvoked()); assertSame(assembledChannel, channelListener.getChannel()); //assertTrue(bindListener.isInvoked()); // FIXME XNIO-192 //assertSame(assembledChannel, bindListener.getChannel()); assertEquals(Xnio.ANY_LOCAL_ADDRESS, assembledChannel.getLocalAddress()); assertEquals(socketAddress, assembledChannel.getPeerAddress()); assertEquals(800000, (int) assembledChannel.getOption(Options.WRITE_TIMEOUT)); final MessageConnectionMock connectionMock = getConnectedChannel(assembledChannel); assertSame(optionMap, connectionMock.getOptionMap()); assertEquals(XnioWorkerMock.LOCAL_CHANNEL_INFO, connectionMock.getInfo()); } @Test public void connectDatagramWithBindAddress() throws CancellationException, IOException { final SocketAddress socketAddress = new LocalSocketAddress("local1"); final SocketAddress bindAddress = new LocalSocketAddress("local2"); final TestChannelListener channelListener = new TestChannelListener(); final TestChannelListener bindListener = new TestChannelListener(); final OptionMap optionMap = OptionMap.create(Options.STACK_SIZE, 9000000l); final IoFuture connectedDatagramFuture = xnioWorker.connectDatagram(bindAddress, socketAddress, channelListener, bindListener, optionMap); assertNotNull(connectedDatagramFuture); final AssembledConnectedMessageChannel assembledChannel = (AssembledConnectedMessageChannel) connectedDatagramFuture.get(); assertTrue(channelListener.isInvoked()); assertSame(assembledChannel, channelListener.getChannel()); //assertTrue(bindListener.isInvoked()); // FIXME XNIO-192 //assertSame(assembledChannel, bindListener.getChannel()); assertEquals(Xnio.ANY_LOCAL_ADDRESS, assembledChannel.getLocalAddress()); // FIXME bindAddress is ignored assertEquals(bindAddress, assembledChannel.getLocalAddress()); assertEquals(socketAddress, assembledChannel.getPeerAddress()); assertEquals(9000000l, (long) assembledChannel.getOption(Options.STACK_SIZE)); final MessageConnectionMock connectionMock = getConnectedChannel(assembledChannel); assertSame(optionMap, connectionMock.getOptionMap()); assertEquals(XnioWorkerMock.LOCAL_CHANNEL_INFO, connectionMock.getInfo()); } @Test public void connectDatagramWithInvalidAddress() { final ChannelListener channelListener = new TestChannelListener(); final ChannelListener bindListener = new TestChannelListener(); Exception expected = null; try { xnioWorker.connectDatagram(null, channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.connectDatagram(unknownSocketAddress, channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); /*expected = null; try { xnioWorker.connectDatagram(null, new LocalSocketAddress("local"), channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); */ // FIXME XNIO-192 bindAddress is now ignored expected = null; try { xnioWorker.connectDatagram(new LocalSocketAddress("local"), null, channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.connectDatagram(null, null, channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); /*expected = null; try { xnioWorker.connectDatagram(new InetSocketAddress(800), new LocalSocketAddress("local"), channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); */ // FIXME XNIO-192 now bind address is ignored expected = null; try { xnioWorker.connectDatagram(new LocalSocketAddress("local"), new InetSocketAddress(800), channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.connectDatagram(unknownSocketAddress, unknownSocketAddress, channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void acceptDatagram() throws CancellationException, IOException { final TestChannelListener channelListener = new TestChannelListener(); final TestChannelListener bindListener = new TestChannelListener(); final SocketAddress localAddress = new LocalSocketAddress("here"); final OptionMap optionMap = OptionMap.create(Options.STACK_SIZE, 990000l); final IoFuture connectedDatagramFuture = xnioWorker.acceptDatagram(localAddress, channelListener, bindListener, optionMap); assertNotNull(connectedDatagramFuture); final AssembledConnectedMessageChannel assembledChannel = (AssembledConnectedMessageChannel) connectedDatagramFuture.get(); assertTrue(channelListener.isInvoked()); assertSame(assembledChannel, channelListener.getChannel()); //assertTrue(bindListener.isInvoked()); // FIXME XNIO-192 //assertSame(assembledChannel, bindListener.getChannel()); assertEquals(localAddress, assembledChannel.getPeerAddress()); assertEquals(990000l, (long) assembledChannel.getOption(Options.STACK_SIZE)); final MessageConnectionMock connectionMock = getConnectedChannel(assembledChannel); assertSame(optionMap, connectionMock.getOptionMap()); assertEquals(XnioWorkerMock.LOCAL_CHANNEL_INFO, connectionMock.getInfo()); } @Test public void acceptDatagramWithInvalidAddress() { final TestChannelListener channelListener = new TestChannelListener(); final TestChannelListener bindListener = new TestChannelListener(); Exception expected = null; try { xnioWorker.acceptDatagram(null, channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.acceptDatagram(new InetSocketAddress(10), channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.acceptDatagram(unknownSocketAddress, channelListener, bindListener, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void createUdpServer() throws IOException { final InetSocketAddress address = new InetSocketAddress(0); final OptionMap optionMap = OptionMap.create(Options.MULTICAST, true, Options.SECURE, false); MulticastMessageChannel channel = xnioWorker.createUdpServer(address, optionMap); assertNotNull(channel); // check address assertEquals(address, channel.getLocalAddress()); // check optionMap assertTrue(channel instanceof MulticastMessageChannelMock); Mock channelMock = (Mock) channel; assertEquals(optionMap, channelMock.getOptionMap()); } @Test public void createUdpServerWithListener() throws IOException { final InetSocketAddress address = new InetSocketAddress(0); final TestChannelListener listener = new TestChannelListener(); final OptionMap optionMap = OptionMap.create(Options.MULTICAST, true, Options.SECURE, true); MulticastMessageChannel channel = xnioWorker.createUdpServer(address, listener, optionMap); assertNotNull(channel); // check address assertEquals(address, channel.getLocalAddress()); // check listener assertTrue(listener.isInvoked()); assertSame(channel, listener.getChannel()); // check optionMap assertTrue(channel instanceof MulticastMessageChannelMock); Mock channelMock = (Mock) channel; assertEquals(optionMap, channelMock.getOptionMap()); } @Test public void executeCommandsAndShutdownTaskPool() throws InterruptedException { final TestCommand command1 = new TestCommand(); final TestCommand command2 = new TestCommand(); final TestCommand command3 = new TestCommand(); final TestCommand command4 = new TestCommand(); final TestCommand command5 = new TestCommand(); xnioWorker.execute(command1); xnioWorker.execute(command2); xnioWorker.execute(command3); xnioWorker.shutDownTaskPool(); RejectedExecutionException expected = null; try { xnioWorker.execute(command4); } catch (RejectedExecutionException e) { expected = e; } assertNotNull(expected); command1.waitCompletion(); command2.waitCompletion(); command3.waitCompletion(); xnioWorker.shutDownTaskPoolNow(); expected = null; try { xnioWorker.execute(command5); } catch (RejectedExecutionException e) { expected = e; } assertNotNull(expected); } @Test public void shutdownTaskPoolNow() throws InterruptedException { final TestCommand command = new TestCommand(); xnioWorker.shutDownTaskPoolNow(); RejectedExecutionException expected = null; try { xnioWorker.execute(command); } catch (RejectedExecutionException e) { expected = e; } assertNotNull(expected); } @Test public void optionsSupported() { assertTrue(xnioWorker.supportsOption(Options.WORKER_TASK_CORE_THREADS)); assertTrue(xnioWorker.supportsOption(Options.WORKER_TASK_MAX_THREADS)); assertTrue(xnioWorker.supportsOption(Options.WORKER_TASK_KEEPALIVE)); assertFalse(xnioWorker.supportsOption(Options.ALLOW_BLOCKING)); assertFalse(xnioWorker.supportsOption(Options.MULTICAST)); assertFalse(xnioWorker.supportsOption(Options.BROADCAST)); assertFalse(xnioWorker.supportsOption(Options.CLOSE_ABORT)); assertFalse(xnioWorker.supportsOption(Options.RECEIVE_BUFFER)); assertFalse(xnioWorker.supportsOption(Options.REUSE_ADDRESSES)); assertFalse(xnioWorker.supportsOption(Options.SEND_BUFFER)); assertFalse(xnioWorker.supportsOption(Options.TCP_NODELAY)); assertFalse(xnioWorker.supportsOption(Options.MULTICAST_TTL)); assertFalse(xnioWorker.supportsOption(Options.IP_TRAFFIC_CLASS)); assertFalse(xnioWorker.supportsOption(Options.TCP_OOB_INLINE)); assertFalse(xnioWorker.supportsOption(Options.KEEP_ALIVE)); assertFalse(xnioWorker.supportsOption(Options.BACKLOG)); assertFalse(xnioWorker.supportsOption(Options.READ_TIMEOUT)); assertFalse(xnioWorker.supportsOption(Options.WRITE_TIMEOUT)); assertFalse(xnioWorker.supportsOption(Options.MAX_INBOUND_MESSAGE_SIZE)); assertFalse(xnioWorker.supportsOption(Options.MAX_OUTBOUND_MESSAGE_SIZE)); assertFalse(xnioWorker.supportsOption(Options.SSL_ENABLED)); assertFalse(xnioWorker.supportsOption(Options.SSL_CLIENT_AUTH_MODE)); assertFalse(xnioWorker.supportsOption(Options.SSL_ENABLED_CIPHER_SUITES)); assertFalse(xnioWorker.supportsOption(Options.SSL_SUPPORTED_CIPHER_SUITES)); assertFalse(xnioWorker.supportsOption(Options.SSL_ENABLED_PROTOCOLS)); assertFalse(xnioWorker.supportsOption(Options.SSL_SUPPORTED_PROTOCOLS)); assertFalse(xnioWorker.supportsOption(Options.SSL_PROVIDER)); assertFalse(xnioWorker.supportsOption(Options.SSL_PROTOCOL)); assertFalse(xnioWorker.supportsOption(Options.SSL_ENABLE_SESSION_CREATION)); assertFalse(xnioWorker.supportsOption(Options.SSL_USE_CLIENT_MODE)); assertFalse(xnioWorker.supportsOption(Options.SSL_CLIENT_SESSION_CACHE_SIZE)); assertFalse(xnioWorker.supportsOption(Options.SSL_CLIENT_SESSION_TIMEOUT)); assertFalse(xnioWorker.supportsOption(Options.SSL_SERVER_SESSION_CACHE_SIZE)); assertFalse(xnioWorker.supportsOption(Options.SSL_SERVER_SESSION_TIMEOUT)); assertFalse(xnioWorker.supportsOption(Options.SSL_JSSE_KEY_MANAGER_CLASSES)); assertFalse(xnioWorker.supportsOption(Options.SSL_JSSE_TRUST_MANAGER_CLASSES)); assertFalse(xnioWorker.supportsOption(Options.SSL_RNG_OPTIONS)); assertFalse(xnioWorker.supportsOption(Options.SSL_PACKET_BUFFER_SIZE)); assertFalse(xnioWorker.supportsOption(Options.SSL_APPLICATION_BUFFER_SIZE)); assertFalse(xnioWorker.supportsOption(Options.SSL_PACKET_BUFFER_REGION_SIZE)); assertFalse(xnioWorker.supportsOption(Options.SSL_APPLICATION_BUFFER_REGION_SIZE)); assertFalse(xnioWorker.supportsOption(Options.SSL_STARTTLS)); assertFalse(xnioWorker.supportsOption(Options.SSL_PEER_HOST_NAME)); assertFalse(xnioWorker.supportsOption(Options.SSL_PEER_PORT)); assertFalse(xnioWorker.supportsOption(Options.USE_DIRECT_BUFFERS)); assertFalse(xnioWorker.supportsOption(Options.SECURE)); assertFalse(xnioWorker.supportsOption(Options.SASL_POLICY_FORWARD_SECRECY)); assertFalse(xnioWorker.supportsOption(Options.SASL_POLICY_NOACTIVE)); assertFalse(xnioWorker.supportsOption(Options.SASL_POLICY_NOANONYMOUS)); assertFalse(xnioWorker.supportsOption(Options.SASL_POLICY_NODICTIONARY)); assertFalse(xnioWorker.supportsOption(Options.SASL_POLICY_NOPLAINTEXT)); assertFalse(xnioWorker.supportsOption(Options.SASL_POLICY_PASS_CREDENTIALS)); assertFalse(xnioWorker.supportsOption(Options.SASL_QOP)); assertFalse(xnioWorker.supportsOption(Options.SASL_STRENGTH)); assertFalse(xnioWorker.supportsOption(Options.SASL_SERVER_AUTH)); assertFalse(xnioWorker.supportsOption(Options.SASL_REUSE)); assertFalse(xnioWorker.supportsOption(Options.SASL_MECHANISMS)); assertFalse(xnioWorker.supportsOption(Options.SASL_DISALLOWED_MECHANISMS)); assertFalse(xnioWorker.supportsOption(Options.SASL_PROPERTIES)); assertFalse(xnioWorker.supportsOption(Options.FILE_ACCESS)); assertFalse(xnioWorker.supportsOption(Options.STACK_SIZE)); assertFalse(xnioWorker.supportsOption(Options.WORKER_NAME)); assertFalse(xnioWorker.supportsOption(Options.THREAD_PRIORITY)); assertFalse(xnioWorker.supportsOption(Options.THREAD_DAEMON)); assertFalse(xnioWorker.supportsOption(Options.WORKER_READ_THREADS)); assertFalse(xnioWorker.supportsOption(Options.WORKER_WRITE_THREADS)); assertFalse(xnioWorker.supportsOption(Options.WORKER_ESTABLISH_WRITING)); assertFalse(xnioWorker.supportsOption(Options.WORKER_ACCEPT_THREADS)); assertFalse(xnioWorker.supportsOption(Options.WORKER_TASK_LIMIT)); assertFalse(xnioWorker.supportsOption(Options.CORK)); assertFalse(xnioWorker.supportsOption(Options.CONNECTION_HIGH_WATER)); assertFalse(xnioWorker.supportsOption(Options.CONNECTION_LOW_WATER)); } @Test public void setAndGetOption() throws IllegalArgumentException, IOException { xnioWorker.setOption(Options.WORKER_TASK_CORE_THREADS, 3); assertEquals(3, (int) xnioWorker.setOption(Options.WORKER_TASK_CORE_THREADS, 5)); assertEquals(5, (int) xnioWorker.getOption(Options.WORKER_TASK_CORE_THREADS)); xnioWorker.setOption(Options.WORKER_TASK_MAX_THREADS, 15); assertEquals(15, (int) xnioWorker.setOption(Options.WORKER_TASK_MAX_THREADS, 8)); assertEquals(8, (int) xnioWorker.getOption(Options.WORKER_TASK_MAX_THREADS)); xnioWorker.setOption(Options.WORKER_TASK_KEEPALIVE, 500); assertEquals(500l, (int) xnioWorker.setOption(Options.WORKER_TASK_KEEPALIVE, 50)); assertEquals(50, (int) xnioWorker.getOption(Options.WORKER_TASK_KEEPALIVE)); assertNull(xnioWorker.setOption(Options.KEEP_ALIVE, true)); assertNull(xnioWorker.getOption(Options.KEEP_ALIVE)); } @Test public void optionRetrieval() throws IllegalArgumentException, IOException { final Xnio xnio = Xnio.getInstance(); final OptionMap.Builder builder = OptionMap.builder(); builder.set(Options.WORKER_NAME, "**WoRkEr**"); builder.set(Options.WORKER_TASK_LIMIT, 0x8000); builder.set(Options.WORKER_TASK_CORE_THREADS, 10); builder.set(Options.WORKER_TASK_MAX_THREADS, 20); builder.set(Options.WORKER_TASK_KEEPALIVE, 300); builder.set(Options.THREAD_DAEMON, true); xnioWorker = xnio.createWorker(builder.getMap()); assertNotNull(xnioWorker); assertEquals("**WoRkEr**", xnioWorker.getName()); assertNull(xnioWorker.getOption(Options.WORKER_NAME)); assertNull(xnioWorker.getOption(Options.WORKER_TASK_LIMIT)); assertEquals(10, (int) xnioWorker.getOption(Options.WORKER_TASK_CORE_THREADS)); assertEquals(20, (int) xnioWorker.getOption(Options.WORKER_TASK_MAX_THREADS)); assertEquals(300, (int) xnioWorker.getOption(Options.WORKER_TASK_KEEPALIVE)); } @Test public void implementationMustOverrideMethods() throws IOException { final XnioWorker xnioWorker = new XnioWorker(Xnio.getInstance(), Thread.currentThread().getThreadGroup(), OptionMap.EMPTY, new Runnable() {public void run() {}}) { @Override public void shutdown() {} @Override public List shutdownNow() {return null;} @Override public boolean isShutdown() {return false;} @Override public boolean isTerminated() {return false;} @Override public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { return false; } @Override public void awaitTermination() throws InterruptedException { } @Override public int getIoThreadCount() { return 0; } @Override protected XnioIoThread chooseThread() { return new XnioIoThreadMock(this); } }; UnsupportedOperationException expected = null; try { xnioWorker.createStreamConnectionServer(new InetSocketAddress(1000), null, null); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.createStreamConnectionServer(new LocalSocketAddress("server"), null, null); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.createUdpServer(null, null); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); } private static class TestChannelListener implements ChannelListener { private boolean invoked = false; private C channel; @Override public void handleEvent(C c) { invoked = true; channel = c; } public boolean isInvoked() { return invoked; } public C getChannel() { return channel; } } private static class TestCommand implements Runnable { private CountDownLatch latch = new CountDownLatch(1); @Override public void run() { latch.countDown(); } public void waitCompletion() throws InterruptedException { latch.await(); } } private static final Field connectedChannelField; private static final Field connectionField; static { try { connectedChannelField = AssembledConnectedStreamChannel.class.getDeclaredField("connection"); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } catch (SecurityException e) { throw new RuntimeException(e); } connectedChannelField.setAccessible(true); try { connectionField = AssembledConnectedMessageChannel.class.getDeclaredField("connection"); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } catch (SecurityException e) { throw new RuntimeException(e); } connectionField.setAccessible(true); } private StreamConnectionMock getConnectedChannel(AssembledConnectedStreamChannel assembledChannel) { try { return (StreamConnectionMock) connectedChannelField.get(assembledChannel); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } private MessageConnectionMock getConnectedChannel(AssembledConnectedMessageChannel assembledChannel) { try { return (MessageConnectionMock) connectionField.get(assembledChannel); } catch (IllegalAccessException e) { throw new RuntimeException(e); } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/channels/000077500000000000000000000000001257016060700223275ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/org/xnio/channels/AbstractBlockingReadableByteChannelTest.java000066400000000000000000000402531257016060700330070ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.xnio.AssertReadWrite.assertReadMessage; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ScatteringByteChannel; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; import org.xnio.mock.ConnectedStreamChannelMock; /** * Abstract class that contains test cases applicable to any blocking {@code ScatteringByteChannel}. * * @author Flavia Rainone */ public abstract class AbstractBlockingReadableByteChannelTest { private ConnectedStreamChannelMock channelMock; @Before public void initChannelMock() { channelMock = new ConnectedStreamChannelMock(); channelMock.enableRead(true); channelMock.enableWrite(false); } protected abstract T createBlockingReadableByteChannel(ConnectedStreamChannelMock channelMock); protected abstract T createBlockingReadableByteChannel(ConnectedStreamChannelMock channelMock, long timeout, TimeUnit timeoutUnit); protected abstract T createBlockingReadableByteChannel(ConnectedStreamChannelMock channelMock, long readTimeout, TimeUnit readTimeoutUnit, long writeTimeout, TimeUnit writeTimeoutUnit); protected abstract void setReadTimeout(T channel, long readTimeout, TimeUnit readTimeoutUnit); @Test public void simpleRead() throws Exception { final T blockingChannel = createBlockingReadableByteChannel(channelMock); channelMock.setReadData("read"); channelMock.setEof(); final ByteBuffer buffer = ByteBuffer.allocate(10); assertEquals(4, blockingChannel.read(buffer)); assertEquals(-1, blockingChannel.read(buffer)); assertReadMessage(buffer, "read"); } @Test public void readBlocksUntilReadDataAvailable() throws Exception { final T blockingChannel = createBlockingReadableByteChannel(channelMock); final Read readRunnable = new Read(blockingChannel); final Thread readThread = new Thread(readRunnable); readThread.start(); Thread.sleep(30); channelMock.setReadData("read", "all", "this", "message"); readThread.join(); assertEquals(18, readRunnable.getReadResult()); assertReadMessage(readRunnable.getReadBuffer(), "read", "all", "this", "message"); } @Test public void readBlocksWithTimeout1() throws Exception { final T blockingChannel = createBlockingReadableByteChannel(channelMock, Long.MAX_VALUE, TimeUnit.NANOSECONDS); final Read readRunnable = new Read(blockingChannel); final Thread readThread = new Thread(readRunnable); readThread.start(); Thread.sleep(50); channelMock.setReadData("a"); channelMock.setEof(); readThread.join(); assertEquals(1, readRunnable.getReadResult()); assertReadMessage(readRunnable.getReadBuffer(), "a"); } @Test public void readBlocksUntilTimeout2() throws Exception { final T blockingChannel = createBlockingReadableByteChannel(channelMock, 400, TimeUnit.MILLISECONDS, 300, TimeUnit.MINUTES); final Read readRunnable = new Read(blockingChannel); final Thread readThread = new Thread(readRunnable); readThread.start(); Thread.sleep(50); channelMock.setEof(); readThread.join(); assertEquals(-1, readRunnable.getReadResult()); assertReadMessage(readRunnable.getReadBuffer()); } @Test public void readBlocksUntilTimeout3() throws Exception { final T blockingChannel = createBlockingReadableByteChannel(channelMock, 400000000, TimeUnit.NANOSECONDS, 300, TimeUnit.NANOSECONDS); final Read readRunnable = new Read(blockingChannel); final Thread readThread = new Thread(readRunnable); readThread.start(); Thread.sleep(50); channelMock.setReadData("read "); channelMock.setEof(); readThread.join(); assertEquals(5, readRunnable.getReadResult()); assertReadMessage(readRunnable.getReadBuffer(), "read "); } @Test public void readBlocksUntilTimeout4() throws Exception { final T blockingChannel = createBlockingReadableByteChannel(channelMock); setReadTimeout(blockingChannel, 0, TimeUnit.DAYS); final Read readRunnable = new Read(blockingChannel); final Thread readThread = new Thread(readRunnable); readThread.start(); Thread.sleep(50); channelMock.setReadData("testing..."); channelMock.setEof(); readThread.join(); assertEquals(10, readRunnable.getReadResult()); assertReadMessage(readRunnable.getReadBuffer(), "testing..."); } @Test public void readBlocksUntilTimeout5() throws Exception { final T blockingChannel = createBlockingReadableByteChannel(channelMock); setReadTimeout(blockingChannel, 1, TimeUnit.SECONDS); final Read readRunnable = new Read(blockingChannel); final Thread readThread = new Thread(readRunnable); readThread.start(); Thread.sleep(50); channelMock.setReadData("try with 1 nanoseconds"); channelMock.setEof(); readThread.join(); assertEquals(20, readRunnable.getReadResult()); assertReadMessage(readRunnable.getReadBuffer(), "try with 1 nanosecon"); } @Test public void readBlocksUntilTimeout6() throws Exception { final T blockingChannel = createBlockingReadableByteChannel(channelMock); setReadTimeout(blockingChannel, 1, TimeUnit.SECONDS); final Read readRunnable = new Read(blockingChannel); final Thread readThread = new Thread(readRunnable); readThread.start(); channelMock.setReadData("wait a little longer now"); channelMock.setEof(); readThread.join(); assertEquals(20, readRunnable.getReadResult()); assertReadMessage(readRunnable.getReadBuffer(), "wait a little longer"); } @Test public void readBlocksUntilTimeout7() throws Exception { final T blockingChannel = createBlockingReadableByteChannel(channelMock, 0, TimeUnit.SECONDS); final Read readRunnable = new Read(blockingChannel); final Thread readThread = new Thread(readRunnable); readThread.start(); channelMock.setReadData("wait nothing"); channelMock.setEof(); readThread.join(); assertEquals(12, readRunnable.getReadResult()); assertReadMessage(readRunnable.getReadBuffer(), "wait nothing"); } @Test public void simpleReadWithBufferArray() throws Exception { final T blockingChannel = createBlockingReadableByteChannel(channelMock); channelMock.setReadData("a-b-c"); channelMock.setEof(); final ByteBuffer buffer = ByteBuffer.allocate(10); assertEquals(5, blockingChannel.read(new ByteBuffer[] {buffer})); assertEquals(-1, blockingChannel.read(buffer)); assertReadMessage(buffer, "a-b-c"); } @Test public void readBlocksUntilReadDataAvailableWithByteArray() throws Exception { final T blockingChannel = createBlockingReadableByteChannel(channelMock); final ReadToBufferArray readRunnable = new ReadToBufferArray(blockingChannel); final Thread readThread = new Thread(readRunnable); readThread.start(); Thread.sleep(30); channelMock.setReadData("read", "this", "all"); readThread.join(); assertEquals(11, readRunnable.getReadResult()); final ByteBuffer[] readBuffer = readRunnable.getReadBuffer(); assertReadMessage(readBuffer[0], "read", "t"); assertReadMessage(readBuffer[1], "his", "al"); assertReadMessage(readBuffer[2], "l"); assertReadMessage(readBuffer[3]); } @Test public void readBlocksWithTimeout1WithByteArray() throws Exception { final T blockingChannel = createBlockingReadableByteChannel(channelMock, 5, TimeUnit.DAYS); final ReadToBufferArray readRunnable = new ReadToBufferArray(blockingChannel); final Thread readThread = new Thread(readRunnable); readThread.start(); Thread.sleep(50); channelMock.setReadData("array"); channelMock.setEof(); readThread.join(); assertEquals(5, readRunnable.getReadResult()); final ByteBuffer[] readBuffer = readRunnable.getReadBuffer(); assertReadMessage(readBuffer[0], "array"); assertReadMessage(readBuffer[1]); assertReadMessage(readBuffer[2]); assertReadMessage(readBuffer[3]); } @Test public void readBlocksUntilTimeoutWithByteArray2() throws Exception { final T blockingChannel = createBlockingReadableByteChannel(channelMock, 509900, TimeUnit.MICROSECONDS, 300, TimeUnit.MINUTES); final ReadToBufferArray readRunnable = new ReadToBufferArray(blockingChannel); final Thread readThread = new Thread(readRunnable); readThread.start(); Thread.sleep(50); channelMock.setEof(); readThread.join(); assertEquals(-1, readRunnable.getReadResult()); final ByteBuffer[] readBuffer = readRunnable.getReadBuffer(); assertReadMessage(readBuffer[0]); assertReadMessage(readBuffer[1]); assertReadMessage(readBuffer[2]); assertReadMessage(readBuffer[3]); } @Test public void readBlocksUntilTimeoutWithByteArray3() throws Exception { final T blockingChannel = createBlockingReadableByteChannel(channelMock, 100, TimeUnit.HOURS, 3, TimeUnit.NANOSECONDS); final ReadToBufferArray readRunnable = new ReadToBufferArray(blockingChannel); final Thread readThread = new Thread(readRunnable); readThread.start(); Thread.sleep(50); channelMock.setReadData("time", "out", "!"); channelMock.setEof(); readThread.join(); assertEquals(8, readRunnable.getReadResult()); final ByteBuffer[] readBuffer = readRunnable.getReadBuffer(); assertReadMessage(readBuffer[0], "time", "o"); assertReadMessage(readBuffer[1], "ut", "!"); assertReadMessage(readBuffer[2]); assertReadMessage(readBuffer[3]); } @Test public void readBlocksUntilTimeoutWithByteArray4() throws Exception { final T blockingChannel = createBlockingReadableByteChannel(channelMock); setReadTimeout(blockingChannel, 0, TimeUnit.HOURS); final ReadToBufferArray readRunnable = new ReadToBufferArray(blockingChannel); final Thread readThread = new Thread(readRunnable); readThread.start(); Thread.sleep(50); channelMock.setReadData("1, 2, 3..."); channelMock.setEof(); readThread.join(); assertEquals(10, readRunnable.getReadResult()); final ByteBuffer[] readBuffer = readRunnable.getReadBuffer(); assertReadMessage(readBuffer[0], "1, 2,"); assertReadMessage(readBuffer[1], " 3..."); assertReadMessage(readBuffer[2]); assertReadMessage(readBuffer[3]); } @Test public void readBlocksUntilTimeoutWithBytearray5() throws Exception { final T blockingChannel = createBlockingReadableByteChannel(channelMock); setReadTimeout(blockingChannel, 30000, TimeUnit.MICROSECONDS); final ReadToBufferArray readRunnable = new ReadToBufferArray(blockingChannel); final Thread readThread = new Thread(readRunnable); readThread.start(); Thread.sleep(10); channelMock.setReadData("try with 3 microseconds"); channelMock.setEof(); readThread.join(); assertEquals(20, readRunnable.getReadResult()); final ByteBuffer[] readBuffer = readRunnable.getReadBuffer(); assertReadMessage(readBuffer[0], "try w"); assertReadMessage(readBuffer[1], "ith 3"); assertReadMessage(readBuffer[2], " micr"); assertReadMessage(readBuffer[3], "oseco"); } @Test public void readBlocksUntilTimeoutWithByteArray6() throws Exception { final T blockingChannel = createBlockingReadableByteChannel(channelMock); setReadTimeout(blockingChannel, 100, TimeUnit.MILLISECONDS); final ReadToBufferArray readRunnable = new ReadToBufferArray(blockingChannel); final Thread readThread = new Thread(readRunnable); readThread.start(); channelMock.setReadData("wait a little longer now"); channelMock.setEof(); readThread.join(); assertEquals(20, readRunnable.getReadResult()); final ByteBuffer[] readBuffer = readRunnable.getReadBuffer(); assertReadMessage(readBuffer[0], "wait "); assertReadMessage(readBuffer[1], "a lit"); assertReadMessage(readBuffer[2], "tle l"); assertReadMessage(readBuffer[3], "onger"); } // TODO wait until questions are cleared before doing this one public void readTimeOut() {} @Test public void illegalTimeout() throws Exception { boolean illegal = false; try { createBlockingReadableByteChannel(channelMock, -1, TimeUnit.HOURS, 10, TimeUnit.MICROSECONDS); } catch (IllegalArgumentException e) { illegal = true; } assertTrue(illegal); illegal = false; try { createBlockingReadableByteChannel(channelMock, -8, TimeUnit.SECONDS); } catch (IllegalArgumentException e) { illegal = true; } assertTrue(illegal); illegal = false; final T blockingChannel = createBlockingReadableByteChannel(channelMock); illegal = false; try { setReadTimeout(blockingChannel, -1000, TimeUnit.MILLISECONDS); } catch (IllegalArgumentException e) { illegal = true; } assertTrue(illegal); } @Test public void close() throws IOException { final T blockingChannel = createBlockingReadableByteChannel(channelMock); assertTrue(channelMock.isOpen()); assertTrue(blockingChannel.isOpen()); blockingChannel.close(); assertFalse(channelMock.isOpen()); assertFalse(blockingChannel.isOpen()); } private class Read implements Runnable { private final ByteBuffer buffer; private final T channel; private int readResult; public Read(T c) { channel = c; buffer = ByteBuffer.allocate(20); } @Override public void run() { try { readResult = channel.read(buffer); } catch (IOException e) { throw new RuntimeException(e); } } public int getReadResult() { return readResult; } public ByteBuffer getReadBuffer() { return buffer; } } private class ReadToBufferArray implements Runnable { private final ByteBuffer[] buffer; private final T channel; private long readResult; public ReadToBufferArray(T c) { channel = c; buffer = new ByteBuffer[] {ByteBuffer.allocate(5), ByteBuffer.allocate(5), ByteBuffer.allocate(5), ByteBuffer.allocate(5)}; } @Override public void run() { try { readResult = channel.read(buffer); } catch (IOException e) { throw new RuntimeException(e); } } public long getReadResult() { return readResult; } public ByteBuffer[] getReadBuffer() { return buffer; } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/channels/AbstractBlockingWritableByteChannelTest.java000066400000000000000000000513521257016060700330630ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.xnio.AssertReadWrite.assertWrittenMessage; import java.io.Flushable; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.GatheringByteChannel; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; import org.xnio.mock.ConnectedStreamChannelMock; /** * Abstract class that contains test cases applicable to any blocking {@code GatheringByteChannel}, {@code Flushable}. * * @author Flavia Rainone */ public abstract class AbstractBlockingWritableByteChannelTest { private ConnectedStreamChannelMock channelMock; @Before public void initChannelMock() { channelMock = new ConnectedStreamChannelMock(); channelMock.enableRead(true); channelMock.enableWrite(false); } protected abstract T createBlockingWritableByteChannel(ConnectedStreamChannelMock channelMock); protected abstract T createBlockingWritableByteChannel(ConnectedStreamChannelMock channelMock, long timeout, TimeUnit timeoutUnit); protected abstract T createBlockingWritableByteChannel(ConnectedStreamChannelMock channelMock, long readTimeout, TimeUnit readTimeoutUnit, long writeTimeout, TimeUnit writeTimeoutUnit); protected abstract void setWriteTimeout(T channel, long writeTimeout, TimeUnit writeTimeoutUnit); @Test public void simpleWrite() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock); channelMock.enableWrite(true); final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("write".getBytes("UTF-8")).flip(); assertEquals(5, blockingChannel.write(buffer)); assertWrittenMessage(channelMock, "write"); } @Test public void simpleWriteWithTimeout() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock); setWriteTimeout(blockingChannel, 100, TimeUnit.MILLISECONDS); channelMock.enableWrite(true); final ByteBuffer buffer = ByteBuffer.allocate(20); buffer.put("write with timeout".getBytes("UTF-8")).flip(); assertEquals(18, blockingChannel.write(buffer)); assertWrittenMessage(channelMock, "write with timeout"); } @Test public void simpleEmptyWriteWithTimeout() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock); setWriteTimeout(blockingChannel, 15, TimeUnit.MILLISECONDS); channelMock.enableWrite(true); final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.flip(); assertEquals(0, blockingChannel.write(buffer)); assertWrittenMessage(channelMock); } @Test public void writeBlocks() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock); final Write writeRunnable = new Write(blockingChannel, "message"); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); Thread.sleep(30); channelMock.enableWrite(true); writeThread.join(); assertEquals(7, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, "message"); } @Test public void writeBlocksWithTimeout1() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock, Long.MAX_VALUE, TimeUnit.NANOSECONDS); final Write writeRunnable = new Write(blockingChannel, "j"); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); Thread.sleep(50); channelMock.enableWrite(true); writeThread.join(); assertEquals(1, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, "j"); } @Test public void writeBlocksUntilTimeout2() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock, 0, TimeUnit.MILLISECONDS, 0, TimeUnit.MINUTES); final Write writeRunnable = new Write(blockingChannel, ""); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); Thread.sleep(50); channelMock.enableWrite(true); writeThread.join(); assertEquals(0, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, ""); } @Test public void writeBlocksUntilTimeout3() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock, 0, TimeUnit.NANOSECONDS, 30000000, TimeUnit.NANOSECONDS); final Write writeRunnable = new Write(blockingChannel, "write... this"); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); Thread.sleep(20); channelMock.enableWrite(true); writeThread.join(); assertEquals(13, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, "write... this"); } @Test public void writeBlocksUntilTimeout4() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock); setWriteTimeout(blockingChannel, 0, TimeUnit.DAYS); final Write writeRunnable = new Write(blockingChannel, "123456"); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); Thread.sleep(50); channelMock.enableWrite(true); writeThread.join(); assertEquals(6, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, "123456"); } @Test public void writeBlocksUntilTimeout5() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock); setWriteTimeout(blockingChannel, 2, TimeUnit.MICROSECONDS); final Write writeRunnable = new Write(blockingChannel, "try with 1 microsecond"); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); channelMock.enableWrite(true); writeThread.join(); assertEquals(22, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, "try with 1 microsecond"); } @Test public void writeBlocksUntilTimeout6() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock); setWriteTimeout(blockingChannel, 10, TimeUnit.MILLISECONDS); final Write writeRunnable = new Write(blockingChannel, "wait just 10 milliseconds"); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); channelMock.enableWrite(true); writeThread.join(); assertEquals(25, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, "wait just 10 milliseconds"); } @Test public void writeBlocksUntilTimeout7() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock, 0, TimeUnit.MILLISECONDS); final Write writeRunnable = new Write(blockingChannel, "wait nothing"); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); channelMock.enableWrite(true); writeThread.join(); assertEquals(12, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, "wait nothing"); } @Test public void simpleWriteWithBufferArray() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock); channelMock.enableWrite(true); final ByteBuffer[] buffer = new ByteBuffer[]{null, ByteBuffer.allocate(10), ByteBuffer.allocate(0)}; buffer[1].put("write".getBytes("UTF-8")).flip(); assertEquals(5, blockingChannel.write(buffer, 1, 2)); assertWrittenMessage(channelMock, "write"); } @Test public void simpleEmptyWriteWithBufferArray() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock); channelMock.enableWrite(true); final ByteBuffer[] buffer = new ByteBuffer[]{ByteBuffer.allocate(10), ByteBuffer.allocate(0)}; buffer[0].flip(); buffer[1].flip(); assertEquals(0, blockingChannel.write(buffer, 0, 1)); assertWrittenMessage(channelMock); } @Test public void simpleWriteBufferArrayWithTimeou() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock); setWriteTimeout(blockingChannel, 100, TimeUnit.MILLISECONDS); channelMock.enableWrite(true); final ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(10), ByteBuffer.allocate(10), ByteBuffer.allocate(10)}; buffer[0].put("write with".getBytes("UTF-8")).flip(); buffer[1].put(" timeout".getBytes("UTF-8")).flip(); buffer[2].flip(); assertEquals(18, blockingChannel.write(buffer)); assertWrittenMessage(channelMock, "write with timeout"); } @Test public void simpleEmptyWriteWithBufferArrayWithTimeout() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock); setWriteTimeout(blockingChannel, 5, TimeUnit.MILLISECONDS); channelMock.enableWrite(true); final ByteBuffer[] buffer = new ByteBuffer[]{ByteBuffer.allocate(10), ByteBuffer.allocate(0)}; buffer[0].flip(); buffer[1].flip(); assertEquals(0, blockingChannel.write(buffer, 0, 1)); assertWrittenMessage(channelMock); } @Test public void writeBufferArrayBlocks() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock); final WriteBufferArray writeRunnable = new WriteBufferArray(blockingChannel, "mess", "age"); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); Thread.sleep(30); channelMock.enableWrite(true); writeThread.join(); assertEquals(7, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, "message"); } @Test public void writeBufferArrayBlocksWithTimeout1() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock, 50000, TimeUnit.SECONDS); final WriteBufferArray writeRunnable = new WriteBufferArray(blockingChannel, "a"); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); Thread.sleep(10); channelMock.enableWrite(true); writeThread.join(); assertEquals(1, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, "a"); } @Test public void writeBufferArrayBlocksUntilTimeout2() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock, 0, TimeUnit.MILLISECONDS, 0, TimeUnit.MINUTES); final WriteBufferArray writeRunnable = new WriteBufferArray(blockingChannel); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); Thread.sleep(50); channelMock.enableWrite(true); writeThread.join(); assertEquals(0, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, ""); } @Test public void writeBufferArrayBlocksUntilTimeout3() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock, 0, TimeUnit.NANOSECONDS, 30, TimeUnit.MINUTES); final WriteBufferArray writeRunnable = new WriteBufferArray(blockingChannel, "write", "anything", "...", "like", "this"); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); Thread.sleep(5); channelMock.enableWrite(true); writeThread.join(); assertEquals(24, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, "write", "anything", "...", "like", "this"); } @Test public void writeBuffeArrayBlocksUntilTimeout4() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock); setWriteTimeout(blockingChannel, 0, TimeUnit.DAYS); final WriteBufferArray writeRunnable = new WriteBufferArray(blockingChannel, "78910"); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); Thread.sleep(50); channelMock.enableWrite(true); writeThread.join(); assertEquals(5, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, "78910"); } @Test public void writeBufferArrayBlocksUntilTimeout5() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock); setWriteTimeout(blockingChannel, 2, TimeUnit.MICROSECONDS); final WriteBufferArray writeRunnable = new WriteBufferArray(blockingChannel, "2", "microseconds"); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); channelMock.enableWrite(true); writeThread.join(); assertEquals(13, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, "2", "microseconds"); } @Test public void writeBufferArrayBlocksUntilTimeout6() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock); setWriteTimeout(blockingChannel, 10, TimeUnit.MILLISECONDS); final WriteBufferArray writeRunnable = new WriteBufferArray(blockingChannel, "10", "milliseconds"); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); channelMock.enableWrite(true); writeThread.join(); assertEquals(14, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, "10", "milliseconds"); } @Test public void writeBufferArrayBlocksUntilTimeout7() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock, 11000000, TimeUnit.NANOSECONDS); final WriteBufferArray writeRunnable = new WriteBufferArray(blockingChannel, "wait almost"," nothing"); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); channelMock.enableWrite(true); writeThread.join(); assertEquals(19, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, "wait almost", " nothing"); } // TODO wait until questions are cleared before doing this one public void writeTimeOut() {} @Test public void flush() throws IOException { channelMock.enableWrite(true); final T blockingChannel = createBlockingWritableByteChannel(channelMock); assertTrue(channelMock.isFlushed()); blockingChannel.flush(); assertTrue(channelMock.isFlushed()); final ByteBuffer buffer = ByteBuffer.allocate(5); buffer.put("5".getBytes("UTF-8")).flip(); assertEquals(1, blockingChannel.write(buffer)); assertWrittenMessage(channelMock, "5"); assertFalse(channelMock.isFlushed()); blockingChannel.flush(); assertTrue(channelMock.isFlushed()); } @Test public void flushWithTimeout() throws IOException { channelMock.enableWrite(true); final T blockingChannel = createBlockingWritableByteChannel(channelMock); setWriteTimeout(blockingChannel, 500, TimeUnit.HOURS); assertTrue(channelMock.isFlushed()); blockingChannel.flush(); assertTrue(channelMock.isFlushed()); final ByteBuffer buffer = ByteBuffer.allocate(5); buffer.put("500".getBytes("UTF-8")).flip(); assertEquals(3, blockingChannel.write(buffer)); assertWrittenMessage(channelMock, "500"); assertFalse(channelMock.isFlushed()); blockingChannel.flush(); assertTrue(channelMock.isFlushed()); } @Test public void flushBlocks() throws Exception { final T blockingChannel = createBlockingWritableByteChannel(channelMock); final Write writeRunnable = new Write(blockingChannel, "test", true); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); Thread.sleep(50); channelMock.enableFlush(false); channelMock.enableWrite(true); Thread.sleep(50); channelMock.enableFlush(true); writeThread.join(); assertEquals(4, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, "test"); assertTrue(channelMock.isFlushed()); } @Test public void flushWithTimeoutBlocks() throws Exception { channelMock.enableFlush(false); channelMock.enableWrite(true); final T blockingChannel = createBlockingWritableByteChannel(channelMock); setWriteTimeout(blockingChannel, 1, TimeUnit.HOURS); final Write writeRunnable = new Write(blockingChannel, "test2", true); final Thread writeThread = new Thread(writeRunnable); writeThread.start(); Thread.sleep(50); channelMock.enableFlush(true); writeThread.join(); assertEquals(5, writeRunnable.getWriteResult()); assertWrittenMessage(channelMock, "test2"); assertTrue(channelMock.isFlushed()); } @Test public void illegalTimeout() throws Exception { boolean illegal = false; try { createBlockingWritableByteChannel(channelMock, 10, TimeUnit.MICROSECONDS, -3, TimeUnit.DAYS); } catch (IllegalArgumentException e) { illegal = true; } assertTrue(illegal); illegal = false; try { createBlockingWritableByteChannel(channelMock, -8, TimeUnit.SECONDS); } catch (IllegalArgumentException e) { illegal = true; } assertTrue(illegal); illegal = false; final T blockingChannel = createBlockingWritableByteChannel(channelMock); illegal = false; try { setWriteTimeout(blockingChannel, -20, TimeUnit.MINUTES); } catch (IllegalArgumentException e) { illegal = true; } assertTrue(illegal); } @Test public void close() throws IOException { final T blockingChannel = createBlockingWritableByteChannel(channelMock); assertTrue(channelMock.isOpen()); assertTrue(blockingChannel.isOpen()); blockingChannel.close(); assertFalse(channelMock.isOpen()); assertFalse(blockingChannel.isOpen()); } private class Write implements Runnable { private final String message; private final T channel; private final boolean flush; private int writeResult; public Write(T c, String m) { this(c, m, false); } public Write(T c, String m, boolean f) { channel = c; message = m; flush = f; } @Override public void run() { ByteBuffer buffer = ByteBuffer.allocate(30); try { buffer.put(message.getBytes("UTF-8")).flip(); writeResult = channel.write(buffer); if (flush) { channel.flush(); } } catch (IOException e) { throw new RuntimeException(e); } } public int getWriteResult() { return writeResult; } } private class WriteBufferArray implements Runnable { private final String[] message; private final T channel; private long writeResult; public WriteBufferArray(T c, String... m) { channel = c; message = m; } @Override public void run() { final ByteBuffer[] buffer = new ByteBuffer[message.length]; try { for (int i = 0; i < buffer.length; i++) { buffer[i] = ByteBuffer.allocate(message[i].length()); buffer[i].put(message[i].getBytes("UTF-8")).flip(); } writeResult = channel.write(buffer); } catch (IOException e) { throw new RuntimeException(e); } } public long getWriteResult() { return writeResult; } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/channels/BlockingByteChannelReadTestCase.java000066400000000000000000000040611257016060700312700ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import java.util.concurrent.TimeUnit; import org.xnio.mock.ConnectedStreamChannelMock; /** * Test for {@link BlockingByteChannel} read-related operations. * * @author Flavia Rainone * */ public class BlockingByteChannelReadTestCase extends AbstractBlockingReadableByteChannelTest { @Override protected BlockingByteChannel createBlockingReadableByteChannel(ConnectedStreamChannelMock channelMock) { return new BlockingByteChannel(channelMock); } @Override protected BlockingByteChannel createBlockingReadableByteChannel(ConnectedStreamChannelMock channelMock, long timeout, TimeUnit timeoutUnit) { return new BlockingByteChannel(channelMock, timeout, timeoutUnit); } @Override protected BlockingByteChannel createBlockingReadableByteChannel(ConnectedStreamChannelMock channelMock, long readTimeout, TimeUnit readTimeoutUnit, long writeTimeout, TimeUnit writeTimeoutUnit) { return new BlockingByteChannel(channelMock, readTimeout, readTimeoutUnit, writeTimeout, writeTimeoutUnit); } @Override protected void setReadTimeout(BlockingByteChannel channel, long readTimeout, TimeUnit readTimeoutUnit) { channel.setReadTimeout(readTimeout, readTimeoutUnit); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/channels/BlockingByteChannelWriteTestCase.java000066400000000000000000000040701257016060700315070ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import java.util.concurrent.TimeUnit; import org.xnio.mock.ConnectedStreamChannelMock; /** * Test for {@link BlockingByteChannel} write-related operations. * * @author Flavia Rainone */ public class BlockingByteChannelWriteTestCase extends AbstractBlockingWritableByteChannelTest { @Override protected BlockingByteChannel createBlockingWritableByteChannel(ConnectedStreamChannelMock channelMock) { return new BlockingByteChannel(channelMock); } @Override protected BlockingByteChannel createBlockingWritableByteChannel(ConnectedStreamChannelMock channelMock, long timeout, TimeUnit timeoutUnit) { return new BlockingByteChannel(channelMock, timeout, timeoutUnit); } @Override protected BlockingByteChannel createBlockingWritableByteChannel(ConnectedStreamChannelMock channelMock, long readTimeout, TimeUnit readTimeoutUnit, long writeTimeout, TimeUnit writeTimeoutUnit) { return new BlockingByteChannel(channelMock, readTimeout, readTimeoutUnit, writeTimeout, writeTimeoutUnit); } @Override protected void setWriteTimeout(BlockingByteChannel channel, long writeTimeout, TimeUnit writeTimeoutUnit) { channel.setWriteTimeout(writeTimeout, writeTimeoutUnit); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/channels/BlockingReadableByteChannelTestCase.java000066400000000000000000000041271257016060700321170ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import java.util.concurrent.TimeUnit; import org.xnio.mock.ConnectedStreamChannelMock; /** * Test for {@link BlockingReadableByteChannel}. * * @author Flavia Rainone * */ public class BlockingReadableByteChannelTestCase extends AbstractBlockingReadableByteChannelTest { @Override protected BlockingReadableByteChannel createBlockingReadableByteChannel(ConnectedStreamChannelMock channelMock) { return new BlockingReadableByteChannel(channelMock); } @Override protected BlockingReadableByteChannel createBlockingReadableByteChannel(ConnectedStreamChannelMock channelMock, long timeout, TimeUnit timeoutUnit) { return new BlockingReadableByteChannel(channelMock, timeout, timeoutUnit); } @Override protected BlockingReadableByteChannel createBlockingReadableByteChannel(ConnectedStreamChannelMock channelMock, long readTimeout, TimeUnit readTimeoutUnit, long writeTimeout, TimeUnit writeTimeoutUnit) { return new BlockingReadableByteChannel(channelMock, readTimeout, readTimeoutUnit); } @Override protected void setReadTimeout(BlockingReadableByteChannel blockingChannel, long readTimeout, TimeUnit readTimeoutUnit) { blockingChannel.setReadTimeout(readTimeout, readTimeoutUnit); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/channels/BlockingWritableByteChannelTestCase.java000066400000000000000000000041141257016060700321650ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import java.util.concurrent.TimeUnit; import org.xnio.mock.ConnectedStreamChannelMock; /** * Test for {@link BlockingWritableByteChannel}. * * @author Flavia Rainone */ public class BlockingWritableByteChannelTestCase extends AbstractBlockingWritableByteChannelTest { @Override protected BlockingWritableByteChannel createBlockingWritableByteChannel(ConnectedStreamChannelMock channelMock) { return new BlockingWritableByteChannel(channelMock); } @Override protected BlockingWritableByteChannel createBlockingWritableByteChannel(ConnectedStreamChannelMock channelMock, long timeout, TimeUnit timeoutUnit) { return new BlockingWritableByteChannel(channelMock, timeout, timeoutUnit); } @Override protected BlockingWritableByteChannel createBlockingWritableByteChannel(ConnectedStreamChannelMock channelMock, long readTimeout, TimeUnit readTimeoutUnit, long writeTimeout, TimeUnit writeTimeoutUnit) { return new BlockingWritableByteChannel(channelMock, writeTimeout, writeTimeoutUnit); } @Override protected void setWriteTimeout(BlockingWritableByteChannel channel, long writeTimeout, TimeUnit writeTimeoutUnit) { channel.setWriteTimeout(writeTimeout, writeTimeoutUnit); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/channels/ChannelsTestCase.java000066400000000000000000001334441257016060700263720ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.xnio.AssertReadWrite.assertReadMessage; import static org.xnio.AssertReadWrite.assertWrittenMessage; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; import org.xnio.Buffers; import org.xnio.ChannelListener; import org.xnio.Option; import org.xnio.Options; import org.xnio.StreamConnection; import org.xnio.mock.AcceptingChannelMock; import org.xnio.mock.ConnectedStreamChannelMock; import org.xnio.mock.MessageChannelMock; /** * Test for {@link Channels}. * * @author Flavia Rainone */ public class ChannelsTestCase { private ConnectedStreamChannelMock connectedChannelMock; private MessageChannelMock messageChannelMock; @Before public void init() { connectedChannelMock = new ConnectedStreamChannelMock(); messageChannelMock = new MessageChannelMock(connectedChannelMock); } @Test public void flushBlocking() throws IOException, InterruptedException { assertTrue(connectedChannelMock.isFlushed()); Channels.flushBlocking(connectedChannelMock); assertTrue(connectedChannelMock.isFlushed()); connectedChannelMock.enableFlush(false); ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("10".getBytes("UTF-8")).flip(); assertEquals(2, connectedChannelMock.write(buffer)); assertWrittenMessage(connectedChannelMock, "10"); assertFalse(connectedChannelMock.isFlushed()); FlushBlocking flushRunnable = new FlushBlocking(connectedChannelMock); Thread flushThread = new Thread(flushRunnable); flushThread.start(); flushThread.join(50); assertTrue(flushThread.isAlive()); Thread.sleep(100); connectedChannelMock.enableFlush(true); flushThread.join(); assertFalse(flushThread.isAlive()); } @Test public void shutdownWritesBlocking() throws IOException, InterruptedException { connectedChannelMock.enableFlush(false); ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("shutdown".getBytes("UTF-8")).flip(); assertEquals(8, connectedChannelMock.write(buffer)); assertWrittenMessage(connectedChannelMock, "shutdown"); assertFalse(connectedChannelMock.isShutdownWrites()); assertFalse(connectedChannelMock.isFlushed()); ShutdownWritesBlocking shutdownWritesRunnable = new ShutdownWritesBlocking(connectedChannelMock); Thread shutdownThread = new Thread(shutdownWritesRunnable); shutdownThread.start(); shutdownThread.join(50); assertTrue(shutdownThread.isAlive()); Thread.sleep(100); connectedChannelMock.enableFlush(true); shutdownThread.join(); assertFalse(shutdownThread.isAlive()); assertTrue(connectedChannelMock.isShutdownWrites()); assertTrue(connectedChannelMock.isFlushed()); } @Test public void writeBlocking() throws IOException, InterruptedException { connectedChannelMock.enableWrite(false); WriteBlocking writeRunnable = new WriteBlocking(connectedChannelMock, "write this"); Thread writeThread = new Thread(writeRunnable); writeThread.start(); writeThread.join(50); assertTrue(writeThread.isAlive()); Thread.sleep(200); connectedChannelMock.enableWrite(true); writeThread.join(); assertFalse(writeThread.isAlive()); assertEquals(10, writeRunnable.getWriteResult()); assertWrittenMessage(connectedChannelMock, "write this"); } @Test public void writeBlockingWithTimeout() throws IOException, InterruptedException { connectedChannelMock.enableWrite(false); WriteBlocking writeRunnable = new WriteBlocking(connectedChannelMock, "write with timeout", 1000, TimeUnit.MICROSECONDS); Thread writeThread = new Thread(writeRunnable); writeThread.start(); writeThread.join(); assertWrittenMessage(connectedChannelMock); connectedChannelMock.enableWrite(true); writeThread = new Thread(writeRunnable); writeThread.start(); writeThread.join(); assertEquals(18, writeRunnable.getWriteResult()); assertWrittenMessage(connectedChannelMock, "write with timeout"); } @Test public void writeBufferArrayBlocking() throws IOException, InterruptedException { connectedChannelMock.enableWrite(false); WriteBufferArrayBlocking writeRunnable = new WriteBufferArrayBlocking(connectedChannelMock, "write", " this"); Thread writeThread = new Thread(writeRunnable); writeThread.start(); writeThread.join(50); assertTrue(writeThread.isAlive()); Thread.sleep(200); connectedChannelMock.enableWrite(true); writeThread.join(); assertFalse(writeThread.isAlive()); assertEquals(10, writeRunnable.getWriteResult()); assertWrittenMessage(connectedChannelMock, "write this"); } @Test public void writeBufferArrayBlockingWithTimeout() throws IOException, InterruptedException { connectedChannelMock.enableWrite(false); WriteBufferArrayBlocking writeRunnable = new WriteBufferArrayBlocking(connectedChannelMock, 1000, TimeUnit.MILLISECONDS, "write", "with", "timeout"); Thread writeThread = new Thread(writeRunnable); writeThread.start(); writeThread.join(); assertWrittenMessage(connectedChannelMock); connectedChannelMock.enableWrite(true); writeThread = new Thread(writeRunnable); writeThread.start(); writeThread.join(); assertEquals(16, writeRunnable.getWriteResult()); assertWrittenMessage(connectedChannelMock, "write", "with", "timeout"); } @Test public void sendBlocking() throws IOException, InterruptedException { connectedChannelMock.enableWrite(false); SendBlocking sendRunnable = new SendBlocking(messageChannelMock, "send this"); Thread sendThread = new Thread(sendRunnable); sendThread.start(); sendThread.join(50); assertTrue(sendThread.isAlive()); Thread.sleep(200); connectedChannelMock.enableWrite(true); sendThread.join(); assertFalse(sendThread.isAlive()); assertWrittenMessage(connectedChannelMock, "send this"); } @Test public void sendBlockingWithTimeout() throws IOException, InterruptedException { connectedChannelMock.enableWrite(false); SendBlocking sendRunnable = new SendBlocking(messageChannelMock, "send with timeout", 1000, TimeUnit.MICROSECONDS); Thread sendThread = new Thread(sendRunnable); sendThread.start(); sendThread.join(); assertFalse(sendRunnable.getSendResult()); assertWrittenMessage(connectedChannelMock); connectedChannelMock.enableWrite(true); sendThread = new Thread(sendRunnable); sendThread.start(); sendThread.join(); assertTrue(sendRunnable.getSendResult()); assertWrittenMessage(connectedChannelMock, "send with timeout"); } @Test public void sendBufferArrayBlocking() throws IOException, InterruptedException { connectedChannelMock.enableWrite(false); SendBufferArrayBlocking sendRunnable = new SendBufferArrayBlocking(messageChannelMock, "send", " this"); Thread sendThread = new Thread(sendRunnable); sendThread.start(); sendThread.join(50); assertTrue(sendThread.isAlive()); Thread.sleep(200); connectedChannelMock.enableWrite(true); sendThread.join(); assertFalse(sendThread.isAlive()); assertWrittenMessage(connectedChannelMock, "send this"); } @Test public void sendBufferArrayBlockingWithTimeout() throws IOException, InterruptedException { connectedChannelMock.enableWrite(false); SendBufferArrayBlocking sendRunnable = new SendBufferArrayBlocking(messageChannelMock, 1000, TimeUnit.MILLISECONDS, "send", "with", "timeout"); Thread sendThread = new Thread(sendRunnable); sendThread.start(); sendThread.join(); assertFalse(sendRunnable.getSendResult()); assertWrittenMessage(connectedChannelMock); connectedChannelMock.enableWrite(true); sendThread = new Thread(sendRunnable); sendThread.start(); sendThread.join(); assertTrue(sendRunnable.getSendResult()); assertWrittenMessage(connectedChannelMock, "send", "with", "timeout"); } @Test public void readBlocking() throws IOException, InterruptedException { connectedChannelMock.setReadData("read this"); ReadBlocking readRunnable = new ReadBlocking(connectedChannelMock); Thread readThread = new Thread(readRunnable); readThread.start(); readThread.join(50); assertTrue(readThread.isAlive()); Thread.sleep(200); connectedChannelMock.enableRead(true); readThread.join(); assertFalse(readThread.isAlive()); assertEquals(9, readRunnable.getReadResult()); assertReadMessage(readRunnable.getReadBuffer(), "read this"); } @Test public void readBlockingToEmptyBuffer() throws IOException, InterruptedException { connectedChannelMock.setReadData("can't read this"); ReadBlocking readRunnable = new ReadBlocking(connectedChannelMock, Buffers.EMPTY_BYTE_BUFFER); Thread readThread = new Thread(readRunnable); readThread.start(); readThread.join(); assertFalse(readThread.isAlive()); assertEquals(0, readRunnable.getReadResult()); } @Test public void readBlockingWithTimeout() throws IOException, InterruptedException { connectedChannelMock.setReadData("read with timeout"); ReadBlocking readRunnable = new ReadBlocking(connectedChannelMock, 100, TimeUnit.MILLISECONDS); Thread readThread = new Thread(readRunnable); readThread.start(); readThread.join(); assertEquals(0, readRunnable.getReadResult()); connectedChannelMock.enableRead(true); readThread = new Thread(readRunnable); readThread.start(); readThread.join(); assertEquals(17, readRunnable.getReadResult()); assertReadMessage(readRunnable.getReadBuffer(), "read with timeout"); } @Test public void readBlockingWithTimeoutToEmptyBuffer() throws IOException, InterruptedException { connectedChannelMock.setReadData("can't read this"); ReadBlocking readRunnable = new ReadBlocking(connectedChannelMock, 100, TimeUnit.MILLISECONDS, Buffers.EMPTY_BYTE_BUFFER); Thread readThread = new Thread(readRunnable); readThread.start(); readThread.join(); assertEquals(0, readRunnable.getReadResult()); connectedChannelMock.enableRead(true); readThread = new Thread(readRunnable); readThread.start(); readThread.join(); assertEquals(0, readRunnable.getReadResult()); } @Test public void readBlockingToBufferArray() throws IOException, InterruptedException { connectedChannelMock.setReadData("read", "this"); ReadToBufferArrayBlocking readRunnable = new ReadToBufferArrayBlocking(connectedChannelMock); Thread readThread = new Thread(readRunnable); readThread.start(); readThread.join(50); assertTrue(readThread.isAlive()); Thread.sleep(200); connectedChannelMock.enableRead(true); readThread.join(); assertFalse(readThread.isAlive()); assertEquals(8, readRunnable.getReadResult()); ByteBuffer[] readBuffer = readRunnable.getReadBuffer(); assertReadMessage(readBuffer[0], "read", "t"); assertReadMessage(readBuffer[1], "his"); assertReadMessage(readBuffer[2]); assertReadMessage(readBuffer[3]); } @Test public void readBlockingToBufferArrayWithTimeout() throws IOException, InterruptedException { connectedChannelMock.setReadData("read", "with", "timeout"); ReadToBufferArrayBlocking readRunnable = new ReadToBufferArrayBlocking(connectedChannelMock, 1000, TimeUnit.MILLISECONDS); Thread readThread = new Thread(readRunnable); readThread.start(); readThread.join(); assertEquals(0, readRunnable.getReadResult()); connectedChannelMock.enableRead(true); readThread = new Thread(readRunnable); readThread.start(); readThread.join(); assertEquals(15, readRunnable.getReadResult()); ByteBuffer[] readBuffer = readRunnable.getReadBuffer(); assertReadMessage(readBuffer[0], "read", "w"); assertReadMessage(readBuffer[1], "ith", "ti"); assertReadMessage(readBuffer[2], "meout"); assertReadMessage(readBuffer[3]); } @Test public void readBlockingToEmptyBufferArrayWithTimeout() throws IOException, InterruptedException { connectedChannelMock.setReadData("can't read this"); assertEquals(0, Channels.readBlocking(connectedChannelMock, new ByteBuffer[0], 0, 0, 2, TimeUnit.MINUTES)); } @Test public void receiveBlocking() throws IOException, InterruptedException { connectedChannelMock.setReadData("receive this"); ReceiveBlocking receiveRunnable = new ReceiveBlocking(messageChannelMock); Thread receiveThread = new Thread(receiveRunnable); receiveThread.start(); receiveThread.join(50); assertTrue(receiveThread.isAlive()); Thread.sleep(200); connectedChannelMock.enableRead(true); receiveThread.join(); assertFalse(receiveThread.isAlive()); assertEquals(12, receiveRunnable.getReceiveResult()); assertReadMessage(receiveRunnable.getReceiveBuffer(), "receive this"); } @Test public void receiveBlockingWithTimeout() throws IOException, InterruptedException { connectedChannelMock.setReadData("receive with timeout"); ReceiveBlocking receiveRunnable = new ReceiveBlocking(messageChannelMock, 100, TimeUnit.MILLISECONDS); Thread receiveThread = new Thread(receiveRunnable); receiveThread.start(); receiveThread.join(); assertEquals(0, receiveRunnable.getReceiveResult()); connectedChannelMock.enableRead(true); receiveThread = new Thread(receiveRunnable); receiveThread.start(); receiveThread.join(); assertEquals(20, receiveRunnable.getReceiveResult()); assertReadMessage(receiveRunnable.getReceiveBuffer(), "receive with timeout"); } @Test public void receiveBufferArrayBlocking() throws IOException, InterruptedException { connectedChannelMock.setReadData("receive", "this"); ReceiveBufferArrayBlocking receiveRunnable = new ReceiveBufferArrayBlocking(messageChannelMock); Thread receiveThread = new Thread(receiveRunnable); receiveThread.start(); receiveThread.join(50); assertTrue(receiveThread.isAlive()); Thread.sleep(200); connectedChannelMock.enableRead(true); receiveThread.join(); assertFalse(receiveThread.isAlive()); assertEquals(11, receiveRunnable.getReceiveResult()); ByteBuffer[] receiveBuffer = receiveRunnable.getReceiveBuffer(); assertReadMessage(receiveBuffer[0], "recei"); assertReadMessage(receiveBuffer[1], "ve", "thi"); assertReadMessage(receiveBuffer[2], "s"); assertReadMessage(receiveBuffer[3]); } @Test public void receiveBufferArrayBlockingWithTimeout() throws IOException, InterruptedException { connectedChannelMock.setReadData("receive", "with", "timeout"); ReceiveBufferArrayBlocking receiveRunnable = new ReceiveBufferArrayBlocking(messageChannelMock, 1000, TimeUnit.MILLISECONDS); Thread receiveThread = new Thread(receiveRunnable); receiveThread.start(); receiveThread.join(); assertEquals(0, receiveRunnable.getReceiveResult()); connectedChannelMock.enableRead(true); receiveThread = new Thread(receiveRunnable); receiveThread.start(); receiveThread.join(); assertEquals(18, receiveRunnable.getReceiveResult()); ByteBuffer[] receiveBuffer = receiveRunnable.getReceiveBuffer(); assertReadMessage(receiveBuffer[0], "recei"); assertReadMessage(receiveBuffer[1], "ve", "wit"); assertReadMessage(receiveBuffer[2], "h", "time"); assertReadMessage(receiveBuffer[3], "out"); } @Test public void acceptBlocking() throws IOException, InterruptedException { final AcceptingChannelMock acceptingChannelMock = new AcceptingChannelMock(); final AcceptBlocking acceptBlockingRunnable = new AcceptBlocking(acceptingChannelMock); final Thread acceptChannelThread = new Thread(acceptBlockingRunnable); assertNotNull(Channels.acceptBlocking(acceptingChannelMock)); assertFalse(acceptingChannelMock.haveWaitedAcceptable()); // try to accept in another thread, while acceptance has been disabled acceptingChannelMock.enableAcceptance(false); acceptChannelThread.start(); acceptChannelThread.join(200); assertTrue(acceptChannelThread.isAlive()); // enable acceptance so that acceptChannelThread can finish acceptingChannelMock.enableAcceptance(true); acceptChannelThread.join(); // check that accepting channel received at least once call to waitAcceptable assertTrue(acceptingChannelMock.haveWaitedAcceptable()); assertNotNull(acceptBlockingRunnable.getAcceptedChannel()); } @Test public void acceptBlockingWithTimeout() throws IOException, InterruptedException { final AcceptingChannelMock acceptingChannelMock = new AcceptingChannelMock(); final AcceptBlocking acceptBlockingRunnable = new AcceptBlocking(acceptingChannelMock, 10, TimeUnit.SECONDS); final Thread acceptChannelThread = new Thread(acceptBlockingRunnable); // try to accept blocking with acceptance enabled at accepting channel mock assertNotNull(Channels.acceptBlocking(acceptingChannelMock, 1, TimeUnit.SECONDS)); assertFalse(acceptingChannelMock.haveWaitedAcceptable()); // try to accept in another thread, while acceptance has been disabled acceptingChannelMock.enableAcceptance(false); acceptChannelThread.start(); acceptChannelThread.join(200); assertFalse(acceptChannelThread.isAlive()); // thread is supposed to have finished, after having invoked awaitAcceptable at acceptingchannelMock with 10s timeout assertTrue(acceptingChannelMock.haveWaitedAcceptable()); assertEquals(10, acceptingChannelMock.getAwaitAcceptableTime()); assertEquals(TimeUnit.SECONDS, acceptingChannelMock.getAwaitAcceptableTimeUnit()); // a null channel has been returned by accept assertNull(acceptBlockingRunnable.getAcceptedChannel()); // enable acceptance so that acceptBlocking can return a non-null value acceptingChannelMock.enableAcceptance(true); acceptingChannelMock.clearWaitedAcceptable(); assertNotNull(Channels.acceptBlocking(acceptingChannelMock, 15, TimeUnit.SECONDS)); assertFalse(acceptingChannelMock.haveWaitedAcceptable()); } @Test public void transferBlockingToFile1() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); channelMock.setReadData("test"); channelMock.enableRead(true); final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); final FileChannel fileChannel = randomAccessFile.getChannel(); try { Channels.transferBlocking(fileChannel, channelMock, 0, 4); fileChannel.position(0); ByteBuffer buffer = ByteBuffer.allocate(10); fileChannel.read(buffer); assertReadMessage(buffer, "test"); } finally { fileChannel.close(); randomAccessFile.close(); } } @Test public void transferBlockingToFile2() throws IOException, InterruptedException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); channelMock.setReadData("test", "12345"); final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); final FileChannel fileChannel = randomAccessFile.getChannel(); try { final Thread transferBlockingThread = new Thread(new TransferBlockingToFileChannel(channelMock, fileChannel, 0, 8)); transferBlockingThread.start(); transferBlockingThread.join(200); assertTrue(transferBlockingThread.isAlive()); channelMock.enableRead(true); transferBlockingThread.join(); fileChannel.position(0); ByteBuffer buffer = ByteBuffer.allocate(10); fileChannel.read(buffer); assertReadMessage(buffer, "test", "1234"); } finally { fileChannel.close(); randomAccessFile.close(); } } @Test public void transferBlockingFromFile1() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); final FileChannel fileChannel = randomAccessFile.getChannel(); try { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("test".getBytes("UTF-8")).flip(); assertEquals(4, fileChannel.write(buffer)); fileChannel.position(0); Channels.transferBlocking(channelMock, fileChannel, 0, 4); assertWrittenMessage(channelMock, "test"); } finally { fileChannel.close(); randomAccessFile.close(); } } @Test public void transferBlockingFromFile2() throws IOException, InterruptedException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); channelMock.enableWrite(false); final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); final FileChannel fileChannel = randomAccessFile.getChannel(); try { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("test12345".getBytes("UTF-8")).flip(); assertEquals(9, fileChannel.write(buffer)); fileChannel.position(0); final Thread transferBlockingThread = new Thread(new TransferBlockingFromFileChannel(fileChannel, channelMock, 0, 8)); transferBlockingThread.start(); transferBlockingThread.join(200); assertTrue(transferBlockingThread.isAlive()); channelMock.enableWrite(true); transferBlockingThread.join(); assertWrittenMessage(channelMock, "test", "1234"); } finally { fileChannel.close(); randomAccessFile.close(); } } @Test public void setChannelListeners() { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final ChannelListener channelListener = new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) {} }; // test setReadListener Channels.setReadListener(channelMock, channelListener); assertSame(channelListener, channelMock.getReadListener()); Channels.setReadListener(channelMock, null); assertNull(channelMock.getReadListener()); // test setWriteListener Channels.setWriteListener(channelMock, channelListener); assertSame(channelListener, channelMock.getWriteListener()); Channels.setWriteListener(channelMock, null); assertNull(channelMock.getWriteListener()); // test setCloseListener Channels.setCloseListener(channelMock, channelListener); assertSame(channelListener, channelMock.getCloseListener()); Channels.setCloseListener(channelMock, null); assertNull(channelMock.getCloseListener()); } @Test public void setAcceptListener() { final AcceptingChannelMock channelMock = new AcceptingChannelMock(); final ChannelListener> channelListener = new ChannelListener>() { public void handleEvent(final AcceptingChannel channel) {} }; Channels.setAcceptListener(channelMock, channelListener); assertSame(channelListener, channelMock.getAcceptListener()); Channels.setAcceptListener(channelMock, null); assertNull(channelMock.getAcceptListener()); } @Test public void wrapChannel() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final ByteChannel wrappedByteChannel = Channels.wrapByteChannel(channelMock); // test isOpen assertSame(wrappedByteChannel.isOpen(), channelMock.isOpen()); // test read(ByteBuffer) channelMock.setReadData("read", "data"); channelMock.enableRead(true); ByteBuffer buffer = ByteBuffer.allocate(10); assertEquals(8, wrappedByteChannel.read(buffer)); assertReadMessage(buffer, "read", "data"); // test read(ByteBuffer[]) channelMock.setReadData("read", "in ", "four", "sizd", "blks"); ByteBuffer[] bufferArray = new ByteBuffer[]{ByteBuffer.allocate(4), ByteBuffer.allocate(4), ByteBuffer.allocate(4), ByteBuffer.allocate(4), ByteBuffer.allocate(4), ByteBuffer.allocate(4)}; wrappedByteChannel.read(bufferArray); assertReadMessage(bufferArray[0], "read"); assertReadMessage(bufferArray[1], "in "); assertReadMessage(bufferArray[2], "four"); assertReadMessage(bufferArray[3], "sizd"); assertReadMessage(bufferArray[4], "blks"); assertReadMessage(bufferArray[5]); // test read(ByteBuffer[], int, int) for(ByteBuffer bufferItem: bufferArray) { bufferItem.clear(); } channelMock.setReadData("read", "again"); wrappedByteChannel.read(bufferArray, 2, 4); assertReadMessage(bufferArray[0]); assertReadMessage(bufferArray[1]); assertReadMessage(bufferArray[2], "read"); assertReadMessage(bufferArray[3], "agai"); assertReadMessage(bufferArray[4], "n"); assertReadMessage(bufferArray[5]); // test write(ByteBuffer) buffer.clear(); buffer.put("write".getBytes("UTF-8")).flip(); wrappedByteChannel.write(buffer); assertWrittenMessage(channelMock, "write"); // test write(ByteBuffer[]) for(ByteBuffer bufferItem: bufferArray) { bufferItem.clear(); } bufferArray[0].put("writ".getBytes("UTF-8")).flip(); bufferArray[1].put("e_ag".getBytes("UTF-8")).flip(); bufferArray[2].put("ain".getBytes("UTF-8")).flip(); bufferArray[3].flip(); bufferArray[4].flip(); bufferArray[5].flip(); wrappedByteChannel.write(bufferArray); assertWrittenMessage(channelMock, "write", "write", "_again"); // test write(ByteBuffer, int, int) for (ByteBuffer bufferItem: bufferArray) { bufferItem.flip(); } wrappedByteChannel.write(bufferArray, 1, 1); assertWrittenMessage(channelMock, "write", "write", "_again", "e_ag"); // test close() wrappedByteChannel.close(); assertFalse(channelMock.isOpen()); assertFalse(wrappedByteChannel.isOpen()); } @Test public void getOption() throws IllegalArgumentException, IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final Configurable brokenConfigurable = new Configurable() { @Override public boolean supportsOption(Option option) { return true; } @Override public T getOption(Option option) throws IOException { throw new IOException("broken configurable for tests"); } @Override public T setOption(Option option, T value) throws IllegalArgumentException, IOException { throw new IOException("broken configurable for tests"); } }; // Object type option channelMock.setOption(Options.SSL_PEER_HOST_NAME, "peer host name"); assertEquals("peer host name", Channels.getOption(channelMock, Options.SSL_PEER_HOST_NAME, null)); assertEquals("default", Channels.getOption(channelMock, Options.SSL_PROVIDER, "default")); assertNull(Channels.getOption(brokenConfigurable, Options.SSL_PEER_HOST_NAME, null)); // boolean type option channelMock.setOption(Options.ALLOW_BLOCKING, true); assertTrue(Channels.getOption(channelMock, Options.ALLOW_BLOCKING, false)); assertTrue(Channels.getOption(channelMock, Options.BROADCAST, true)); assertFalse(Channels.getOption(brokenConfigurable, Options.ALLOW_BLOCKING, false)); // int type option channelMock.setOption(Options.SSL_CLIENT_SESSION_TIMEOUT, 3000); assertEquals(3000, Channels.getOption(channelMock, Options.SSL_CLIENT_SESSION_TIMEOUT, 5000)); assertEquals(1000, Channels.getOption(channelMock, Options.MAX_OUTBOUND_MESSAGE_SIZE, 1000)); assertEquals(5000, Channels.getOption(brokenConfigurable, Options.SSL_CLIENT_SESSION_TIMEOUT, 5000)); // long type option assertEquals(1l, Channels.getOption(channelMock, Options.STACK_SIZE, 1l)); channelMock.setOption(Options.STACK_SIZE, 50000l); assertEquals(50000l, Channels.getOption(channelMock, Options.STACK_SIZE, 100)); assertEquals(100, Channels.getOption(brokenConfigurable, Options.STACK_SIZE, 100)); } @Test public void unwrap() { assertNull(Channels.unwrap(ConnectedStreamChannelMock.class, null)); final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final FramedMessageChannel wrappedChannel = new FramedMessageChannel(channelMock, ByteBuffer.allocate(500), ByteBuffer.allocate(500)); assertSame(channelMock, Channels.unwrap(ConnectedStreamChannelMock.class, channelMock)); assertSame(channelMock, Channels.unwrap(ConnectedStreamChannelMock.class, wrappedChannel)); assertNull(Channels.unwrap(FramedMessageChannel.class, channelMock)); } public static class FlushBlocking implements Runnable { private final SuspendableWriteChannel channel; public FlushBlocking(SuspendableWriteChannel c) { channel = c; } @Override public void run() { try { Channels.flushBlocking(channel); } catch (IOException e) { throw new RuntimeException(e); } } } public static class ShutdownWritesBlocking implements Runnable { private final SuspendableWriteChannel channel; public ShutdownWritesBlocking(SuspendableWriteChannel c) { channel = c; } @Override public void run() { try { Channels.shutdownWritesBlocking(channel); } catch (IOException e) { throw new RuntimeException(e); } } } public static class WriteBlocking implements Runnable { private final String message; private final ConnectedStreamChannel channel; private final int timeout; private final TimeUnit timeoutUnit; private int writeResult = -1; public WriteBlocking(ConnectedStreamChannel c, String m) { this(c, m, 0, null); } public WriteBlocking(ConnectedStreamChannel c, String m, int t, TimeUnit tu) { channel = c; message = m; timeout = t; timeoutUnit = tu; } @Override public void run() { ByteBuffer buffer = ByteBuffer.allocate(30); try { buffer.put(message.getBytes("UTF-8")).flip(); if (timeoutUnit != null) { writeResult = Channels.writeBlocking(channel, buffer, timeout, timeoutUnit); } else { writeResult = Channels.writeBlocking(channel, buffer); } } catch (IOException e) { throw new RuntimeException(e); } } public int getWriteResult() { return writeResult; } } public static class WriteBufferArrayBlocking implements Runnable { private final String[] message; private final ConnectedStreamChannel channel; private final long timeout; private final TimeUnit timeoutUnit; private long writeResult = -1; public WriteBufferArrayBlocking(ConnectedStreamChannel c, String ...m) { this(c, 0, null, m); } public WriteBufferArrayBlocking(ConnectedStreamChannel c, long t, TimeUnit tu, String ...m) { channel = c; message = m; timeout = t; timeoutUnit = tu; } @Override public void run() { final ByteBuffer[] buffer = new ByteBuffer[message.length]; try { for (int i = 0; i < buffer.length; i++) { buffer[i] = ByteBuffer.allocate(message[i].length()); buffer[i].put(message[i].getBytes("UTF-8")).flip(); } if (timeoutUnit != null) { writeResult = Channels.writeBlocking(channel, buffer, 0, buffer.length, timeout, timeoutUnit); } else { writeResult = Channels.writeBlocking(channel, buffer, 0, buffer.length); } } catch (IOException e) { throw new RuntimeException(e); } } public long getWriteResult() { return writeResult; } } public static class SendBlocking implements Runnable { private final String message; private final WritableMessageChannel channel; private final int timeout; private final TimeUnit timeoutUnit; private boolean sendResult; public SendBlocking(WritableMessageChannel c, String m) { this(c, m, 0, null); } public SendBlocking(WritableMessageChannel c, String m, int t, TimeUnit tu) { channel = c; message = m; timeout = t; timeoutUnit = tu; } @Override public void run() { ByteBuffer buffer = ByteBuffer.allocate(30); try { buffer.put(message.getBytes("UTF-8")).flip(); if (timeoutUnit != null) { sendResult = Channels.sendBlocking(channel, buffer, timeout, timeoutUnit); } else { Channels.sendBlocking(channel, buffer); } } catch (IOException e) { throw new RuntimeException(e); } } public boolean getSendResult() { return sendResult; } } public static class SendBufferArrayBlocking implements Runnable { private final String[] message; private final WritableMessageChannel channel; private final long timeout; private final TimeUnit timeoutUnit; private boolean sendResult; public SendBufferArrayBlocking(WritableMessageChannel c, String ...m) { this(c, 0, null, m); } public SendBufferArrayBlocking(WritableMessageChannel c, long t, TimeUnit tu, String ...m) { channel = c; message = m; timeout = t; timeoutUnit = tu; } @Override public void run() { final ByteBuffer[] buffer = new ByteBuffer[message.length]; try { for (int i = 0; i < buffer.length; i++) { buffer[i] = ByteBuffer.allocate(message[i].length()); buffer[i].put(message[i].getBytes("UTF-8")).flip(); } if (timeoutUnit != null) { sendResult = Channels.sendBlocking(channel, buffer, 0, buffer.length, timeout, timeoutUnit); } else { Channels.sendBlocking(channel, buffer, 0, buffer.length); } } catch (IOException e) { throw new RuntimeException(e); } } public boolean getSendResult() { return sendResult; } } public static class ReadBlocking implements Runnable { private final ByteBuffer buffer; private final ConnectedStreamChannel channel; private final long timeout; private final TimeUnit timeoutUnit; private int readResult; public ReadBlocking(ConnectedStreamChannel c) { this(c, 0, null); } public ReadBlocking(ConnectedStreamChannel c, ByteBuffer b) { this(c, 0, null, b); } public ReadBlocking(ConnectedStreamChannel c, long t, TimeUnit tu) { this(c, t, tu, ByteBuffer.allocate(20)); } public ReadBlocking(ConnectedStreamChannel c, long t, TimeUnit tu, ByteBuffer b) { channel = c; timeout = t; timeoutUnit = tu; buffer = b; } @Override public void run() { try { if (timeoutUnit == null) { readResult = Channels.readBlocking(channel, buffer); } else { readResult = Channels.readBlocking(channel, buffer, timeout, timeoutUnit); } } catch (IOException e) { throw new RuntimeException(e); } } public int getReadResult() { return readResult; } public ByteBuffer getReadBuffer() { return buffer; } } public static class ReadToBufferArrayBlocking implements Runnable { private final ByteBuffer[] buffer; private final ConnectedStreamChannel channel; private final long timeout; private final TimeUnit timeoutUnit; private long readResult; public ReadToBufferArrayBlocking(ConnectedStreamChannel c) { this(c, 0, null); } public ReadToBufferArrayBlocking(ConnectedStreamChannel c, long t, TimeUnit tu) { channel = c; timeout = t; timeoutUnit = tu; buffer = new ByteBuffer[] {ByteBuffer.allocate(5), ByteBuffer.allocate(5), ByteBuffer.allocate(5), ByteBuffer.allocate(5)}; } @Override public void run() { try { if (timeoutUnit == null) { readResult = Channels.readBlocking(channel, buffer, 0, buffer.length); } else { readResult = Channels.readBlocking(channel, buffer, 0, buffer.length, timeout, timeoutUnit); } } catch (IOException e) { throw new RuntimeException(e); } } public long getReadResult() { return readResult; } public ByteBuffer[] getReadBuffer() { return buffer; } } public static class ReceiveBlocking implements Runnable { private final ByteBuffer buffer; private final ReadableMessageChannel channel; private final long timeout; private final TimeUnit timeoutUnit; private int receiveResult; public ReceiveBlocking(ReadableMessageChannel c) { this(c, 0, null); } public ReceiveBlocking(ReadableMessageChannel c, long t, TimeUnit tu) { channel = c; timeout = t; timeoutUnit = tu; buffer = ByteBuffer.allocate(20); } @Override public void run() { try { if (timeoutUnit == null) { receiveResult = Channels.receiveBlocking(channel, buffer); } else { receiveResult = Channels.receiveBlocking(channel, buffer, timeout, timeoutUnit); } } catch (IOException e) { throw new RuntimeException(e); } } public int getReceiveResult() { return receiveResult; } public ByteBuffer getReceiveBuffer() { return buffer; } } public static class ReceiveBufferArrayBlocking implements Runnable { private final ByteBuffer[] buffer; private final ReadableMessageChannel channel; private final long timeout; private final TimeUnit timeoutUnit; private long receiveResult; public ReceiveBufferArrayBlocking(ReadableMessageChannel c) { this(c, 0, null); } public ReceiveBufferArrayBlocking(ReadableMessageChannel c, long t, TimeUnit tu) { channel = c; buffer = new ByteBuffer[] {ByteBuffer.allocate(5), ByteBuffer.allocate(5), ByteBuffer.allocate(5), ByteBuffer.allocate(5)}; timeout = t; timeoutUnit = tu; } @Override public void run() { try { if (timeoutUnit == null) { receiveResult = Channels.receiveBlocking(channel, buffer, 0, buffer.length); } else { receiveResult = Channels.receiveBlocking(channel, buffer, 0, buffer.length, timeout, timeoutUnit); } } catch (IOException e) { throw new RuntimeException(e); } } public long getReceiveResult() { return receiveResult; } public ByteBuffer[] getReceiveBuffer() { return buffer; } } public static class AcceptBlocking implements Runnable { private final AcceptingChannel acceptingChannel; private C acceptedChannel; private final int timeout; private final TimeUnit timeoutUnit; public AcceptBlocking(AcceptingChannel c) { this(c, -1, null); } public AcceptBlocking(AcceptingChannel c, int t, TimeUnit tu) { acceptingChannel = c; timeout = t; timeoutUnit = tu; } @Override public void run() { try { if (timeoutUnit == null) { acceptedChannel = Channels.acceptBlocking(acceptingChannel); }else { acceptedChannel = Channels.acceptBlocking(acceptingChannel, timeout, timeoutUnit); } } catch (IOException e) { throw new RuntimeException(e); } } public C getAcceptedChannel() { return acceptedChannel; } } public static class TransferBlockingToFileChannel implements Runnable { private final StreamSourceChannel fromChannel; private final FileChannel fileChannel; private final long startPosition; private final long count; public TransferBlockingToFileChannel(StreamSourceChannel from, FileChannel to, long startPosition, long count) { fromChannel = from; fileChannel = to; this.startPosition = startPosition; this.count = count; } @Override public void run() { try { Channels.transferBlocking(fileChannel, fromChannel, startPosition, count); } catch (IOException e) { throw new RuntimeException(e); } } } public static class TransferBlockingFromFileChannel implements Runnable { private final StreamSinkChannel toChannel; private final FileChannel fileChannel; private final long startPosition; private final long count; public TransferBlockingFromFileChannel(FileChannel from, StreamSinkChannel to, long startPosition, long count) { fileChannel = from; toChannel = to; this.startPosition = startPosition; this.count = count; } @Override public void run() { try { Channels.transferBlocking(toChannel, fileChannel, startPosition, count); } catch (IOException e) { throw new RuntimeException(e); } } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/channels/EmptyStreamSourceChannelTestCase.java000066400000000000000000000323751257016060700315640ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; import org.xnio.ChannelListener; import org.xnio.FileAccess; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.Xnio; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.mock.ConnectedStreamChannelMock; import org.xnio.mock.XnioIoThreadMock; /** * Test for {@link EmptySourceStreamChannel}. * * @author Flavia Rainone */ public class EmptyStreamSourceChannelTestCase { private EmptyStreamSourceChannel channel; @Before public void createChannel() throws Exception { this.channel = new EmptyStreamSourceChannel(new XnioIoThreadMock(null)); } @SuppressWarnings("deprecation") @Test public void getWorkerAndExecutor() throws Exception { final Xnio xnio = Xnio.getInstance("xnio-mock"); final XnioWorker worker = xnio.createWorker(OptionMap.EMPTY); final XnioIoThread executor = new XnioIoThreadMock(worker); this.channel = new EmptyStreamSourceChannel(executor); assertSame(worker, channel.getWorker()); assertSame(executor, channel.getReadThread()); assertSame(executor, channel.getIoThread()); } @Test public void setAndGetOption() throws IOException { assertNull(channel.getOption(Options.ALLOW_BLOCKING)); assertNull(channel.setOption(Options.ALLOW_BLOCKING, true)); assertNull(channel.getOption(Options.ALLOW_BLOCKING)); assertNull(channel.getOption(Options.FILE_ACCESS)); assertNull(channel.setOption(Options.FILE_ACCESS, FileAccess.READ_ONLY)); assertNull(channel.getOption(Options.FILE_ACCESS)); assertNull(channel.getOption(Options.SECURE)); assertNull(channel.setOption(Options.SECURE, false)); assertNull(channel.getOption(Options.SECURE)); assertNull(channel.getOption(Options.MAX_INBOUND_MESSAGE_SIZE)); assertNull(channel.setOption(Options.MAX_INBOUND_MESSAGE_SIZE, 5000)); assertNull(channel.getOption(Options.MAX_INBOUND_MESSAGE_SIZE)); assertNull(channel.getOption(Options.SEND_BUFFER)); assertNull(channel.setOption(Options.SEND_BUFFER, 100000)); assertNull(channel.getOption(Options.SEND_BUFFER)); assertNull(channel.getOption(Options.WORKER_NAME)); assertNull(channel.setOption(Options.WORKER_NAME, "dummy")); assertNull(channel.getOption(Options.WORKER_NAME)); assertNull(channel.getOption(Options.WRITE_TIMEOUT)); assertNull(channel.setOption(Options.WRITE_TIMEOUT, 700000)); assertNull(channel.getOption(Options.WRITE_TIMEOUT)); } @Test public void supportsOption() throws IOException { assertFalse(channel.supportsOption(Options.ALLOW_BLOCKING)); assertFalse(channel.supportsOption(Options.FILE_ACCESS)); assertFalse(channel.supportsOption(Options.SECURE)); assertFalse(channel.supportsOption(Options.MAX_INBOUND_MESSAGE_SIZE)); assertFalse(channel.supportsOption(Options.SEND_BUFFER)); assertFalse(channel.supportsOption(Options.WORKER_NAME)); assertFalse(channel.supportsOption(Options.WRITE_TIMEOUT)); } @Test public void transferToFileChannel() throws Exception { final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); final FileChannel fileChannel = randomAccessFile.getChannel(); try { assertEquals(0, channel.transferTo(5, 0, fileChannel)); assertEquals(0, channel.transferTo(0, 0, fileChannel)); assertEquals(0, channel.transferTo(500, 5, fileChannel)); assertEquals(0, channel.transferTo(300, 3, null)); } finally { fileChannel.close(); randomAccessFile.close(); } } @Test public void transferToStreamSinkChannel() throws Exception { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); assertEquals(-1, channel.transferTo(50, ByteBuffer.allocate(60), channelMock)); } @Test public void simpleRead() throws Exception { final ReadListener listener = new ReadListener(); channel.getReadSetter().set(listener); channel.resumeReads(); assertTrue(channel.isReadResumed()); listener.waitInvocation(); assertEquals(-1, listener.getReadToBufferResult()); assertEquals(-1, listener.getReadToBufferArrayResult()); assertEquals(-1, listener.getReadToBufferArrayWithOffsetResult()); listener.clearListenerInvocationData(); // show resume reads is idempotent assertFalse(listener.isInvoked()); channel.resumeReads(); channel.suspendReads(); assertFalse(channel.isReadResumed()); // suspend reads is idempotent as well channel.suspendReads(); assertFalse(channel.isReadResumed()); } @Test public void resumeReadAfterEmptied() throws Exception { final ReadListener listener = new ReadListener(); channel.getReadSetter().set(listener); channel.resumeReads(); assertTrue(channel.isReadResumed()); listener.waitInvocation(); channel.suspendReads(); assertFalse(channel.isReadResumed()); listener.clearListenerInvocationData(); channel.resumeReads(); assertTrue(channel.isReadResumed()); assertFalse(listener.isInvoked()); } @Test public void wrappedReadListener() throws Exception { final ReadListener listener = new ReadListener(); final WrappedReadListener wrappedListener = new WrappedReadListener(listener); channel.getReadSetter().set(wrappedListener); channel.resumeReads(); assertTrue(channel.isReadResumed()); listener.waitInvocation(); assertEquals(-1, listener.getReadToBufferResult()); assertEquals(-1, listener.getReadToBufferArrayResult()); assertEquals(-1, listener.getReadToBufferArrayWithOffsetResult()); listener.clearListenerInvocationData(); // show resume reads is idempotent assertFalse(listener.isInvoked()); channel.resumeReads(); channel.suspendReads(); assertFalse(channel.isReadResumed()); // suspend reads is idempotent as well channel.suspendReads(); assertFalse(channel.isReadResumed()); } @Test public void listenerSuspendReadsOnChannel() throws Exception { final SuspendReadListener listener = new SuspendReadListener(); channel.getReadSetter().set(listener); channel.resumeReads(); listener.waitInvocation(); assertFalse(channel.isReadResumed()); } @Test public void resumeReadsWithoutListener() { channel.resumeReads(); } @Test public void awaitReadable() throws IOException { // should return immediately no matter what channel.awaitReadable(); channel.awaitReadable(500, TimeUnit.DAYS); channel.resumeReads(); channel.awaitReadable(); channel.awaitReadable(1, TimeUnit.SECONDS); channel.suspendReads(); channel.awaitReadable(); channel.awaitReadable(30, TimeUnit.MILLISECONDS); } @Test public void shutdownReads() throws Exception { final EmptyListener listener = new EmptyListener(); channel.getCloseSetter().set(listener); channel.resumeReads(); channel.shutdownReads(); listener.waitInvocation(); assertFalse(channel.isReadResumed()); assertFalse(channel.isOpen()); // shutdownReads is idempotent listener.clearInvocationData(); channel.shutdownReads(); assertFalse(listener.isInvoked()); assertFalse(channel.isReadResumed()); assertFalse(channel.isOpen()); } @Test public void close() throws Exception { final EmptyListener listener = new EmptyListener(); channel.getCloseSetter().set(listener); channel.close(); listener.waitInvocation(); assertFalse(channel.isReadResumed()); assertFalse(channel.isOpen()); // close is idempotent listener.clearInvocationData(); channel.close(); assertFalse(listener.isInvoked()); assertFalse(channel.isReadResumed()); assertFalse(channel.isOpen()); assertEquals(-1, channel.read(ByteBuffer.allocate(15))); final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); final FileChannel fileChannel = randomAccessFile.getChannel(); try { assertEquals(0, channel.transferTo(0, 10, fileChannel)); } finally { fileChannel.close(); randomAccessFile.close(); } } @Test public void listenerClosesChannel() throws Exception { } private static class ReadListener implements ChannelListener { private CountDownLatch countDownLatch = new CountDownLatch(1); private boolean listenerInvoked = false; private int readToBufferResult = 0; private long readToBufferArrayResult = 0; private long readToBufferArrayWithOffsetResult = 0; @Override public void handleEvent(StreamSourceChannel channel) { listenerInvoked = true; countDownLatch.countDown(); final ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(10)}; try { readToBufferResult = channel.read(buffer[0]); readToBufferArrayResult = channel.read(buffer); readToBufferArrayWithOffsetResult = channel.read(buffer, 0, 1); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } public void waitInvocation() throws InterruptedException { countDownLatch.await(); } public boolean isInvoked() { return listenerInvoked; } public int getReadToBufferResult() { return readToBufferResult; } public long getReadToBufferArrayResult() { return readToBufferArrayResult; } public long getReadToBufferArrayWithOffsetResult() { return readToBufferArrayWithOffsetResult; } public void clearListenerInvocationData() { listenerInvoked = false; countDownLatch = new CountDownLatch(1); } } private static class SuspendReadListener implements ChannelListener { private final CountDownLatch countDownLatch = new CountDownLatch(1); @Override public void handleEvent(StreamSourceChannel channel) { countDownLatch.countDown(); channel.suspendReads(); } public void waitInvocation() throws InterruptedException { countDownLatch.await(); } } private static class WrappedReadListener implements ChannelListener { private final ChannelListener listener; public WrappedReadListener(ChannelListener listener) { this.listener = listener; } @Override public void handleEvent(StreamSourceChannel channel) { channel.getReadSetter().set(listener); } } private static class EmptyListener implements ChannelListener { private CountDownLatch countDownLatch = new CountDownLatch(1); private boolean invoked = false; @Override public void handleEvent(StreamSourceChannel channel) { countDownLatch.countDown(); invoked = true; } public void waitInvocation() throws InterruptedException { countDownLatch.await(); } public boolean isInvoked() { return invoked; } public void clearInvocationData() { invoked = false; countDownLatch = new CountDownLatch(1); } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/channels/FramedMessageChannelTestCase.java000066400000000000000000001007551257016060700306320ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.EOFException; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.Arrays; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.xnio.BufferAllocator; import org.xnio.Buffers; import org.xnio.ByteBufferSlicePool; import org.xnio.LocalSocketAddress; import org.xnio.mock.ConnectedStreamChannelMock; /** * Test for {@link FramedMessageChannel}. * * @author Flavia Rainone */ public class FramedMessageChannelTestCase { private ConnectedStreamChannelMock connectedChannel; @Before public void init() { connectedChannel = new ConnectedStreamChannelMock(); } @Test public void receive() throws IOException { final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, ByteBuffer.allocate(15000), ByteBuffer.allocate(15000)); try { connectedChannel.setReadDataWithLength("data"); connectedChannel.enableRead(true); ByteBuffer buffer = ByteBuffer.allocate(20); assertEquals(4, channel.receive(buffer)); assertEquals(0, channel.receive(buffer)); assertReadMessage(buffer, "data"); } finally { channel.close(); } } @Test public void receiveDoubleMessage() throws IOException { final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, ByteBuffer.allocate(15000), ByteBuffer.allocate(15000)); try { connectedChannel.setReadDataWithLength("message_1"); connectedChannel.setReadDataWithLength("message_2"); connectedChannel.enableRead(true); ByteBuffer buffer = ByteBuffer.allocate(20); assertEquals(9, channel.receive(buffer)); assertEquals(9, channel.receive(buffer)); assertEquals(0, channel.receive(buffer)); assertReadMessage(buffer, "message_1", "message_2"); } finally { channel.close(); } } @Test public void bufferOverflowOnReceive() throws IOException { final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, ByteBuffer.allocate(15000), ByteBuffer.allocate(15000)); try { connectedChannel.setReadDataWithLength("message"); connectedChannel.setReadDataWithLength("12"); connectedChannel.setReadDataWithLength("34"); connectedChannel.setReadDataWithLength("1"); connectedChannel.setReadDataWithLength("again"); connectedChannel.setEof(); connectedChannel.enableRead(true); ByteBuffer buffer = ByteBuffer.allocate(2); assertEquals(7, channel.receive(buffer)); assertReadMessage(buffer, "me"); // full buffer assertEquals(2, channel.receive(buffer)); // empty full buffer buffer.clear(); assertEquals(2, channel.receive(buffer)); assertReadMessage(buffer, "34"); buffer.clear(); assertEquals(1, channel.receive(buffer)); assertReadMessage(buffer, "1"); buffer.clear(); assertEquals(5, channel.receive(buffer)); assertReadMessage(buffer, "ag"); assertEquals(-1, channel.receive(buffer)); buffer.clear(); assertEquals(-1, channel.receive(buffer)); } finally { channel.close(); } } @Test public void receiveTruncatedMessage() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 1000, 1000 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { connectedChannel.setReadDataWithLength("1234"); connectedChannel.setReadDataWithLength(4, "567890"); connectedChannel.enableRead(true); ByteBuffer buffer = ByteBuffer.allocate(20); assertEquals(4, channel.receive(buffer)); assertEquals(4, channel.receive(buffer)); assertEquals(0, channel.receive(buffer)); connectedChannel.setEof(); assertEquals(-1, channel.receive(buffer)); assertEquals(-1, channel.receive(buffer)); assertReadMessage(buffer, "12345678"); } finally { channel.close(); } } @Test public void receiveIncompleteMessage() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 1000, 1000 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { connectedChannel.setReadDataWithLength(6, "hello"); connectedChannel.enableRead(true); ByteBuffer buffer = ByteBuffer.allocate(20); assertEquals(0, channel.receive(buffer)); assertEquals(0, channel.receive(buffer)); connectedChannel.setEof(); assertEquals(-1, channel.receive(buffer)); assertEquals(-1, channel.receive(buffer)); } finally { channel.close(); } } @Test public void receiveInvalidLengthMessage() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 10, 10 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { connectedChannel.setReadDataWithLength(20, "12345678901234567890"); connectedChannel.enableRead(true); ByteBuffer buffer = ByteBuffer.allocate(20); boolean failed = false; try { channel.receive(buffer); } catch (IOException e) { failed = true; } assertTrue(failed); } finally { channel.close(); } } @Test public void receiveNegativeLengthMessage() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 10, 10 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { connectedChannel.setReadDataWithLength(-8, "abcdefgh"); connectedChannel.enableRead(true); ByteBuffer buffer = ByteBuffer.allocate(10); boolean failed = false; try { channel.receive(buffer); } catch (IOException e) { failed = true; } assertTrue(failed); } finally { channel.close(); } } @Test public void receiveBrokenMessage() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 1000, 1000 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { connectedChannel.setReadDataWithLength(2); connectedChannel.enableRead(true); ByteBuffer buffer = ByteBuffer.allocate(5); assertEquals(0, channel.receive(buffer)); assertEquals(0, channel.receive(buffer)); connectedChannel.setReadData("oh"); assertEquals(2, channel.receive(buffer)); assertEquals(0, channel.receive(buffer)); assertReadMessage(buffer, "oh"); } finally { channel.close(); } } @Test public void receiveToByteBufferArray() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 1000, 1000 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { connectedChannel.setReadDataWithLength("receive"); connectedChannel.setReadDataWithLength("this"); connectedChannel.enableRead(true); ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(4), ByteBuffer.allocate(4), ByteBuffer.allocate(4), ByteBuffer.allocate(4)}; assertEquals(7, channel.receive(buffer)); assertEquals(4, channel.receive(buffer)); assertEquals(0, channel.receive(buffer)); assertReadMessage(buffer[0], "rece"); assertReadMessage(buffer[1], "ivet"); assertReadMessage(buffer[2], "his"); assertReadMessage(buffer[3]); } finally { channel.close(); } } @Test public void bufferOverflowOnReceiveToByteArray() throws IOException { final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, ByteBuffer.allocate(15000), ByteBuffer.allocate(15000)); try { connectedChannel.setReadDataWithLength("message"); connectedChannel.setReadDataWithLength("12"); connectedChannel.setReadDataWithLength("34"); connectedChannel.setReadDataWithLength("1"); connectedChannel.setReadDataWithLength("again"); connectedChannel.setEof(); connectedChannel.enableRead(true); ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(1), ByteBuffer.allocate(1)}; assertEquals(7, channel.receive(buffer)); assertReadMessage(buffer[0], "m"); assertReadMessage(buffer[1], "e"); // full buffers assertEquals(2, channel.receive(buffer)); // make sure buffer contents haven't been overwritten assertReadMessage(buffer[0], "m"); assertReadMessage(buffer[1], "e"); // empty buffers buffer[0].clear(); buffer[1].clear(); assertEquals(2, channel.receive(buffer)); assertReadMessage(buffer[0], "3"); assertReadMessage(buffer[1], "4"); buffer[0].clear(); buffer[1].clear(); assertEquals(1, channel.receive(buffer)); assertReadMessage(buffer[0], "1"); buffer[0].clear(); buffer[1].clear(); assertEquals(5, channel.receive(buffer)); assertReadMessage(buffer[0], "a"); assertReadMessage(buffer[1], "g"); assertEquals(-1, channel.receive(buffer)); buffer[0].clear(); buffer[1].clear(); assertEquals(-1, channel.receive(buffer)); } finally { channel.close(); } } @Test public void receiveToByteBufferArrayWithOffset1() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 1000, 1000 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { connectedChannel.setReadDataWithLength("123"); connectedChannel.setReadDataWithLength("456"); connectedChannel.enableRead(true); ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(3), ByteBuffer.allocate(3), ByteBuffer.allocate(3),ByteBuffer.allocate(3)}; assertEquals(3, channel.receive(buffer, 1, 3)); assertEquals(3, channel.receive(buffer, 1, 3)); assertEquals(0, channel.receive(buffer, 1, 3)); assertEquals(0, buffer[0].position()); assertReadMessage(buffer[1], "123"); assertReadMessage(buffer[2], "456"); assertEquals(0, buffer[3].position()); } finally { channel.close(); } } @Test public void receiveToByteBufferArrayWithOffset2() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 1000, 1000 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { connectedChannel.setReadDataWithLength("1234"); connectedChannel.setReadDataWithLength("567890"); connectedChannel.enableRead(true); ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(3), ByteBuffer.allocate(3), ByteBuffer.allocate(3), ByteBuffer.allocate(3)}; assertEquals(4, channel.receive(buffer, 0, 3)); assertEquals(6, channel.receive(buffer, 0, 3)); assertEquals(0, channel.receive(buffer, 0, 3)); assertReadMessage(buffer[0], "123"); assertReadMessage(buffer[1], "456"); assertReadMessage(buffer[2], "789"); assertEquals(0, buffer[3].position()); } finally { channel.close(); } } @Test public void receiveTruncatedMessageToByteArray() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 1000, 1000 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { connectedChannel.setReadDataWithLength("1234"); connectedChannel.setReadDataWithLength(4, "567890"); connectedChannel.enableRead(true); ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(3), ByteBuffer.allocate(3), ByteBuffer.allocate(3), ByteBuffer.allocate(3)}; assertEquals(4, channel.receive(buffer, 0, 3)); assertEquals(4, channel.receive(buffer, 0, 3)); assertEquals(0, channel.receive(buffer, 0, 3)); connectedChannel.setEof(); assertEquals(-1, channel.receive(buffer, 0, 3)); assertEquals(-1, channel.receive(buffer, 0, 3)); assertEquals(-1, channel.receive(buffer, 0, 3)); assertReadMessage(buffer[0], "123"); assertReadMessage(buffer[1], "456"); assertReadMessage(buffer[2], "78"); assertEquals(0, buffer[3].position()); } finally { channel.close(); } } @Test public void receiveIncompleteMessageToByteArray() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 1000, 1000 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { connectedChannel.setReadDataWithLength(10, "hello"); connectedChannel.enableRead(true); ByteBuffer[] buffer = new ByteBuffer[]{ByteBuffer.allocate(20)}; assertEquals(0, channel.receive(buffer)); assertEquals(0, channel.receive(buffer)); connectedChannel.setEof(); assertEquals(-1, channel.receive(buffer)); assertEquals(-1, channel.receive(buffer)); } finally { channel.close(); } } @Test public void receiveInvalidLengthMessageToByteArray() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 10, 10 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { connectedChannel.setReadDataWithLength(15, "987654321098765"); connectedChannel.enableRead(true); ByteBuffer buffer = ByteBuffer.allocate(20); boolean failed = false; try { channel.receive(new ByteBuffer[] {buffer}); } catch (IOException e) { failed = true; } assertTrue(failed); } finally { channel.close(); } } @Test public void receiveNegativeLengthMessageToByteArray() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 10, 10 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { connectedChannel.setReadDataWithLength(-3, "abc"); connectedChannel.enableRead(true); ByteBuffer buffer = ByteBuffer.allocate(5); boolean failed = false; try { channel.receive(new ByteBuffer[] {buffer}); } catch (IOException e) { failed = true; } assertTrue(failed); } finally { channel.close(); } } @Test public void send() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 1000, 1000 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { final ByteBuffer buffer = ByteBuffer.allocate(20); buffer.put("hello!".getBytes("UTF-8")).flip(); assertTrue(channel.send(buffer)); assertWrittenMessage("hello!"); } finally { channel.close(); } } @Test public void sendMultipleMessages() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 1000, 1000 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { final ByteBuffer buffer = ByteBuffer.allocate(20); buffer.put("jboss ".getBytes("UTF-8")).flip(); assertTrue(channel.send(buffer)); assertTrue(channel.send(buffer)); buffer.clear(); buffer.put("xnio".getBytes("UTF-8")).flip(); assertTrue(channel.send(buffer)); assertTrue(channel.send(buffer)); buffer.clear(); buffer.put("-api".getBytes("UTF-8")).flip(); assertTrue(channel.send(buffer)); assertTrue(channel.send(buffer)); assertWrittenMessage("jboss ", "xnio", "-api"); } finally { channel.close(); } } @Test public void sendMessageTooLarge() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 2, 2 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { final ByteBuffer buffer = ByteBuffer.allocate(20); buffer.put("hello!".getBytes("UTF-8")).flip(); boolean failed = false; try { assertTrue(channel.send(buffer)); } catch (IOException e) { failed = true; } assertTrue(failed); } finally { channel.close(); } } @Test public void bufferOverflowOnSend() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 28, 28 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { // framed message channel won't be able to flush because write is disabled at connectedChannel connectedChannel.enableWrite(false); final ByteBuffer buffer = ByteBuffer.allocate(20); buffer.put("hi!".getBytes("UTF-8")).flip(); assertTrue(channel.send(buffer)); buffer.flip(); assertTrue(channel.send(buffer)); buffer.flip(); assertTrue(channel.send(buffer)); buffer.flip(); assertTrue(channel.send(buffer)); buffer.flip(); assertFalse(channel.send(buffer)); assertWrittenMessage(); // enable write connectedChannel.enableWrite(true); assertTrue(channel.send(buffer)); assertWrittenMessage("hi!", "hi!", "hi!", "hi!", "hi!"); } finally { channel.close(); } } @Test public void sendByteBufferArray() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 1000, 1000 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { final ByteBuffer[] buffer = new ByteBuffer[]{ByteBuffer.allocate(20), ByteBuffer.allocate(20)}; buffer[0].put("hello!".getBytes("UTF-8")).flip(); buffer[1].put("world!".getBytes("UTF-8")).flip(); assertTrue(channel.send(buffer)); assertWrittenMessage("hello!world!"); } finally { channel.close(); } } @Test public void sendMultipleMessagesWithBufferByteArray() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 1000, 1000 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { final ByteBuffer[] buffer = new ByteBuffer[]{ByteBuffer.allocate(2), ByteBuffer.allocate(5)}; buffer[0].put("jb".getBytes("UTF-8")).flip(); buffer[1].put("oss ".getBytes("UTF-8")).flip(); assertTrue(channel.send(buffer)); assertTrue(channel.send(buffer)); buffer[0].clear(); buffer[1].clear(); buffer[0].put("xn".getBytes("UTF-8")).flip(); buffer[1].put("io".getBytes("UTF-8")).flip(); assertTrue(channel.send(buffer)); assertTrue(channel.send(buffer)); buffer[0].clear(); buffer[1].clear(); buffer[0].put("-a".getBytes("UTF-8")).flip(); buffer[1].put("pi".getBytes("UTF-8")).flip(); assertTrue(channel.send(buffer)); assertTrue(channel.send(buffer)); assertWrittenMessage("jboss ", "xnio", "-api"); } finally { channel.close(); } } @Test public void sendMultipleMessagesWithBufferByteArrayAndOffset() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 1000, 1000 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { final ByteBuffer[] buffer = new ByteBuffer[]{ByteBuffer.allocate(2), ByteBuffer.allocate(5), ByteBuffer.allocate(2), ByteBuffer.allocate(5)}; buffer[1].put("jboss".getBytes("UTF-8")).flip(); buffer[2].put(" ".getBytes("UTF-8")).flip(); assertTrue(channel.send(buffer, 1, 2)); assertTrue(channel.send(buffer, 1, 2)); buffer[1].clear(); buffer[1].put("xnio".getBytes("UTF-8")).flip(); assertTrue(channel.send(buffer, 1, 2)); assertTrue(channel.send(buffer, 1, 2)); buffer[1].clear(); buffer[1].put("-api".getBytes("UTF-8")).flip(); assertTrue(channel.send(buffer, 1, 2)); assertTrue(channel.send(buffer, 1, 2)); assertWrittenMessage("jboss ", "xnio", "-api"); } finally { channel.close(); } } @Test public void sendMessageTooLargeWithByteBufferArray() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 2, 2 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { final ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(20)}; buffer[0].put("hello!".getBytes("UTF-8")).flip(); boolean failed = false; try { assertTrue(channel.send(buffer)); } catch (IOException e) { failed = true; } assertTrue(failed); } finally { channel.close(); } } @Test public void bufferOverflowOnSendByteBufferArray() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 40, 40 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { // framed message channel won't be able to flush because write is disabled at connectedChannel connectedChannel.enableWrite(false); final ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(20)}; buffer[0].put("hello!".getBytes("UTF-8")).flip(); assertTrue(channel.send(buffer)); buffer[0].flip(); assertTrue(channel.send(buffer)); buffer[0].flip(); assertTrue(channel.send(buffer)); buffer[0].flip(); assertTrue(channel.send(buffer)); buffer[0].flip(); assertFalse(channel.send(buffer)); assertWrittenMessage(); // enable write connectedChannel.enableWrite(true); assertTrue(channel.send(buffer)); assertWrittenMessage("hello!", "hello!", "hello!", "hello!", "hello!"); } finally { channel.close(); } } @Test public void shutdownWritesAndClose() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 40, 40 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); channel.shutdownWrites(); assertTrue(channel.isWriteShutDown()); channel.flush(); final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("can't send".getBytes("UTF-8")).flip(); boolean eofException = false; try { channel.send(buffer); } catch (EOFException e) { eofException = true; } assertTrue(eofException); eofException = false; try { channel.send(new ByteBuffer[]{buffer}); } catch (EOFException e) { eofException = true; } assertTrue(eofException); assertFalse(channel.isReadShutDown()); channel.close(); assertTrue(channel.isReadShutDown()); } @Test public void shutdownReadsAndClose() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 40, 40 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); channel.shutdownReads(); assertTrue(channel.isReadShutDown()); assertFalse(channel.isWriteShutDown()); channel.close(); assertTrue(channel.isWriteShutDown()); } @Test public void close() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 40, 40 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); channel.close(); assertTrue(channel.isWriteShutDown()); assertTrue(channel.isReadShutDown()); } @Test public void closeFailure() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 40, 40 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); connectedChannel.enableFlush(false); ByteBuffer buffer = ByteBuffer.allocate(5); buffer.put("a".getBytes("UTF-8")).flip(); channel.send(buffer); boolean failed = false; try { channel.close(); } catch (IOException e) { failed = true; } assertTrue(failed); //assertTrue(channel.isWriteShutDown()); //assertTrue(channel.isReadShutDown()); } @Test public void flush() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 40, 40 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("test".getBytes("UTF-8")).flip(); connectedChannel.enableWrite(false); connectedChannel.enableFlush(false); assertTrue(channel.send(buffer)); assertFalse(channel.flush()); connectedChannel.enableWrite(true); assertFalse(channel.flush()); connectedChannel.enableFlush(true); assertTrue(channel.flush()); connectedChannel.enableWrite(false); connectedChannel.enableFlush(false); buffer.flip(); assertTrue(channel.send(buffer)); channel.shutdownWrites(); assertFalse(channel.flush()); connectedChannel.enableWrite(true); assertFalse(channel.flush()); connectedChannel.enableFlush(true); assertTrue(channel.flush()); } finally { channel.close(); } } @Test public void getAddresses() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 40, 40 * 16); final FramedMessageChannel channel = new FramedMessageChannel(connectedChannel, pool.allocate(), pool.allocate()); try { assertSame(connectedChannel, channel.getChannel()); // getLocalAddress connectedChannel.setLocalAddress(new InetSocketAddress(10)); assertEquals(connectedChannel.getLocalAddress(), channel.getLocalAddress()); assertEquals(connectedChannel.getLocalAddress(InetSocketAddress.class), channel.getLocalAddress(InetSocketAddress.class)); assertEquals(connectedChannel.getLocalAddress(LocalSocketAddress.class), channel.getLocalAddress(LocalSocketAddress.class)); // getPeerAddress connectedChannel.setPeerAddress(new LocalSocketAddress("local")); assertEquals(connectedChannel.getPeerAddress(), channel.getPeerAddress()); assertEquals(connectedChannel.getPeerAddress(LocalSocketAddress.class), channel.getPeerAddress(LocalSocketAddress.class)); assertEquals(connectedChannel.getPeerAddress(InetSocketAddress.class), channel.getPeerAddress(InetSocketAddress.class)); } finally { channel.close(); } } protected final void assertReadMessage(ByteBuffer dst, String... message) { StringBuffer stringBuffer = new StringBuffer(); for (String messageString: message) { stringBuffer.append(messageString); } dst.flip(); assertEquals(stringBuffer.toString(), Buffers.getModifiedUtf8(dst)); } protected final void assertWrittenMessage(String... message) throws UnsupportedEncodingException { int totalLength = 0; for (String m: message) { totalLength += 4 + m.length(); } ByteBuffer byteBuffer = ByteBuffer.allocate(totalLength); for (String m: message) { byteBuffer.putInt(m.length()); byteBuffer.put(m.getBytes("UTF-8")); } ByteBuffer written = connectedChannel.getWrittenBytes(); written.flip(); assertEquals(byteBuffer.limit(), written.limit()); Assert.assertArrayEquals(byteBuffer.array(), Arrays.copyOf(written.array(), totalLength)); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/channels/PushBackStreamChannelTestCase.java000066400000000000000000000760271257016060700310070ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.xnio.AssertReadWrite.assertReadMessage; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; import org.xnio.ByteBufferSlicePool; import org.xnio.ChannelListener; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.Pool; import org.xnio.Pooled; import org.xnio.mock.ConnectedStreamChannelMock; /** * Test for {@link PushBacksStreamChannel}. * * @author Flavia Rainone * */ public class PushBackStreamChannelTestCase { private PushBackStreamChannel channel; private ConnectedStreamChannelMock firstChannel; @Before public void init() { firstChannel = new ConnectedStreamChannelMock(); firstChannel.enableRead(true); channel = new PushBackStreamChannel(firstChannel); } @Test public void readToEmptyBuffer() throws IOException { final ByteBuffer emptyBuffer = ByteBuffer.allocate(0); assertEquals(0, channel.read(emptyBuffer)); final Pool messagePool = new ByteBufferSlicePool(15, 15); final Pooled messageBuffer = messagePool.allocate(); messageBuffer.getResource().put("dummy".getBytes("UTF-8")).flip(); channel.unget(messageBuffer); assertEquals(0, channel.read(emptyBuffer)); firstChannel.setReadData("dummy"); assertEquals(0, channel.read(emptyBuffer)); } @Test public void readPushedMessage() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(10); final Pool messagePool = new ByteBufferSlicePool(15, 15); final Pooled messageBuffer = messagePool.allocate(); messageBuffer.getResource().put("new read data".getBytes("UTF-8")).flip(); assertEquals(0, channel.read(buffer)); channel.unget(messageBuffer); assertEquals (10, channel.read(buffer)); assertReadMessage(buffer, "new read d"); buffer.clear(); assertEquals (3, channel.read(buffer)); assertReadMessage(buffer, "ata"); } @Test public void readFirstChannelData() throws IOException { firstChannel.setReadData("data", "123"); final ByteBuffer buffer = ByteBuffer.allocate(15); assertEquals(7, channel.read(buffer)); assertReadMessage(buffer, "data", "123"); } @Test public void readFirstChannelDataAndPushedMessage1() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(15); final Pool messagePool = new ByteBufferSlicePool(5, 5); final Pooled messageBuffer = messagePool.allocate(); firstChannel.setReadData("E="); messageBuffer.getResource().put("mc".getBytes("UTF-8")).flip(); assertEquals(2, channel.read(buffer)); assertEquals(0, channel.read(buffer)); firstChannel.setReadData("2"); channel.unget(messageBuffer); assertEquals(2, channel.read(buffer)); assertEquals(1, channel.read(buffer)); assertEquals(0, channel.read(buffer)); assertReadMessage(buffer, "E=mc2"); } @Test public void readFirstChannelDataAndPushedMessage2() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(15); final Pool messagePool = new ByteBufferSlicePool(5, 5); final Pooled messageBuffer1 = messagePool.allocate(); final Pooled messageBuffer2 = messagePool.allocate(); firstChannel.setReadData("E="); messageBuffer1.getResource().put("c".getBytes("UTF-8")).flip(); messageBuffer2.getResource().put("m".getBytes("UTF-8")).flip(); assertEquals(2, channel.read(buffer)); assertEquals(0, channel.read(buffer)); firstChannel.setReadData("2"); channel.unget(messageBuffer1); channel.unget(messageBuffer2); assertEquals(2, channel.read(buffer)); assertEquals(1, channel.read(buffer)); assertReadMessage(buffer, "E=mc2"); } @Test public void readToEmptyBufferArray() throws IOException { final ByteBuffer[] emptyBufferArray = new ByteBuffer[0]; assertEquals(0, channel.read(emptyBufferArray)); final Pool messagePool = new ByteBufferSlicePool(15, 15); final Pooled messageBuffer = messagePool.allocate(); messageBuffer.getResource().put("dummy".getBytes("UTF-8")).flip(); channel.unget(messageBuffer); assertEquals(0, channel.read(emptyBufferArray)); firstChannel.setReadData("dummy"); assertEquals(0, channel.read(emptyBufferArray)); } @Test public void readPushedMessageToByteArray() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(15); final Pool messagePool = new ByteBufferSlicePool(20, 20); final Pooled messageBuffer = messagePool.allocate(); messageBuffer.getResource().put("pushed read data".getBytes("UTF-8")).flip(); assertEquals(0, channel.read(new ByteBuffer[] {buffer})); channel.unget(messageBuffer); assertEquals (15, channel.read(new ByteBuffer[] {buffer})); assertReadMessage(buffer, "pushed read dat"); } @Test public void readFirstChannelDataToByteArray() throws IOException { firstChannel.setReadData("data", "for", "array"); final ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(2), ByteBuffer.allocate(2), ByteBuffer.allocate(2), ByteBuffer.allocate(2), ByteBuffer.allocate(2), ByteBuffer.allocate(2), ByteBuffer.allocate(2)}; assertEquals(12, channel.read(buffer)); assertReadMessage(buffer[0], "da"); assertReadMessage(buffer[1], "ta"); assertReadMessage(buffer[2], "fo"); assertReadMessage(buffer[3], "ra"); assertReadMessage(buffer[4], "rr"); assertReadMessage(buffer[5], "ay"); assertReadMessage(buffer[6]); } @Test public void readFirstChannelDataAndPushedMessageToByteArray1() throws IOException { final ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(3), ByteBuffer.allocate(10)}; final Pool messagePool = new ByteBufferSlicePool(5, 5); final Pooled messageBuffer = messagePool.allocate(); firstChannel.setReadData("JBoss"); messageBuffer.getResource().put("Xnio".getBytes("UTF-8")).flip(); assertEquals(5, channel.read(buffer)); assertEquals(0, channel.read(buffer)); firstChannel.setReadData("Api"); channel.unget(messageBuffer); assertEquals(4, channel.read(buffer)); assertEquals(3, channel.read(buffer)); assertReadMessage(buffer[0], "JBo"); assertReadMessage(buffer[1], "ss", "Xnio", "Api"); } @Test public void readFirstChannelDataAndPushedMessageToByteArray2() throws IOException { final ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(3), ByteBuffer.allocate(10)}; final Pool messagePool = new ByteBufferSlicePool(5, 5); final Pooled messageBuffer1 = messagePool.allocate(); final Pooled messageBuffer2 = messagePool.allocate(); firstChannel.setReadData("JBoss"); messageBuffer1.getResource().put("io".getBytes("UTF-8")).flip(); messageBuffer2.getResource().put("Xn".getBytes("UTF-8")).flip(); assertEquals(5, channel.read(buffer)); assertEquals(0, channel.read(buffer)); firstChannel.setReadData("Api"); channel.unget(messageBuffer1); channel.unget(messageBuffer2); assertEquals(4, channel.read(buffer)); assertEquals(3, channel.read(buffer)); assertReadMessage(buffer[0], "JBo"); assertReadMessage(buffer[1], "ss", "Xnio", "Api"); } @Test public void readPushedMessageToByteArrayWithOffset() throws IOException { final ByteBuffer[] buffer = new ByteBuffer[] {null, ByteBuffer.allocate(50)}; final Pool messagePool = new ByteBufferSlicePool(50, 50); final Pooled messageBuffer = messagePool.allocate(); messageBuffer.getResource().put("read data for array with offset".getBytes("UTF-8")).flip(); assertEquals(0, channel.read(buffer, 1, 1)); channel.unget(messageBuffer); assertEquals (31, channel.read(buffer, 1, 2)); assertReadMessage(buffer[1], "read data for array with offset"); } @Test public void readFirstChannelDataToByteArrayWithOffset() throws IOException { firstChannel.setReadData("read to byte array [1]"); final ByteBuffer[] buffer = new ByteBuffer[] {null, ByteBuffer.allocate(50)}; assertEquals(22, channel.read(buffer, 1, 1)); assertReadMessage(buffer[1], "read to byte array [1]"); } @Test public void readFirstChannelDataAndPushedMessageToByteArrayWithOffset1() throws IOException { final ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(20), ByteBuffer.allocate(20), ByteBuffer.allocate(20), ByteBuffer.allocate(20)}; final Pool messagePool = new ByteBufferSlicePool(20, 20); final Pooled messageBuffer = messagePool.allocate(); firstChannel.setReadData("123456789"); messageBuffer.getResource().put("10111213141516171819".getBytes("UTF-8")).flip(); assertEquals(9, channel.read(buffer, 1, 2)); assertEquals(0, channel.read(buffer, 1, 2)); firstChannel.setReadData("20212223242526272829"); channel.unget(messageBuffer); assertEquals(20, channel.read(buffer, 1, 2)); assertEquals(11, channel.read(buffer, 1, 2)); assertReadMessage(buffer[0]); assertReadMessage(buffer[1], "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "1"); assertReadMessage(buffer[2], "5", "16", "17", "18", "19", "20", "21", "22", "23", "24", "2"); assertReadMessage(buffer[3]); } @Test public void readFirstChannelDataAndPushedMessageToByteArrayWithOffset2() throws IOException { final ByteBuffer[] buffer = new ByteBuffer[] {ByteBuffer.allocate(20), ByteBuffer.allocate(20), ByteBuffer.allocate(20), ByteBuffer.allocate(20)}; final Pool messagePool = new ByteBufferSlicePool(20, 20); final Pooled messageBuffer1 = messagePool.allocate(); final Pooled messageBuffer2 = messagePool.allocate(); firstChannel.setReadData("123456789"); messageBuffer1.getResource().put("16171819".getBytes("UTF-8")).flip(); messageBuffer2.getResource().put("101112131415".getBytes("UTF-8")).flip(); assertEquals(9, channel.read(buffer, 1, 2)); assertEquals(0, channel.read(buffer, 1, 2)); firstChannel.setReadData("20212223242526272829"); channel.unget(messageBuffer1); channel.unget(messageBuffer2); assertEquals(20, channel.read(buffer, 1, 2)); assertEquals(11, channel.read(buffer, 1, 2)); assertReadMessage(buffer[0]); assertReadMessage(buffer[1], "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "1"); assertReadMessage(buffer[2], "5", "16", "17", "18", "19", "20", "21", "22", "23", "24", "2"); assertReadMessage(buffer[3]); } @Test public void transferPushedMessageToFileChannel() throws IOException { final Pool messagePool = new ByteBufferSlicePool(15, 15); final Pooled messageBuffer = messagePool.allocate(); messageBuffer.getResource().put("pushed message".getBytes("UTF-8")).flip(); final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final FileChannel fileChannel = new RandomAccessFile(file, "rw").getChannel(); try { assertEquals(0, channel.transferTo(0, 6, fileChannel)); channel.unget(messageBuffer); assertEquals (6, channel.transferTo(0, 6, fileChannel)); fileChannel.position(0); final ByteBuffer transferedMessage = ByteBuffer.allocate(6); assertEquals(6, fileChannel.read(transferedMessage)); assertReadMessage(transferedMessage, "pushed"); } finally { fileChannel.close(); } } @Test public void transferFirstChannelDataToFileChannel() throws IOException { firstChannel.setReadData("data", "from", "first", "channel"); final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final FileChannel fileChannel = new RandomAccessFile(file, "rw").getChannel(); try { assertEquals(20, channel.transferTo(0, 30, fileChannel)); fileChannel.position(0); final ByteBuffer transferedMessage = ByteBuffer.allocate(30); assertEquals(20, fileChannel.read(transferedMessage)); assertReadMessage(transferedMessage, "data", "from", "first", "channel"); } finally { fileChannel.close(); } } @Test public void transferFirstChannelDataAndPushedMessageToFileChannel1() throws IOException { firstChannel.setReadData("x"); final Pool messagePool = new ByteBufferSlicePool(5, 5); final Pooled messageBuffer = messagePool.allocate(); messageBuffer.getResource().put("nio".getBytes("UTF-8")).flip(); final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final FileChannel fileChannel = new RandomAccessFile(file, "rw").getChannel(); try { assertEquals(1, channel.transferTo(0, 6, fileChannel)); assertEquals(0, channel.transferTo(1, 6, fileChannel)); firstChannel.setReadData("-api"); channel.unget(messageBuffer); assertEquals (6, channel.transferTo(1, 6, fileChannel)); assertEquals (1, channel.transferTo(7, 6, fileChannel)); fileChannel.position(0); final ByteBuffer transferedMessage = ByteBuffer.allocate(10); assertEquals(8, fileChannel.read(transferedMessage)); assertReadMessage(transferedMessage, "xnio-api"); } finally { fileChannel.close(); } } @Test public void transferFirstChannelDataAndPushedMessageToFileChannel2() throws IOException { firstChannel.setReadData("x"); final Pool messagePool = new ByteBufferSlicePool(5, 5); final Pooled messageBuffer1 = messagePool.allocate(); messageBuffer1.getResource().put("io".getBytes("UTF-8")).flip(); final Pooled messageBuffer2 = messagePool.allocate(); messageBuffer2.getResource().put("n".getBytes("UTF-8")).flip(); final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final FileChannel fileChannel = new RandomAccessFile(file, "rw").getChannel(); try { assertEquals(1, channel.transferTo(0, 6, fileChannel)); assertEquals(0, channel.transferTo(1, 6, fileChannel)); firstChannel.setReadData("-api"); channel.unget(messageBuffer1); channel.unget(messageBuffer2); assertEquals (6, channel.transferTo(1, 6, fileChannel)); assertEquals (1, channel.transferTo(7, 6, fileChannel)); fileChannel.position(0); final ByteBuffer transferedMessage = ByteBuffer.allocate(10); assertEquals(8, fileChannel.read(transferedMessage)); assertReadMessage(transferedMessage, "xnio-api"); } finally { fileChannel.close(); } } @Test public void transferToStreamSinkChannel() throws Exception { final Pool messagePool = new ByteBufferSlicePool(15, 15); final Pooled messageBuffer = messagePool.allocate(); messageBuffer.getResource().put("pushed message".getBytes("UTF-8")).flip(); final ConnectedStreamChannelMock sinkChannel = new ConnectedStreamChannelMock(); assertEquals(0, channel.transferTo(15, ByteBuffer.allocate(60), sinkChannel)); channel.unget(messageBuffer); assertEquals(14, channel.transferTo(15, ByteBuffer.allocate(60), sinkChannel)); assertReadMessage(sinkChannel.getWrittenBytes(), "pushed", " ", "message"); } @Test public void transferFirstChannelDataToSinkChannel() throws IOException { firstChannel.setReadData("data!", "from@", "first#", "channel$"); final ConnectedStreamChannelMock sinkChannel = new ConnectedStreamChannelMock(); assertEquals(24, channel.transferTo(30, ByteBuffer.allocate(60), sinkChannel)); assertReadMessage(sinkChannel.getWrittenBytes(), "data!", "from@", "first#", "channel$"); } @Test public void transferFirstChannelDataAndPushedMessageToSinkChannel1() throws IOException { firstChannel.setReadData("1+"); final Pool messagePool = new ByteBufferSlicePool(5, 5); final Pooled messageBuffer = messagePool.allocate(); messageBuffer.getResource().put("2=".getBytes("UTF-8")).flip(); final ConnectedStreamChannelMock sinkChannel = new ConnectedStreamChannelMock(); final ByteBuffer throughBuffer = ByteBuffer.allocate(10); assertEquals(1, channel.transferTo(1, throughBuffer, sinkChannel)); assertEquals(1, channel.transferTo(1, throughBuffer, sinkChannel)); assertEquals(0, channel.transferTo(1, throughBuffer, sinkChannel)); firstChannel.setReadData("3"); channel.unget(messageBuffer); assertEquals (1, channel.transferTo(1, throughBuffer, sinkChannel)); assertEquals (1, channel.transferTo(1, throughBuffer, sinkChannel)); assertEquals (1, channel.transferTo(1, throughBuffer, sinkChannel)); assertEquals (0, channel.transferTo(1, throughBuffer, sinkChannel)); assertReadMessage(sinkChannel.getWrittenBytes(), "1+2=3"); } @Test public void transferFirstChannelDataAndPushedMessageToSinkChannel2() throws IOException { firstChannel.setReadData("1+"); final Pool messagePool = new ByteBufferSlicePool(5, 5); final Pooled messageBuffer1 = messagePool.allocate(); messageBuffer1.getResource().put("30".getBytes("UTF-8")).flip(); final Pooled messageBuffer2 = messagePool.allocate(); messageBuffer2.getResource().put("2+".getBytes("UTF-8")).flip(); final ConnectedStreamChannelMock sinkChannel = new ConnectedStreamChannelMock(); final ByteBuffer throughBuffer = ByteBuffer.allocate(10); assertEquals(1, channel.transferTo(1, throughBuffer, sinkChannel)); assertEquals(1, channel.transferTo(1, throughBuffer, sinkChannel)); assertEquals(0, channel.transferTo(1, throughBuffer, sinkChannel)); firstChannel.setReadData("=33"); channel.unget(messageBuffer1); channel.unget(messageBuffer2); assertEquals (3, channel.transferTo(3, throughBuffer, sinkChannel)); assertEquals (3, channel.transferTo(3, throughBuffer, sinkChannel)); assertEquals (1, channel.transferTo(3, throughBuffer, sinkChannel)); assertEquals (0, channel.transferTo(3, throughBuffer, sinkChannel)); assertReadMessage(sinkChannel.getWrittenBytes(), "1+2+30=33"); } @Test public void suspendResumeReads() throws Exception { channel.resumeReads(); assertTrue(firstChannel.isReadResumed()); Thread t = new Thread(new Runnable() { public void run() { firstChannel.setReadData("test"); } }); t.start(); channel.awaitReadable(); t.join(); channel.suspendReads(); assertFalse(firstChannel.isReadResumed()); t = new Thread(new Runnable() { public void run() { channel.resumeReads(); } }); t.start(); channel.awaitReadable(10, TimeUnit.SECONDS); t.join(); // push data final Pool messagePool = new ByteBufferSlicePool(15, 15); final Pooled messageBuffer = messagePool.allocate(); messageBuffer.getResource().put("pushed message".getBytes("UTF-8")).flip(); channel.unget(messageBuffer); channel.resumeReads(); assertTrue(firstChannel.isReadResumed()); channel.awaitReadable(); channel.suspendReads(); assertFalse(firstChannel.isReadResumed()); channel.awaitReadable(10, TimeUnit.DAYS); } @Test public void shutdownReads() throws IOException { channel.shutdownReads(); assertTrue(firstChannel.isShutdownReads()); // shutdownReads is idempotent channel.shutdownReads(); assertTrue(firstChannel.isShutdownReads()); // cannot unget after shutdown final Pool messagePool = new ByteBufferSlicePool(5, 5); final Pooled messageBuffer = messagePool.allocate(); boolean bufferCleared = false; messageBuffer.getResource().put("a".getBytes("UTF-8")).flip(); channel.unget(messageBuffer); try { messageBuffer.getResource(); } catch (IllegalStateException e) { bufferCleared = true; } assertTrue(bufferCleared); // cannot read final ByteBuffer buffer = ByteBuffer.allocate(30); assertEquals(-1, channel.read(buffer)); assertEquals(-1, channel.read(new ByteBuffer[] {buffer}, 0, 1)); // cannot transfer final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final FileChannel fileChannel = new RandomAccessFile(file, "rw").getChannel(); try { assertEquals(0, channel.transferTo(0, 10, null)); } finally { fileChannel.close(); } assertEquals(-1L, channel.transferTo(10, ByteBuffer.allocate(10), new ConnectedStreamChannelMock())); } @Test public void shutdownReadsWithPushedData() throws IOException { final Pool messagePool = new ByteBufferSlicePool(5, 5); final Pooled messageBuffer1 = messagePool.allocate(); messageBuffer1.getResource().put("1".getBytes("UTF-8")).flip(); channel.unget(messageBuffer1); final Pooled messageBuffer2 = messagePool.allocate(); messageBuffer2.getResource().put("2".getBytes("UTF-8")).flip(); channel.unget(messageBuffer2); channel.shutdownReads(); assertTrue(firstChannel.isShutdownReads()); // shutdownReads is idempotent channel.shutdownReads(); assertTrue(firstChannel.isShutdownReads()); // cannot unget after shutdown final Pooled messageBuffer3 = messagePool.allocate(); boolean bufferCleared = false; messageBuffer3.getResource().put("3".getBytes("UTF-8")).flip(); channel.unget(messageBuffer3); try { messageBuffer3.getResource(); } catch (IllegalStateException e) { bufferCleared = true; } assertTrue(bufferCleared); // cannot read final ByteBuffer buffer = ByteBuffer.allocate(30); assertEquals(-1, channel.read(buffer)); assertEquals(-1, channel.read(new ByteBuffer[] {buffer}, 0, 1)); // cannot transfer final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final FileChannel fileChannel = new RandomAccessFile(file, "rw").getChannel(); try { assertEquals(0, channel.transferTo(0, 10, null)); } finally { fileChannel.close(); } assertEquals(-1L, channel.transferTo(10, ByteBuffer.allocate(10), new ConnectedStreamChannelMock())); } @Test public void closeEmptyChannel() throws IOException { channel.close(); assertFalse(channel.isOpen()); assertFalse(firstChannel.isOpen()); // close is idempotent channel.close(); assertFalse(channel.isOpen()); assertFalse(firstChannel.isOpen()); // close is idempotent channel.close(); assertFalse(channel.isOpen()); assertFalse(firstChannel.isOpen()); // cannot unget after closed final Pool messagePool = new ByteBufferSlicePool(5, 5); final Pooled messageBuffer = messagePool.allocate(); boolean bufferCleared = false; messageBuffer.getResource().put("a".getBytes("UTF-8")).flip(); channel.unget(messageBuffer); try { messageBuffer.getResource(); } catch (IllegalStateException e) { bufferCleared = true; } assertTrue(bufferCleared); // cannot read final ByteBuffer buffer = ByteBuffer.allocate(30); assertEquals(-1, channel.read(buffer)); assertEquals(-1, channel.read(new ByteBuffer[] {buffer})); assertEquals(-1, channel.read(new ByteBuffer[] {buffer}, 0, 1)); // cannot transfer final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final FileChannel fileChannel = new RandomAccessFile(file, "rw").getChannel(); try { assertEquals(0, channel.transferTo(0, 10, null)); } finally { fileChannel.close(); } assertEquals(-1L, channel.transferTo(10, ByteBuffer.allocate(10), new ConnectedStreamChannelMock())); // await readable does nothing channel.awaitReadable(); channel.awaitReadable(1, TimeUnit.DAYS); } @Test public void closeChannelWithPushedData() throws IOException { final Pool messagePool = new ByteBufferSlicePool(5, 5); final Pooled messageBuffer1 = messagePool.allocate(); messageBuffer1.getResource().put("1".getBytes("UTF-8")).flip(); channel.unget(messageBuffer1); final Pooled messageBuffer2 = messagePool.allocate(); messageBuffer2.getResource().put("2".getBytes("UTF-8")).flip(); channel.unget(messageBuffer2); channel.close(); assertFalse(channel.isOpen()); assertFalse(firstChannel.isOpen()); // close is idempotent channel.close(); assertFalse(channel.isOpen()); assertFalse(firstChannel.isOpen()); // cannot unget after closed final Pooled messageBuffer3 = messagePool.allocate(); boolean bufferCleared = false; messageBuffer3.getResource().put("3".getBytes("UTF-8")).flip(); channel.unget(messageBuffer3); try { messageBuffer3.getResource(); } catch (IllegalStateException e) { bufferCleared = true; } assertTrue(bufferCleared); // cannot read final ByteBuffer buffer = ByteBuffer.allocate(30); assertEquals(-1, channel.read(buffer)); assertEquals(-1, channel.read(new ByteBuffer[] {buffer})); assertEquals(-1, channel.read(new ByteBuffer[] {buffer}, 0, 1)); // cannot transfer final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final FileChannel fileChannel = new RandomAccessFile(file, "rw").getChannel(); try { assertEquals(0, channel.transferTo(0, 10, null)); } finally { fileChannel.close(); } assertEquals(-1L, channel.transferTo(10, ByteBuffer.allocate(10), new ConnectedStreamChannelMock())); // await readable does nothing channel.awaitReadable(); channel.awaitReadable(1, TimeUnit.DAYS); } @Test public void delegateOperationsToFirstChannel() throws IOException { assertSame(firstChannel, channel.getChannel()); channel.resumeReads(); assertTrue(firstChannel.isReadResumed()); assertTrue(channel.isReadResumed()); channel.suspendReads(); assertFalse(firstChannel.isReadResumed()); assertFalse(channel.isReadResumed()); channel.wakeupReads(); assertTrue(firstChannel.isReadAwaken()); assertTrue(channel.isReadResumed()); assertSame(firstChannel.getReadThread(), channel.getReadThread()); assertSame(firstChannel.getWorker(), channel.getWorker()); assertSame(firstChannel.isOpen(), channel.isOpen()); firstChannel.setOptionMap(OptionMap.create(Options.KEEP_ALIVE, true, Options.READ_TIMEOUT, 3000)); assertSame(firstChannel.supportsOption(Options.BACKLOG), channel.supportsOption(Options.BACKLOG)); assertSame(firstChannel.supportsOption(Options.KEEP_ALIVE), channel.supportsOption(Options.KEEP_ALIVE)); assertSame(firstChannel.supportsOption(Options.READ_TIMEOUT), channel.supportsOption(Options.READ_TIMEOUT)); assertSame(firstChannel.getOption(Options.BACKLOG), channel.getOption(Options.BACKLOG)); assertSame(firstChannel.getOption(Options.KEEP_ALIVE), channel.getOption(Options.KEEP_ALIVE)); assertSame(firstChannel.getOption(Options.READ_TIMEOUT), channel.getOption(Options.READ_TIMEOUT)); channel.setOption(Options.BACKLOG, 5000); assertEquals(5000, (int) firstChannel.getOption(Options.BACKLOG)); assertEquals(5000, (int) channel.getOption(Options.BACKLOG)); } @Test public void getListenerSetter() { final DummyListener readListener = new DummyListener(); final DummyListener closeListener = new DummyListener(); channel.getReadSetter().set(readListener); channel.getCloseSetter().set(closeListener); assertFalse(readListener.isInvoked()); firstChannel.getReadListener().handleEvent(firstChannel); assertTrue(readListener.isInvoked()); assertFalse(closeListener.isInvoked()); firstChannel.getCloseListener().handleEvent(firstChannel); assertTrue(closeListener.isInvoked()); } private static class DummyListener implements ChannelListener { private boolean invoked = false; @Override public void handleEvent(PushBackStreamChannel channel) { invoked = true; } public boolean isInvoked() { return invoked; } }; } xnio-3.3.2.Final/api/src/test/java/org/xnio/channels/SocketAddressBufferTestCase.java000066400000000000000000000053571257016060700305300ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.channels; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import java.net.InetSocketAddress; import java.net.SocketAddress; import org.junit.Test; import org.xnio.LocalSocketAddress; /** * Test for {@link SocketAddressBuffer}. * * @author Flavia Rainone * */ public class SocketAddressBufferTestCase { @Test public void test() { final SocketAddressBuffer buffer = new SocketAddressBuffer(); final SocketAddress sourceAddress = new InetSocketAddress(10); final SocketAddress destinationAddress = new InetSocketAddress("farfarhost", 15); assertNull(buffer.getSourceAddress()); assertNull(buffer.getSourceAddress(InetSocketAddress.class)); assertNull(buffer.getSourceAddress(LocalSocketAddress.class)); buffer.setSourceAddress(sourceAddress); assertSame(sourceAddress, buffer.getSourceAddress()); assertSame(sourceAddress, buffer.getSourceAddress(InetSocketAddress.class)); assertNull(buffer.getSourceAddress(LocalSocketAddress.class)); assertNull(buffer.getDestinationAddress()); assertNull(buffer.getDestinationAddress(InetSocketAddress.class)); assertNull(buffer.getDestinationAddress(LocalSocketAddress.class)); buffer.setDestinationAddress(destinationAddress); assertSame(destinationAddress, buffer.getDestinationAddress()); assertSame(destinationAddress, buffer.getDestinationAddress(InetSocketAddress.class)); assertNull(buffer.getDestinationAddress(LocalSocketAddress.class)); buffer.clear(); assertNull(buffer.getSourceAddress()); assertNull(buffer.getSourceAddress(InetSocketAddress.class)); assertNull(buffer.getSourceAddress(LocalSocketAddress.class)); assertNull(buffer.getDestinationAddress()); assertNull(buffer.getDestinationAddress(InetSocketAddress.class)); assertNull(buffer.getDestinationAddress(LocalSocketAddress.class)); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/http/000077500000000000000000000000001257016060700215135ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/org/xnio/http/HttpParserTestCase.java000066400000000000000000000077231257016060700261170ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.http; import java.io.IOException; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import org.junit.Assert; import org.junit.Test; /** * @author Stuart Douglas */ public class HttpParserTestCase { @Test public void testSimpleResponses() throws IOException { runTest("HTTP/1.1 101 Upgrade\r\n\r\n", 101, "HTTP/1.1", "Upgrade"); runTest("HTTP/1.1 101 Upgrade\r\nConnection: Upgrade\r\n\r\n", 101, "HTTP/1.1", "Upgrade", "connection", "Upgrade"); runTest("HTTP/1.1 404 Not Found\r\nConnection: close\r\nSet-Cookie: someCookie\r\n\r\n", 404, "HTTP/1.1", "Not Found", "connection", "close", "set-cookie", "someCookie"); } public void runTest(String response, final int status, final String version, final String message, final String... header) throws IOException { final Map headerMap = new HashMap(); Assert.assertEquals("Headers must be a multiple of 2", 0, header.length % 2); for (int i = 0; i < header.length; i += 2) { headerMap.put(header[i], header[i + 1]); } testMethodSplit(response, status, version, message, headerMap); testOneCharacterAtATime(response, status, version, message, headerMap); } void testMethodSplit(String response, final int status, final String version, final String message, final Map headers) { byte[] in = response.getBytes(); for (int i = 0; i < in.length - 4; ++i) { try { testSplit(i, in, status, version, message, headers); } catch (Throwable e) { throw new RuntimeException("Test failed at split " + i, e); } } } public void testOneCharacterAtATime(String response, final int status, final String version, final String message, final Map headers) throws IOException { ByteBuffer buffer = ByteBuffer.wrap(response.getBytes()); buffer.limit(0); final HttpUpgradeParser parser = new HttpUpgradeParser(); while (!parser.isComplete()) { buffer.limit(buffer.limit() + 1); parser.parse(buffer); } runAssertions(parser, status, version, message, headers); } private void testSplit(final int split, byte[] in, final int status, final String version, final String message, final Map headers) throws IOException { final HttpUpgradeParser parser = new HttpUpgradeParser(); ByteBuffer buffer = ByteBuffer.wrap(in); buffer.limit(split); parser.parse(buffer); buffer.limit(buffer.capacity()); parser.parse(buffer); runAssertions(parser, status, version, message, headers); } private void runAssertions(HttpUpgradeParser parser, final int status, final String version, final String message, final Map headers) { Assert.assertEquals(status, parser.getResponseCode()); Assert.assertEquals(version, parser.getHttpVersion()); Assert.assertEquals(message, parser.getMessage()); Assert.assertEquals(headers.size(), parser.getHeaders().size()); for (Map.Entry entry : headers.entrySet()) { Assert.assertEquals(entry.getValue(), parser.getHeaders().get(entry.getKey()).get(0)); } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/mock/000077500000000000000000000000001257016060700214655ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/org/xnio/mock/AcceptingChannelMock.java000066400000000000000000000152241257016060700263340ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.mock; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.Arrays; import java.util.HashSet; import java.util.Set; import java.util.concurrent.TimeUnit; import org.xnio.ChannelListener; import org.xnio.ChannelListener.Setter; import org.xnio.ChannelListener.SimpleSetter; import org.xnio.Option; import org.xnio.OptionMap; import org.xnio.OptionMap.Builder; import org.xnio.StreamConnection; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.AcceptingChannel; /** * {@link AcceptingChannel} mock. * * @author Flavia Rainone */ public class AcceptingChannelMock implements AcceptingChannel, Mock { private SimpleSetter acceptSetter = new SimpleSetter(); private SimpleSetter closeSetter = new SimpleSetter(); private volatile boolean acceptanceEnabled = true; private OptionMap optionMap = OptionMap.EMPTY; private boolean closed = false; private SocketAddress localAddress; private boolean acceptsResumed = false; private boolean acceptsWokenUp = false; private boolean waitedAcceptable = false; private long awaitAcceptableTime; private TimeUnit awaitAcceptableTimeUnit; private String info = null; // any extra information regarding this channel used by tests public AcceptingChannelMock() { setWorker(new XnioWorkerMock()); } public void setLocalAddress(SocketAddress address) { localAddress = address; } @Override public SocketAddress getLocalAddress() { return localAddress; } @Override public A getLocalAddress(Class type) { if (type.isAssignableFrom(localAddress.getClass())) { return type.cast(localAddress); } return null; } private XnioWorkerMock worker = null; public XnioIoThread getIoThread() { return worker.chooseThread(); } @Override public XnioWorker getWorker() { return worker; } public void setWorker(XnioWorkerMock worker) { this.worker = worker; } @Override public void close() throws IOException { closed = true; } @Override public boolean isOpen() { return !closed; } private Option[] supportedOptions; @Override public boolean supportsOption(Option option) { final Set> supported = new HashSet>(Arrays.asList(supportedOptions)); return supported.contains(option); } public void setSupportedOptions(Option ... options) { supportedOptions = options; } @Override public T getOption(Option option) throws IOException { return optionMap.get(option); } @Override public T setOption(Option option, T value) throws IllegalArgumentException, IOException { Builder optionMapBuilder = OptionMap.builder(); optionMapBuilder.addAll(optionMap); optionMapBuilder.set(option, value); T oldValue = optionMap.get(option); optionMap = optionMapBuilder.getMap(); return oldValue; } @Override public OptionMap getOptionMap() { return optionMap; } public void setOptionMap(OptionMap optionMap) { this.optionMap = optionMap; } @Override public void suspendAccepts() { acceptsResumed = acceptsWokenUp = false; } @Override public void resumeAccepts() { acceptsResumed = true; } public boolean isAcceptResumed() { return acceptsResumed; } @Override public void wakeupAccepts() { acceptsResumed = acceptsWokenUp = true; } public boolean isAcceptWokenUp() { return acceptsWokenUp; } public void clearWaitedAcceptable() { waitedAcceptable = false; } public boolean haveWaitedAcceptable() { return waitedAcceptable; } public long getAwaitAcceptableTime() { return awaitAcceptableTime; } public TimeUnit getAwaitAcceptableTimeUnit() { return awaitAcceptableTimeUnit; } @Override public void awaitAcceptable() throws IOException { waitedAcceptable = true; } @Override public void awaitAcceptable(long time, TimeUnit timeUnit) throws IOException { waitedAcceptable = true; awaitAcceptableTime = time; awaitAcceptableTimeUnit = timeUnit; } @Override public StreamConnectionMock accept() throws IOException { if (acceptanceEnabled) { final XnioIoThread thread = worker.chooseThread(); StreamConnectionMock streamConnection = new StreamConnectionMock(new ConduitMock(worker, thread)); streamConnection.setPeerAddress(new InetSocketAddress(42630)); streamConnection.setInfo(getInfo()); streamConnection.setOptionMap(getOptionMap()); streamConnection.setServer(this); if (acceptSetter.get() != null) { acceptSetter.get().handleEvent(this); } return streamConnection; } return null; } @Override public Setter> getAcceptSetter() { return acceptSetter; } @Override public Setter> getCloseSetter() { return closeSetter; } public ChannelListener getAcceptListener() { return acceptSetter.get(); } public void enableAcceptance(boolean enable) { acceptanceEnabled = enable; } @Override public XnioExecutor getAcceptThread() { return null; } @Override public String getInfo() { return info; } @Override public void setInfo(String i) { info = i; } } xnio-3.3.2.Final/api/src/test/java/org/xnio/mock/ConduitMock.java000066400000000000000000000676071257016060700245670ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.mock; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.LockSupport; import org.xnio.Buffers; import org.xnio.IoUtils; import org.xnio.OptionMap; import org.xnio.StreamConnection; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.AssembledConnectedStreamChannel; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; import org.xnio.conduits.Conduits; import org.xnio.conduits.ReadReadyHandler; import org.xnio.conduits.StreamSinkConduit; import org.xnio.conduits.StreamSourceConduit; import org.xnio.conduits.WriteReadyHandler; /** * Mock of a sink/source conduit.

* This channel mock will store everything that is written to it for later comparison, and allows feeding of bytes for * reading. * * @author Flavia Rainone */ public class ConduitMock implements StreamSinkConduit, StreamSourceConduit, Mock{ // written stuff will be copied to this buffer private ByteBuffer writeBuffer = ByteBuffer.allocate(1000); // read stuff will be taken from this buffer private ByteBuffer readBuffer = ByteBuffer.allocate(10000); // if eof is true, read will return -1 if readBuffer is empty private boolean eof = false; // read stuff can only be read if read operations are enabled private boolean readsEnabled; // can only write when write operations are enabled private boolean writesEnabled = true; // terminateWrites() will be ignored if allowTerminateWrites is false private boolean allowTerminateWrites = true; // is flush enabled private boolean flushEnabled = true; // enables check for closed conduit (if an attempt to perform an operation is performed once this conduit is // closed, a ClosedChannelException will be thrown only if checkClosed is true) private boolean checkClosed = true; // is write operation resumed private boolean writesResumed = false; // is write operation awaken private boolean writesAwaken = false; // is write operation terminated private boolean writesTerminated = false; // is write operation truncated private boolean writesTruncated = false; // are all written contents flushed private boolean flushed = true; // is read operation resumed private boolean readsResumed = false; // is read operation awaken private boolean readsAwaken = false; // is read operation terminated private boolean readsTerminated = false; // indicates if this conduit is closed private boolean closed = false; // the worker private XnioWorker worker; // the executor private XnioIoThread executor; // read waiter private Thread readWaiter; // write waiter private Thread writeWaiter; // write ready handler // implement this when needed @SuppressWarnings("unused") private WriteReadyHandler writeReadyHandler; // read ready handler // implement this when needed @SuppressWarnings("unused") private ReadReadyHandler readReadyHandler; // any extra information regarding this channel used by tests private String info = null; public ConduitMock(XnioWorker worker, XnioIoThread xnioIoThread) { this.executor = xnioIoThread; this.worker = worker; } public ConduitMock() { final XnioWorkerMock worker = new XnioWorkerMock(); this.worker = worker; this.executor = worker.chooseThread(); } /** * Returns the executor. */ XnioIoThread getXnioIoThread() { return executor; } // implement this for handlers when needed // listener setters // private final ChannelListener.Setter readListenerSetter = new ChannelListener.Setter() { // @Override // public void set(ChannelListener listener) { // readListener = listener; // } // }; // // private final ChannelListener.Setter writeListenerSetter = new ChannelListener.Setter() { // @Override // public void set(ChannelListener listener) { // writeListener = listener; // } // }; // // private final ChannelListener.Setter closeListenerSetter = new ChannelListener.Setter() { // @Override // public void set(ChannelListener listener) { // closeListener = listener; // } // }; /** * Feeds {@code readData} to read clients. * @param readData data that will be available for reading */ public void setReadData(String... readData) { final Thread waiter; synchronized (this) { int totalLength = 0; for (String data: readData) { totalLength += data.length(); } int position = readBuffer.position(); boolean resetPosition = false; if (!readBuffer.hasRemaining()) { readBuffer.compact(); } else if(readBuffer.position() > 0 || readBuffer.limit() != readBuffer.capacity()) { if (readBuffer.capacity() - readBuffer.limit() < totalLength) { if (readBuffer.position() > 0 && readBuffer.capacity() - readBuffer.limit() + readBuffer.position() >= totalLength) { readBuffer.compact(); } throw new RuntimeException("ReadBuffer is full - not enough space to add more read data"); } int limit = readBuffer.limit(); readBuffer.position(limit); readBuffer.limit(limit += totalLength); resetPosition = true; } for (String data: readData) { try { readBuffer.put(data.getBytes("UTF-8")); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } readBuffer.flip(); if (resetPosition) { readBuffer.position(position); } if (readWaiter == null || totalLength == 0 || !readsEnabled) { return; } waiter = readWaiter; readWaiter = null; } LockSupport.unpark(waiter); } /** * Feeds {@code readData} to read clients. * @param readData data that will be available for reading */ public void setReadDataWithLength(String... readData) { final Thread waiter; synchronized (this) { if (eof == true) { throw new IllegalStateException("Cannot add read data once eof is set"); } int totalLength = 0; for (String data: readData) { totalLength += data.length(); } int position = readBuffer.position(); boolean resetPosition = false; if (!readBuffer.hasRemaining()) { readBuffer.compact(); } else if(readBuffer.position() > 0 || readBuffer.limit() != readBuffer.capacity()) { if (readBuffer.capacity() - readBuffer.limit() + 4 < totalLength) { if (readBuffer.position() > 0 && readBuffer.capacity() - readBuffer.limit() + readBuffer.position() + 4 >= totalLength) { readBuffer.compact(); } throw new RuntimeException("ReadBuffer is full - not enough space to add more read data"); } int limit = readBuffer.limit(); readBuffer.position(limit); readBuffer.limit(limit += totalLength + 4); resetPosition = true; } readBuffer.putInt(totalLength); for (String data: readData) { try { readBuffer.put(data.getBytes("UTF-8")); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } readBuffer.flip(); if (resetPosition) { readBuffer.position(position); } if (readWaiter == null || totalLength == 0 || !readsEnabled) { return; } waiter = readWaiter; } LockSupport.unpark(waiter); } /** * Feeds {@code readData} to read clients. * @param readData data that will be available for reading on this channel mock */ public void setReadDataWithLength(int length, String... readData) { final Thread waiter; synchronized (this) { if (eof == true) { throw new IllegalStateException("Cannot add read data once eof is set"); } int totalLength = 0; for (String data: readData) { totalLength += data.length(); } int position = readBuffer.position(); boolean resetPosition = false; if (!readBuffer.hasRemaining()) { readBuffer.compact(); } else if(readBuffer.position() > 0 || readBuffer.limit() != readBuffer.capacity()) { if (readBuffer.capacity() - readBuffer.limit() + 4 < totalLength) { if (readBuffer.position() > 0 && readBuffer.capacity() - readBuffer.limit() + readBuffer.position() + 4 >= totalLength) { readBuffer.compact(); } throw new RuntimeException("ReadBuffer is full - not enough space to add more read data"); } int limit = readBuffer.limit(); readBuffer.position(limit); readBuffer.limit(limit += totalLength + 4); resetPosition = true; } readBuffer.putInt(length); for (String data: readData) { try { readBuffer.put(data.getBytes("UTF-8")); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } readBuffer.flip(); if (resetPosition) { readBuffer.position(position); } if (readWaiter == null || totalLength == 0 || !readsEnabled) { return; } waiter = readWaiter; } LockSupport.unpark(waiter); } /** * Marks the eof for read operations. Once eof is set, all read operations will return -1 as soon as there is no * read data available. */ public void setEof() { final Thread waiter; synchronized (this) { eof = true; if (readWaiter == null || !readsEnabled) { return; } waiter = readWaiter; } LockSupport.unpark(waiter); } /** * Indicates if has all read data been consumed by read operations. */ public synchronized boolean allReadDataConsumed() { return readBuffer.position() == readBuffer.limit(); } /** * Enables and disables read operations. If read operations are disabled, read will always return 0, even if * there is {@link #setReadData(String...) read data available} in the local buffer. *

* Read operations are disabled by default. * * @param enable {@code false} for disabling reads, {@code true} for enabling. */ public void enableReads(boolean enable) { final Thread waiter; synchronized (this) { readsEnabled = enable; if (readWaiter == null || !readsEnabled || !((readBuffer.hasRemaining() && readBuffer.limit() != readBuffer.capacity()) || eof)) { return; } waiter = readWaiter; } LockSupport.unpark(waiter); } /** * Enables and disables write operations. If write operations are disabled, write will always return 0. *

* Write operations are enabled by default. * * @param enable {@code false} for disabling writes, {@code true} for enabling. */ public void enableWrites(boolean enable) { final Thread waiter; synchronized (this) { writesEnabled = enable; waiter = writeWaiter; } if (waiter != null) { LockSupport.unpark(waiter); } } /** * Enables check for closed. This will result in a ClosedChannelException is an attempt to execute an operation * is performed when this conduit is closed. If closed check is disabled, any operation can be performed on this * mock regardless of whether it is closed. *

* This check is enabled by default. * * @param enable {@code true} for enabling the closed check, {@code false} for disabling it */ public synchronized void enableClosedCheck(boolean enable) { checkClosed = enable; } /** * Returns all the bytes that have been written to this conduit mock. * * @return the written bytes in the form of a UTF-8 string */ public String getWrittenText() { if (writeBuffer.position() == 0 && writeBuffer.limit() == writeBuffer.capacity()) { return ""; } writeBuffer.flip(); return Buffers.getModifiedUtf8(writeBuffer); } /** * Returns the written bytes buffer * * @return the buffer containing all the bytes that have been written to this conduit mock */ public ByteBuffer getWrittenBytes() { return writeBuffer; } /** * Indicates if all data written to this conduit has been flushed. * @return */ public boolean isFlushed() { return flushed; } /** * Enables and disables flush. If flush is disabled, requests to flush data are ignored. *

* Flush is enabled by default. * * @param enable {@code true} for enabling flush, {@code false} for disabling */ public synchronized void enableFlush(boolean enable) { flushEnabled = enable; } /** * Changes the worker associated with this conduit mock. */ public void setWorker(XnioWorker worker) { this.worker = worker; } @Override public OptionMap getOptionMap() { return optionMap; } @Override public String getInfo() { return info; } @Override public void setInfo(String i) { info = i; } public boolean isOpen() { return !writesTerminated || !readsTerminated; } private OptionMap optionMap; // review this // @Override // public boolean supportsOption(Option option) { // return optionMap == null? false: optionMap.contains(option); // } // // @Override // public T getOption(Option option) throws IOException { // return optionMap == null? null: optionMap.get(option); // } // // @Override // public T setOption(Option option, T value) throws IllegalArgumentException, IOException { // final OptionMap.Builder optionMapBuilder = OptionMap.builder(); // T previousValue = null; // if (optionMap != null) { // optionMapBuilder.addAll(optionMap); // previousValue = optionMap.get(option); // } // optionMapBuilder.set(option, value); // optionMap = optionMapBuilder.getMap(); // return previousValue; // } public void setOptionMap(OptionMap optionMap) { this.optionMap = optionMap; } @Override public void suspendReads() { readsAwaken = false; readsResumed = false; } @Override public void resumeReads() { readsResumed = true; } @Override public boolean isReadResumed() { return readsResumed; } @Override public void terminateReads() throws IOException { readsTerminated = true; return; } @Override public synchronized boolean isReadShutdown() { return readsTerminated; } /** * This mock does not support more than one read thread waiter at the same time. */ @Override public void awaitReadable() throws IOException { synchronized(this) { if (readWaiter != null) { throw new IllegalStateException("ConnectedStreamChannelMock can be used only with one read waiter thread at most... there is already a waiting thread" + readWaiter); } if (((readBuffer.hasRemaining() && readBuffer.capacity() != readBuffer.limit()) || eof) && readsEnabled) { return; } readWaiter = Thread.currentThread(); } LockSupport.park(readWaiter); synchronized(this) { readWaiter = null; } } /** * This mock does not support more than one read thread waiter at the same time. */ @Override public void awaitReadable(long time, TimeUnit timeUnit) throws IOException { synchronized (this) { if (readWaiter != null) { throw new IllegalStateException("ConnectedStreamChannelMock can be used only with one read waiter thread at most... there is already a waiting thread" + readWaiter); } if (((readBuffer.hasRemaining() && readBuffer.capacity() != readBuffer.limit()) || eof) && readsEnabled) { return; } readWaiter = Thread.currentThread(); } // FIXME assertSame("ConnectedStreamChannelMock.awaitReadable(long, TimeUnit) can be used only with TimeUnit.NANOSECONDS", TimeUnit.MILLISECONDS, timeUnit); LockSupport.parkNanos(readWaiter, timeUnit.toNanos(time)); synchronized (this) { readWaiter = null; } } @Override public void suspendWrites() { writesAwaken = false; writesResumed = false; } @Override public void resumeWrites() { writesResumed = true; } @Override public boolean isWriteResumed() { return writesResumed; } @Override public synchronized void terminateWrites() throws IOException { if (!allowTerminateWrites) { return; } writesTerminated = true; final Thread waiter; synchronized (this) { eof = true; if (readWaiter == null) { return; } waiter = readWaiter; } LockSupport.unpark(waiter); return; } @Override public synchronized void truncateWrites() throws IOException { terminateWrites(); writesTruncated = true; } @Override public synchronized boolean isWriteShutdown() { return writesTerminated; } public synchronized boolean isWriteTruncated() { return writesTruncated; } /** * This mock does not support more than one read thread waiter at the same time. */ @Override public void awaitWritable() throws IOException { synchronized(this) { if (writeWaiter != null) { throw new IllegalStateException("ConnectedStreamChannelMock can be used only with one write waiter thread at most... there is already a waiting thread" + writeWaiter); } if (writesEnabled) { return; } writeWaiter = Thread.currentThread(); } LockSupport.park(writeWaiter); synchronized(this) { writeWaiter = null; } } /** * This mock does not support more than one write thread waiter at the same time. */ @Override public void awaitWritable(long time, TimeUnit timeUnit) throws IOException { synchronized (this) { if (writeWaiter != null) { throw new IllegalStateException("ConnectedStreamChannelMock can be used only with one write waiter thread at most... there is already a waiting thread" + writeWaiter); } if (writesEnabled) { return; } writeWaiter = Thread.currentThread(); } // FIXME assertSame("ConnectedStreamChannelMock.awaitWritable(long, TimeUnit) can be used only with TimeUnit.NANOSECONDS", TimeUnit.NANOSECONDS, timeUnit); LockSupport.parkNanos(writeWaiter, timeUnit.toNanos(time)); synchronized (this) { writeWaiter = null; } } @Override public XnioIoThread getWriteThread() { return executor; } @Override public synchronized boolean flush() throws IOException { if (flushEnabled) { flushed = true; } return flushed; } @Override public long transferFrom(FileChannel src, long position, long count) throws IOException { if (writesEnabled) { final StreamConnection connection = new StreamConnectionMock(this); final AssembledConnectedStreamChannel assembledChannel = new AssembledConnectedStreamChannel(connection, connection.getSourceChannel(), connection.getSinkChannel()); return src.transferTo(position, count, assembledChannel); } return 0; } @Override public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { if (writesEnabled) { final StreamConnection connection = new StreamConnectionMock(this); final AssembledConnectedStreamChannel assembledChannel = new AssembledConnectedStreamChannel(connection, connection.getSourceChannel(), connection.getSinkChannel()); IoUtils.transfer(source, count, throughBuffer, assembledChannel); } return 0; } @Override public synchronized int write(ByteBuffer src) throws IOException { if (closed && checkClosed) { throw new ClosedChannelException(); } if (writesEnabled) { if (writeBuffer.limit() < writeBuffer.capacity()) { writeBuffer.limit(writeBuffer.capacity()); } int bytes = Buffers.copy(writeBuffer, src); if (bytes > 0) { flushed = false; } return bytes; } return 0; } @Override public synchronized long write(ByteBuffer[] srcs, int offset, int length) throws IOException { if (closed && checkClosed) { throw new ClosedChannelException(); } if (writesEnabled) { if (writeBuffer.limit() < writeBuffer.capacity()) { writeBuffer.limit(writeBuffer.capacity()); } int bytes = Buffers.copy(writeBuffer, srcs, offset, length); if (bytes > 0) { flushed = false; } return bytes; } return 0; } @Override public int writeFinal(ByteBuffer src) throws IOException { return Conduits.writeFinalBasic(this, src); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { return Conduits.writeFinalBasic(this, srcs, offset, length); } @Override public long transferTo(long position, long count, FileChannel target) throws IOException { if (readsEnabled) { final StreamConnection connection = new StreamConnectionMock(this); final AssembledConnectedStreamChannel assembledChannel = new AssembledConnectedStreamChannel(connection, connection.getSourceChannel(), connection.getSinkChannel()); return target.transferFrom(assembledChannel, position, count); } return 0; } @Override public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { if (readsEnabled) { final StreamConnection connection = new StreamConnectionMock(this); final AssembledConnectedStreamChannel assembledChannel = new AssembledConnectedStreamChannel(connection, connection.getSourceChannel(), connection.getSinkChannel()); return IoUtils.transfer(assembledChannel, count, throughBuffer, target); } return 0; } @Override public synchronized int read(ByteBuffer dst) throws IOException { if (closed && checkClosed) { throw new ClosedChannelException(); } if (readsEnabled) { try { if ((!readBuffer.hasRemaining() || readBuffer.position() == 0 && readBuffer.limit() == readBuffer.capacity()) && eof) { return -1; } if (readBuffer.limit() == readBuffer.capacity() && readBuffer.position() == 0) { return 0; } return Buffers.copy(dst, readBuffer); } catch (RuntimeException e) { System.out.println("Got exception at attempt of copying contents of dst "+ dst.remaining() + " into read buffer " + readBuffer.remaining()); throw e; } } return 0; } @Override public synchronized long read(ByteBuffer[] dsts, int offset, int length) throws IOException { if (closed && checkClosed) { throw new ClosedChannelException(); } if (readsEnabled) { if ((!readBuffer.hasRemaining() || readBuffer.position() == 0 && readBuffer.limit() == readBuffer.capacity()) && eof) { return -1; } if (readBuffer.limit() == readBuffer.capacity() && readBuffer.position() == 0) { return 0; } return Buffers.copy(dsts, offset, length, readBuffer); } return 0; } @Override public XnioWorker getWorker() { return worker; } @Override public void wakeupReads() { readsAwaken = true; readsResumed = true; } public boolean isReadAwaken() { return readsAwaken; } @Override public void wakeupWrites() { writesAwaken = true; writesResumed = true; } public boolean isWriteAwaken() { return writesAwaken; } // implement this when needed // @Override // public Setter getReadSetter() { // return readListenerSetter; // } // // @Override // public Setter getWriteSetter() { // return writeListenerSetter; // } // // @Override // public Setter getCloseSetter() { // return closeListenerSetter; // } // public ChannelListener getReadListener() { // return readListener; // } // // public ChannelListener getWriteListener() { // return writeListener; // } // // public ChannelListener getCloseListener() { // return closeListener; // } @Override // make ready handler active when needed public synchronized void setWriteReadyHandler(WriteReadyHandler handler) { writeReadyHandler = handler; } @Override // make ready handler active when needed public void setReadReadyHandler(ReadReadyHandler handler) { readReadyHandler = handler; } @Override public XnioIoThread getReadThread() { return executor; } } xnio-3.3.2.Final/api/src/test/java/org/xnio/mock/ConnectedStreamChannelMock.java000066400000000000000000000620421257016060700275150ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2011 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.mock; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.LockSupport; import org.xnio.Buffers; import org.xnio.ChannelListener; import org.xnio.ChannelListener.Setter; import org.xnio.IoUtils; import org.xnio.Option; import org.xnio.OptionMap; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.Channels; import org.xnio.channels.ConnectedStreamChannel; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; /** * Mock of a connected stream channel.

* This channel mock will store everything that is written to it for later comparison, and allows feeding of bytes for * reading. * * @author Flavia Rainone */ public class ConnectedStreamChannelMock implements ConnectedStreamChannel, StreamSourceChannel, StreamSinkChannel, Mock{ // written stuff will be copied to this buffer private ByteBuffer writeBuffer = ByteBuffer.allocate(1000); // read stuff will be taken from this buffer private ByteBuffer readBuffer = ByteBuffer.allocate(10000); // read stuff can only be read if read is enabled private boolean readEnabled; // can only write when write is enabled private boolean writeEnabled = true; // indicates if this channel is closed private boolean closed = false; private boolean checkClosed = true; private boolean writeResumed = false; private boolean writeAwaken = false; private boolean readAwaken = false; private boolean readResumed = false; private boolean readsDown = false; private boolean writesDown = false; private boolean allowShutdownWrites = true; private boolean flushed = true; private boolean flushEnabled = true; private boolean eof = false; private XnioWorker worker = new XnioWorkerMock(); private XnioIoThread executor = new XnioIoThreadMock(null); private Thread readWaiter; private Thread writeWaiter; private ChannelListener readListener; private ChannelListener writeListener; private ChannelListener closeListener; private String info = null; // any extra information regarding this channel used by tests // listener setters private final ChannelListener.Setter readListenerSetter = new ChannelListener.Setter() { @Override public void set(ChannelListener listener) { readListener = listener; } }; private final ChannelListener.Setter writeListenerSetter = new ChannelListener.Setter() { @Override public void set(ChannelListener listener) { writeListener = listener; } }; private final ChannelListener.Setter closeListenerSetter = new ChannelListener.Setter() { @Override public void set(ChannelListener listener) { closeListener = listener; } }; /** * Feeds {@code readData} to read clients. * @param readData data that will be available for reading on this channel mock */ public void setReadData(String... readData) { final Thread waiter; synchronized (this) { int totalLength = 0; for (String data: readData) { totalLength += data.length(); } int position = readBuffer.position(); boolean resetPosition = false; if (!readBuffer.hasRemaining()) { readBuffer.compact(); } else if(readBuffer.position() > 0 || readBuffer.limit() != readBuffer.capacity()) { if (readBuffer.capacity() - readBuffer.limit() < totalLength) { if (readBuffer.position() > 0 && readBuffer.capacity() - readBuffer.limit() + readBuffer.position() >= totalLength) { readBuffer.compact(); } throw new RuntimeException("ReadBuffer is full - not enough space to add more read data"); } int limit = readBuffer.limit(); readBuffer.position(limit); readBuffer.limit(limit += totalLength); resetPosition = true; } for (String data: readData) { try { readBuffer.put(data.getBytes("UTF-8")); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } readBuffer.flip(); if (resetPosition) { readBuffer.position(position); } if (readWaiter == null || totalLength == 0 || !readEnabled) { return; } waiter = readWaiter; readWaiter = null; } LockSupport.unpark(waiter); } /** * Feeds {@code readData} to read clients. * @param readData data that will be available for reading on this channel mock */ public void setReadDataWithLength(String... readData) { final Thread waiter; synchronized (this) { if (eof == true) { throw new IllegalStateException("Cannot add read data once eof is set"); } int totalLength = 0; for (String data: readData) { totalLength += data.length(); } int position = readBuffer.position(); boolean resetPosition = false; if (!readBuffer.hasRemaining()) { readBuffer.compact(); } else if(readBuffer.position() > 0 || readBuffer.limit() != readBuffer.capacity()) { if (readBuffer.capacity() - readBuffer.limit() + 4 < totalLength) { if (readBuffer.position() > 0 && readBuffer.capacity() - readBuffer.limit() + readBuffer.position() + 4 >= totalLength) { readBuffer.compact(); } throw new RuntimeException("ReadBuffer is full - not enough space to add more read data"); } int limit = readBuffer.limit(); readBuffer.position(limit); readBuffer.limit(limit += totalLength + 4); resetPosition = true; } readBuffer.putInt(totalLength); for (String data: readData) { try { readBuffer.put(data.getBytes("UTF-8")); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } readBuffer.flip(); if (resetPosition) { readBuffer.position(position); } if (readWaiter == null || totalLength == 0 || !readEnabled) { return; } waiter = readWaiter; } LockSupport.unpark(waiter); } /** * Feeds {@code readData} to read clients. * @param readData data that will be available for reading on this channel mock */ public void setReadDataWithLength(int length, String... readData) { final Thread waiter; synchronized (this) { if (eof == true) { throw new IllegalStateException("Cannot add read data once eof is set"); } int totalLength = 0; for (String data: readData) { totalLength += data.length(); } int position = readBuffer.position(); boolean resetPosition = false; if (!readBuffer.hasRemaining()) { readBuffer.compact(); } else if(readBuffer.position() > 0 || readBuffer.limit() != readBuffer.capacity()) { if (readBuffer.capacity() - readBuffer.limit() + 4 < totalLength) { if (readBuffer.position() > 0 && readBuffer.capacity() - readBuffer.limit() + readBuffer.position() + 4 >= totalLength) { readBuffer.compact(); } throw new RuntimeException("ReadBuffer is full - not enough space to add more read data"); } int limit = readBuffer.limit(); readBuffer.position(limit); readBuffer.limit(limit += totalLength + 4); resetPosition = true; } readBuffer.putInt(length); for (String data: readData) { try { readBuffer.put(data.getBytes("UTF-8")); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } } readBuffer.flip(); if (resetPosition) { readBuffer.position(position); } if (readWaiter == null || totalLength == 0 || !readEnabled) { return; } waiter = readWaiter; } LockSupport.unpark(waiter); } public void setEof() { final Thread waiter; synchronized (this) { eof = true; if (readWaiter == null || !readEnabled) { return; } waiter = readWaiter; } LockSupport.unpark(waiter); } public void enableRead(boolean enable) { final Thread waiter; synchronized (this) { readEnabled = enable; if (readWaiter == null || !readEnabled || !((readBuffer.hasRemaining() && readBuffer.limit() != readBuffer.capacity()) || eof)) { return; } waiter = readWaiter; } LockSupport.unpark(waiter); } public void enableWrite(boolean enable) { final Thread waiter; synchronized (this) { writeEnabled = enable; waiter = writeWaiter; } if (waiter != null) { LockSupport.unpark(waiter); } } public synchronized void enableClosedCheck(boolean enable) { checkClosed = enable; } /** * Returns all the bytes that have been written to this channel mock. * * @return the written bytes in the form of a UTF-8 string */ public String getWrittenText() { if (writeBuffer.position() == 0 && writeBuffer.limit() == writeBuffer.capacity()) { return ""; } writeBuffer.flip(); return Buffers.getModifiedUtf8(writeBuffer); } public ByteBuffer getWrittenBytes() { return writeBuffer; } @Override public void close() throws IOException { closed = true; shutdownWrites(); shutdownReads(); } @Override public boolean isOpen() { return !closed; } private OptionMap optionMap; @Override public boolean supportsOption(Option option) { return optionMap == null? false: optionMap.contains(option); } @Override public T getOption(Option option) throws IOException { return optionMap == null? null: optionMap.get(option); } @Override public T setOption(Option option, T value) throws IllegalArgumentException, IOException { final OptionMap.Builder optionMapBuilder = OptionMap.builder(); T previousValue = null; if (optionMap != null) { optionMapBuilder.addAll(optionMap); previousValue = optionMap.get(option); } optionMapBuilder.set(option, value); optionMap = optionMapBuilder.getMap(); return previousValue; } public void setOptionMap(OptionMap optionMap) { this.optionMap = optionMap; } @Override public OptionMap getOptionMap() { return optionMap; } @Override public void suspendReads() { readAwaken = false; readResumed = false; } @Override public void resumeReads() { readResumed = true; } @Override public boolean isReadResumed() { return readResumed; } @Override public void shutdownReads() throws IOException { readsDown = true; return; } public boolean isShutdownReads() { return readsDown; } /** * This mock supports only one read thread waiting at most. */ @Override public void awaitReadable() throws IOException { synchronized(this) { if (readWaiter != null) { throw new IllegalStateException("ConnectedStreamChannelMock can be used only with one read waiter thread at most... there is already a waiting thread" + readWaiter); } if (((readBuffer.hasRemaining() && readBuffer.capacity() != readBuffer.limit()) || eof) && readEnabled) { return; } readWaiter = Thread.currentThread(); } LockSupport.park(readWaiter); synchronized(this) { readWaiter = null; } } /** * This mock supports only one read thread waiting at most. */ @Override public void awaitReadable(long time, TimeUnit timeUnit) throws IOException { synchronized (this) { if (readWaiter != null) { throw new IllegalStateException("ConnectedStreamChannelMock can be used only with one read waiter thread at most... there is already a waiting thread" + readWaiter); } if (((readBuffer.hasRemaining() && readBuffer.capacity() != readBuffer.limit()) || eof) && readEnabled) { return; } readWaiter = Thread.currentThread(); } // FIXME assertSame("ConnectedStreamChannelMock.awaitReadable(long, TimeUnit) can be used only with TimeUnit.NANOSECONDS", TimeUnit.MILLISECONDS, timeUnit); LockSupport.parkNanos(readWaiter, timeUnit.toNanos(time)); synchronized (this) { readWaiter = null; } } @Override @Deprecated public XnioExecutor getReadThread() { return executor; } @Override public XnioIoThread getIoThread() { return executor; } @Override public void suspendWrites() { writeAwaken = false; writeResumed = false; } @Override public void resumeWrites() { writeResumed = true; } @Override public boolean isWriteResumed() { return writeResumed; } @Override public synchronized void shutdownWrites() throws IOException { if (!allowShutdownWrites) { return; } writesDown = true; final Thread waiter; synchronized (this) { eof = true; if (readWaiter == null) { return; } waiter = readWaiter; } LockSupport.unpark(waiter); return; } public boolean isShutdownWrites() { return writesDown; } @Override public void awaitWritable() throws IOException { synchronized(this) { if (writeWaiter != null) { throw new IllegalStateException("ConnectedStreamChannelMock can be used only with one write waiter thread at most... there is already a waiting thread" + writeWaiter); } if (writeEnabled) { return; } writeWaiter = Thread.currentThread(); } LockSupport.park(writeWaiter); synchronized(this) { writeWaiter = null; } } @Override public void awaitWritable(long time, TimeUnit timeUnit) throws IOException { synchronized (this) { if (writeWaiter != null) { throw new IllegalStateException("ConnectedStreamChannelMock can be used only with one write waiter thread at most... there is already a waiting thread" + writeWaiter); } if (writeEnabled) { return; } writeWaiter = Thread.currentThread(); } // FIXME assertSame("ConnectedStreamChannelMock.awaitWritable(long, TimeUnit) can be used only with TimeUnit.NANOSECONDS", TimeUnit.NANOSECONDS, timeUnit); LockSupport.parkNanos(writeWaiter, timeUnit.toNanos(time)); synchronized (this) { writeWaiter = null; } } @Override @Deprecated public XnioExecutor getWriteThread() { return executor; } @Override public synchronized boolean flush() throws IOException { if (flushEnabled) { flushed = true; } return flushed; } public boolean isFlushed() { return flushed; } public synchronized void enableFlush(boolean enable) { flushEnabled = enable; } @Override public long transferFrom(FileChannel src, long position, long count) throws IOException { if (writeEnabled) { return src.transferTo(position, count, this); } return 0; } @Override public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { if (writeEnabled) { IoUtils.transfer(source, count, throughBuffer, this); } return 0; } @Override public synchronized int write(ByteBuffer src) throws IOException { if (closed && checkClosed) { throw new ClosedChannelException(); } if (writeEnabled) { if (writeBuffer.limit() < writeBuffer.capacity()) { writeBuffer.limit(writeBuffer.capacity()); } int bytes = Buffers.copy(writeBuffer, src); if (bytes > 0) { flushed = false; } return bytes; } return 0; } @Override public synchronized long write(ByteBuffer[] srcs, int offset, int length) throws IOException { if (closed && checkClosed) { throw new ClosedChannelException(); } if (writeEnabled) { if (writeBuffer.limit() < writeBuffer.capacity()) { writeBuffer.limit(writeBuffer.capacity()); } int bytes = Buffers.copy(writeBuffer, srcs, offset, length); if (bytes > 0) { flushed = false; } return bytes; } return 0; } @Override public synchronized long write(ByteBuffer[] srcs) throws IOException { if (closed && checkClosed) { throw new ClosedChannelException(); } if (writeEnabled) { if (writeBuffer.limit() < writeBuffer.capacity()) { writeBuffer.limit(writeBuffer.capacity()); } return Buffers.copy(writeBuffer, srcs, 0, srcs.length); } return 0; } @Override public long transferTo(long position, long count, FileChannel target) throws IOException { if (readEnabled) { return target.transferFrom(this, position, count); } return 0; } @Override public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { if (readEnabled) { return IoUtils.transfer(this, count, throughBuffer, target); } return 0; } @Override public synchronized int read(ByteBuffer dst) throws IOException { if (closed && checkClosed) { throw new ClosedChannelException(); } if (readEnabled) { try { if ((!readBuffer.hasRemaining() || readBuffer.position() == 0 && readBuffer.limit() == readBuffer.capacity()) && eof) { return -1; } if (readBuffer.limit() == readBuffer.capacity() && readBuffer.position() == 0) { return 0; } return Buffers.copy(dst, readBuffer); } catch (RuntimeException e) { System.out.println("Got exception at attempt of copying contents of dst "+ dst.remaining() + " into read buffer " + readBuffer.remaining()); throw e; } } return 0; } @Override public synchronized long read(ByteBuffer[] dsts, int offset, int length) throws IOException { if (closed && checkClosed) { throw new ClosedChannelException(); } if (readEnabled) { if ((!readBuffer.hasRemaining() || readBuffer.position() == 0 && readBuffer.limit() == readBuffer.capacity()) && eof) { return -1; } if (readBuffer.limit() == readBuffer.capacity() && readBuffer.position() == 0) { return 0; } return Buffers.copy(dsts, offset, length, readBuffer); } return 0; } public synchronized boolean allReadDataConsumed() { return readBuffer.position() == readBuffer.limit(); } @Override public synchronized long read(ByteBuffer[] dsts) throws IOException { if (closed && checkClosed) { throw new ClosedChannelException(); } if (readEnabled) { if ((!readBuffer.hasRemaining() || readBuffer.position() == 0 && readBuffer.limit() == readBuffer.capacity()) && eof) { return -1; } if (readBuffer.limit() == readBuffer.capacity() && readBuffer.position() == 0) { return 0; } return Buffers.copy(dsts, 0, dsts.length, readBuffer); } return 0; } private SocketAddress peerAddress; @Override public SocketAddress getPeerAddress() { return peerAddress; } @SuppressWarnings("unchecked") @Override public A getPeerAddress(Class type) { if (type.isAssignableFrom(peerAddress.getClass())) { return (A) peerAddress; } return null; } public void setPeerAddress(SocketAddress peerAddress) { this.peerAddress = peerAddress; } private SocketAddress localAddress; @Override public SocketAddress getLocalAddress() { return localAddress; } @SuppressWarnings("unchecked") @Override public A getLocalAddress(Class type) { if (type.isAssignableFrom(localAddress.getClass())) { return (A) localAddress; } return null; } public void setLocalAddress(SocketAddress localAddress) { this.localAddress = localAddress; } @Override public XnioWorker getWorker() { return worker; } public void setWorker(XnioWorker worker) { this.worker = worker; } @Override public void wakeupReads() { readAwaken = true; readResumed = true; } public boolean isReadAwaken() { return readAwaken; } @Override public void wakeupWrites() { writeAwaken = true; writeResumed = true; } public boolean isWriteAwaken() { return writeAwaken; } @Override public Setter getReadSetter() { return readListenerSetter; } @Override public Setter getWriteSetter() { return writeListenerSetter; } @Override public Setter getCloseSetter() { return closeListenerSetter; } @Override public int writeFinal(ByteBuffer src) throws IOException { return Channels.writeFinalBasic(this, src); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { return Channels.writeFinalBasic(this, srcs, offset, length); } @Override public long writeFinal(ByteBuffer[] srcs) throws IOException { return Channels.writeFinalBasic(this, srcs, 0, srcs.length); } public ChannelListener getReadListener() { return readListener; } public ChannelListener getWriteListener() { return writeListener; } public ChannelListener getCloseListener() { return closeListener; } @Override public String getInfo() { return info; } @Override public void setInfo(String i) { info = i; } } xnio-3.3.2.Final/api/src/test/java/org/xnio/mock/MessageChannelMock.java000066400000000000000000000154551257016060700260310ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.mock; import java.io.IOException; import java.nio.ByteBuffer; import java.util.concurrent.TimeUnit; import org.xnio.Buffers; import org.xnio.ChannelListener; import org.xnio.Option; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.ChannelListener.Setter; import org.xnio.channels.MessageChannel; import org.xnio.channels.ReadableMessageChannel; import org.xnio.channels.WritableMessageChannel; /** * Mock for {@code ReadableMessageChannel} and {@code WritableMessageChannel}. * * @author Flavia Rainone */ public class MessageChannelMock implements ReadableMessageChannel, WritableMessageChannel { private final ConnectedStreamChannelMock channel; private boolean writeResumed = false; private ChannelListener writeListener; private final ChannelListener.Setter writeListenerSetter = new ChannelListener.Setter() { @Override public void set(ChannelListener listener) { writeListener = listener; } }; public MessageChannelMock(ConnectedStreamChannelMock c) { channel = c; } @Override public void suspendReads() { throw new RuntimeException("Not implemented"); } @Override public void resumeReads() { throw new RuntimeException("Not implemented"); } @Override public boolean isReadResumed() { throw new RuntimeException("Not implemented"); } @Override public void wakeupReads() { throw new RuntimeException("Not implemented"); } @Override public void shutdownReads() throws IOException { throw new RuntimeException("Not implemented"); } @Override public void awaitReadable() throws IOException { channel.awaitReadable(); } @Override public void awaitReadable(long time, TimeUnit timeUnit) throws IOException { channel.awaitReadable(time, timeUnit); } @Override public XnioExecutor getReadThread() { throw new RuntimeException("Not implemented"); } @Override public XnioIoThread getIoThread() { throw new RuntimeException("Not implemented"); } @Override public XnioWorker getWorker() { throw new RuntimeException("Not implemented"); } @Override public void close() throws IOException { throw new RuntimeException("Not implemented"); } @Override public boolean isOpen() { throw new RuntimeException("Not implemented"); } @Override public boolean supportsOption(Option option) { throw new RuntimeException("Not implemented"); } @Override public T getOption(Option option) throws IOException { throw new RuntimeException("Not implemented"); } @Override public T setOption(Option option, T value) throws IllegalArgumentException, IOException { throw new RuntimeException("Not implemented"); } @Override public void suspendWrites() { writeResumed = false; } @Override public void resumeWrites() { writeResumed = true; } @Override public boolean isWriteResumed() { return writeResumed; } @Override public void wakeupWrites() { throw new RuntimeException("Not implemented"); } @Override public void shutdownWrites() throws IOException { throw new RuntimeException("Not implemented"); } @Override public void awaitWritable() throws IOException { channel.awaitWritable(); } @Override public void awaitWritable(long time, TimeUnit timeUnit) throws IOException { channel.awaitWritable(time, timeUnit); } @Override public XnioExecutor getWriteThread() { throw new RuntimeException("Not implemented"); } @Override public boolean flush() throws IOException { throw new RuntimeException("Not implemented"); } @Override public boolean send(ByteBuffer buffer) throws IOException { return !buffer.hasRemaining() || channel.write(buffer) > 0; } @Override public boolean send(ByteBuffer[] buffers) throws IOException { return !Buffers.hasRemaining(buffers) || channel.write(buffers) > 0; } @Override public boolean send(ByteBuffer[] buffers, int offs, int len) throws IOException { return !Buffers.hasRemaining(buffers, offs, len) || channel.write(buffers, offs, len) > 0; } @Override public boolean sendFinal(ByteBuffer buffer) throws IOException { if(send(buffer)) { shutdownWrites(); return true; } return false; } @Override public boolean sendFinal(ByteBuffer[] buffers) throws IOException { if(send(buffers)) { shutdownWrites(); return true; } return false; } @Override public boolean sendFinal(ByteBuffer[] buffers, int offs, int len) throws IOException { if(send(buffers, offs, len)) { shutdownWrites(); return true; } return false; } @Override public Setter getWriteSetter() { return writeListenerSetter; } @Override public int receive(ByteBuffer buffer) throws IOException { return channel.read(buffer); } @Override public long receive(ByteBuffer[] buffers) throws IOException { return channel.read(buffers); } @Override public long receive(ByteBuffer[] buffers, int offs, int len) throws IOException { return channel.read(buffers, offs, len); } @Override public Setter getReadSetter() { throw new RuntimeException("Not implemented"); } @Override public Setter getCloseSetter() { throw new RuntimeException("Not implemented"); } public ChannelListener getWriteListener() { return writeListener; } } xnio-3.3.2.Final/api/src/test/java/org/xnio/mock/MessageConnectionMock.java000066400000000000000000000072511257016060700265530ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.mock; import java.io.IOException; import java.net.SocketAddress; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.integration.junit4.JUnit4Mockery; import org.xnio.MessageConnection; import org.xnio.Option; import org.xnio.OptionMap; import org.xnio.XnioIoThread; import org.xnio.conduits.MessageSinkConduit; import org.xnio.conduits.MessageSourceConduit; import org.xnio.conduits.ReadReadyHandler; import org.xnio.conduits.WriteReadyHandler; /** * {@link MessageConnection} mock. * * @author Flavia Rainone * */ public class MessageConnectionMock extends MessageConnection implements Mock { // the peer address private final SocketAddress peerAddress; // the local address private final SocketAddress localAddress; // the option map private final OptionMap optionMap; // info used to check correct delegation from API to mocks private String info; protected MessageConnectionMock(final XnioIoThread thread, SocketAddress localAddress, SocketAddress peerAddress, OptionMap optionMap) { super(thread); this.localAddress = localAddress; this.peerAddress = peerAddress; this.optionMap = optionMap; final Mockery context = new JUnit4Mockery(); final MessageSourceConduit sourceConduit = context.mock(MessageSourceConduit.class, "source conduit"); final MessageSinkConduit sinkConduit = context.mock(MessageSinkConduit.class, "sink conduit"); context.checking(new Expectations() {{ allowing(sourceConduit).getReadThread(); will(returnValue(thread)); allowing(sourceConduit).setReadReadyHandler(with(any(ReadReadyHandler.class))); allowing(sourceConduit).getWorker(); will(returnValue(thread.getWorker())); allowing(sinkConduit).getWriteThread(); will(returnValue(thread)); allowing(sinkConduit).setWriteReadyHandler(with(any(WriteReadyHandler.class))); allowing(sinkConduit).getWorker(); will(returnValue(thread.getWorker())); }}); setSourceConduit(sourceConduit); setSinkConduit(sinkConduit); } @Override public SocketAddress getPeerAddress() { return peerAddress; } @Override public SocketAddress getLocalAddress() { return localAddress; } @Override protected void notifyWriteClosed() { throw new UnsupportedOperationException("operation not implemented by mock"); } @Override protected void notifyReadClosed() { throw new UnsupportedOperationException("operation not implemented by mock"); } @Override public void setInfo(String info) { this.info = info; } @Override public String getInfo() { return info; } @Override public OptionMap getOptionMap() { return optionMap; } @Override public T getOption(Option option) throws IOException { return optionMap.get(option); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/mock/Mock.java000066400000000000000000000017301257016060700232220ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.mock; import org.xnio.OptionMap; /** * A Mock can contain extra info useful to the tests. * * @author Flavia Rainone * */ public interface Mock { public void setInfo(String info); public String getInfo(); public OptionMap getOptionMap(); } xnio-3.3.2.Final/api/src/test/java/org/xnio/mock/MulticastMessageChannelMock.java000066400000000000000000000220611257016060700277060ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.mock; import java.io.IOException; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.NetworkInterface; import java.net.SocketAddress; import java.nio.ByteBuffer; import java.util.concurrent.TimeUnit; import org.xnio.ChannelListener.Setter; import org.xnio.Option; import org.xnio.OptionMap; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.MulticastMessageChannel; import org.xnio.channels.SocketAddressBuffer; /** * Mock for {@link MulticastMessageChannel}. * * @author Flavia Rainone * */ public class MulticastMessageChannelMock implements MulticastMessageChannel, Mock { private final InetSocketAddress bindAddress; private final OptionMap optionMap; private String info = null; // any extra information regarding this channel used by tests public MulticastMessageChannelMock(InetSocketAddress bindAddress, OptionMap optionMap) { this.bindAddress = bindAddress; this.optionMap = optionMap; } @Override public int receiveFrom(SocketAddressBuffer addressBuffer, ByteBuffer buffer) throws IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public long receiveFrom(SocketAddressBuffer addressBuffer, ByteBuffer[] buffers) throws IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public long receiveFrom(SocketAddressBuffer addressBuffer, ByteBuffer[] buffers, int offs, int len) throws IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public void suspendReads() { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public void resumeReads() { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public boolean isReadResumed() { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public void wakeupReads() { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public void shutdownReads() throws IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public void awaitReadable() throws IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public void awaitReadable(long time, TimeUnit timeUnit) throws IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public XnioExecutor getReadThread() { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public XnioIoThread getIoThread() { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public XnioWorker getWorker() { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public void close() throws IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public boolean isOpen() { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public boolean supportsOption(Option option) { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public T getOption(Option option) throws IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public T setOption(Option option, T value) throws IllegalArgumentException, IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public boolean sendTo(SocketAddress target, ByteBuffer buffer) throws IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public boolean sendTo(SocketAddress target, ByteBuffer[] buffers) throws IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public boolean sendTo(SocketAddress target, ByteBuffer[] buffers, int offset, int length) throws IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public void suspendWrites() { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public void resumeWrites() { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public boolean isWriteResumed() { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public void wakeupWrites() { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public void shutdownWrites() throws IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public void awaitWritable() throws IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public void awaitWritable(long time, TimeUnit timeUnit) throws IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public XnioExecutor getWriteThread() { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public boolean flush() throws IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public SocketAddress getLocalAddress() { return bindAddress; } @SuppressWarnings("unchecked") @Override public A getLocalAddress(Class type) { if (type.getClass().isAssignableFrom(InetSocketAddress.class)) { return (A) bindAddress; } return null; } @Override public Key join(InetAddress group, NetworkInterface iface) throws IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public Key join(InetAddress group, NetworkInterface iface, InetAddress source) throws IOException { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public Setter getReadSetter() { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public Setter getCloseSetter() { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public Setter getWriteSetter() { throw new UnsupportedOperationException("MulticastMessageChannelMock does not support this operation"); } @Override public OptionMap getOptionMap() { return optionMap; } @Override public String getInfo() { return info; } @Override public void setInfo(String i) { info = i; } } xnio-3.3.2.Final/api/src/test/java/org/xnio/mock/StreamConnectionMock.java000066400000000000000000000100431257016060700264130ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.mock; import java.io.IOException; import java.net.SocketAddress; import org.xnio.Option; import org.xnio.OptionMap; import org.xnio.StreamConnection; /** * {@link StreamConnection} mock. * * @author Flavia Rainone * */ public class StreamConnectionMock extends StreamConnection implements Mock { // the option map private OptionMap optionMap; // the peer address private SocketAddress peerAddress; // the local address private SocketAddress localAddress; // the server responsible for accepting this connection private AcceptingChannelMock server; // any extra information regarding this channel used by tests, usually used to check for correct delegation between api and impl private String info = null; public StreamConnectionMock(ConduitMock conduit) { super(conduit.getXnioIoThread()); setSourceConduit(conduit); setSinkConduit(conduit); } /** * Sets the accepting server that created this connection. */ void setServer(AcceptingChannelMock server) { this.server = server; } /** * Returns the accepting server that created this connection. */ public AcceptingChannelMock getServer() { return server; } @Override public SocketAddress getPeerAddress() { return peerAddress; } /** * Sets the peer address. */ public void setPeerAddress(SocketAddress peerAddress) { this.peerAddress = peerAddress; } @Override public SocketAddress getLocalAddress() { return localAddress; } /** * Sets the local address. */ public void setLocalAddress(SocketAddress localAddress) { this.localAddress = localAddress; } @Override public boolean supportsOption(Option option) { return optionMap == null? false: optionMap.contains(option); } @Override public T getOption(Option option) throws IOException { return optionMap == null? null: optionMap.get(option); } @Override public T setOption(Option option, T value) throws IllegalArgumentException, IOException { final OptionMap.Builder optionMapBuilder = OptionMap.builder(); T previousValue = null; if (optionMap != null) { optionMapBuilder.addAll(optionMap); previousValue = optionMap.get(option); } optionMapBuilder.set(option, value); optionMap = optionMapBuilder.getMap(); return previousValue; } /** * Sets the option map. */ public void setOptionMap(OptionMap optionMap) { this.optionMap = optionMap; } @Override public OptionMap getOptionMap() { return optionMap; } @Override protected void notifyWriteClosed() { // just for test verification purposes try { this.getSourceChannel().close(); } catch (IOException e) { e.printStackTrace(); } } @Override protected void notifyReadClosed() { // just for test verification purposes try { this.getSinkChannel().close(); } catch (IOException e) { e.printStackTrace(); } } @Override public void setInfo(String info) { this.info = info; } @Override public String getInfo() { return info; } }xnio-3.3.2.Final/api/src/test/java/org/xnio/mock/XnioIoThreadMock.java000066400000000000000000000242041257016060700255010ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.mock; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.concurrent.TimeUnit; import org.xnio.AbstractIoFuture; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.ChannelPipe; import org.xnio.FailedIoFuture; import org.xnio.FinishedIoFuture; import org.xnio.IoFuture; import org.xnio.LocalSocketAddress; import org.xnio.MessageConnection; import org.xnio.OptionMap; import org.xnio.StreamConnection; import org.xnio.XnioExecutor; import org.xnio.XnioIoFactory; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.BoundChannel; import org.xnio.channels.StreamChannel; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; /** * {@link XnioExecutor} mock. * * @author Flavia Rainone * */ public class XnioIoThreadMock extends XnioIoThread implements XnioExecutor { public XnioIoThreadMock(final XnioWorker worker) { super(worker, 0); } @Override public void execute(Runnable command) { command.run(); } @Override public Key executeAfter(Runnable command, long time, TimeUnit unit) { throw new RuntimeException("Not implemented"); } @Override public Key executeAtInterval(final Runnable command, final long time, final TimeUnit unit) { throw new RuntimeException("Not implemented"); } @Override protected IoFuture acceptLocalStreamConnection(LocalSocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { return internalAcceptStream(destination, openListener, bindListener, optionMap, XnioWorkerMock.LOCAL_CHANNEL_INFO); } @Override protected IoFuture acceptTcpStreamConnection(InetSocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { return internalAcceptStream(destination, openListener, bindListener, optionMap, XnioWorkerMock.TCP_CHANNEL_INFO); } private IoFuture internalAcceptStream(SocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap, String channelInfo) { switch(getWorkerMock().getConnectBehavior()) { case SUCCEED: { final ConduitMock conduit = new ConduitMock(getWorker(), this); final StreamConnectionMock connection = new StreamConnectionMock(conduit); connection.setPeerAddress(destination); ChannelListeners.invokeChannelListener(connection, bindListener); connection.setOptionMap(optionMap); connection.setInfo(channelInfo); ChannelListeners.invokeChannelListener(connection, openListener); return new FinishedIoFuture(connection); } case FAIL: return new FailedIoFuture(new IOException("dummy exception")); case CANCEL: return new AbstractIoFuture() { { setCancelled(); } }; default: throw new IllegalStateException("Unexpected ConnectBehavior"); } } protected IoFuture internalOpenStreamConnection(final SocketAddress bindAddress, final SocketAddress destinationAddress, final ChannelListener openListener, final ChannelListener bindListener, final OptionMap optionMap, final String channelInfo) { switch(getWorkerMock().getConnectBehavior()) { case SUCCEED: { final ConduitMock conduit = new ConduitMock(getWorker(), this); final StreamConnectionMock connection = new StreamConnectionMock(conduit); connection.setLocalAddress(bindAddress); connection.setPeerAddress(destinationAddress); ChannelListeners.invokeChannelListener(connection, bindListener); connection.setOptionMap(optionMap); connection.setInfo(channelInfo); ChannelListeners.invokeChannelListener(connection, openListener); return new FinishedIoFuture(connection); } case FAIL: return new FailedIoFuture(new IOException("dummy exception")); case CANCEL: return new AbstractIoFuture() { { setCancelled(); } }; default: throw new IllegalStateException("Unexpected ConnectBehavior"); } } @Override protected IoFuture openTcpStreamConnection(InetSocketAddress bindAddress, InetSocketAddress destinationAddress, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { return internalConnectStream(bindAddress, destinationAddress, openListener, bindListener, optionMap, XnioWorkerMock.TCP_CHANNEL_INFO); } @Override protected IoFuture openLocalStreamConnection(LocalSocketAddress bindAddress, LocalSocketAddress destinationAddress, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { return internalConnectStream(bindAddress, destinationAddress, openListener, bindListener, optionMap, XnioWorkerMock.LOCAL_CHANNEL_INFO); } protected IoFuture internalConnectStream(final SocketAddress bindAddress, final SocketAddress destinationAddress, final ChannelListener openListener, final ChannelListener bindListener, final OptionMap optionMap, final String channelInfo) { switch(getWorkerMock().getConnectBehavior()) { case SUCCEED: { ConduitMock conduit = new ConduitMock(getWorkerMock(), this); StreamConnectionMock connection = new StreamConnectionMock(conduit); connection.setLocalAddress(bindAddress); connection.setPeerAddress(destinationAddress); ChannelListeners.invokeChannelListener(connection, bindListener); conduit.setWorker(getWorker()); connection.setOptionMap(optionMap); connection.setInfo(channelInfo); ChannelListeners.invokeChannelListener(connection, openListener); return new FinishedIoFuture(connection); } case FAIL: return new FailedIoFuture(new IOException("dummy exception")); case CANCEL: return new AbstractIoFuture() { { setCancelled(); } }; default: throw new IllegalStateException("Unexpected ConnectBehavior"); } } @Override protected IoFuture openLocalMessageConnection(LocalSocketAddress bindAddress, LocalSocketAddress destinationAddress, ChannelListener openListener, OptionMap optionMap) { switch(getWorkerMock().getConnectBehavior()) { case SUCCEED: { MessageConnectionMock messageConnection = new MessageConnectionMock(this, bindAddress, destinationAddress, optionMap); messageConnection.setInfo(XnioWorkerMock.LOCAL_CHANNEL_INFO); ChannelListeners.invokeChannelListener(messageConnection, openListener); return new FinishedIoFuture(messageConnection); } case FAIL: return new FailedIoFuture(new IOException("dummy exception")); case CANCEL: return new AbstractIoFuture() { { setCancelled(); } }; default: throw new IllegalStateException("Unexpected ConnectBehavior"); } } protected IoFuture acceptLocalMessageConnection(LocalSocketAddress destination, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { return openLocalMessageConnection(null, destination, openListener, optionMap); } @Override public ChannelPipe createFullDuplexPipe() throws IOException { throw new RuntimeException("method not implemented by mock"); } @Override public ChannelPipe createFullDuplexPipeConnection(final XnioIoFactory peer) throws IOException { throw new RuntimeException("method not implemented by mock"); } @Override public ChannelPipe createHalfDuplexPipe(final XnioIoFactory peer) throws IOException { throw new RuntimeException("method not implemented by mock"); } private XnioWorkerMock getWorkerMock() { return (XnioWorkerMock) super.getWorker(); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/mock/XnioMock.java000066400000000000000000000033171257016060700240630ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.mock; import java.io.IOException; import org.xnio.FileSystemWatcher; import org.xnio.OptionMap; import org.xnio.Xnio; import org.xnio.XnioProvider; import org.xnio.XnioWorker; /** * {@link Xnio} mock. * * @author Flavia Rainone */ public class XnioMock extends Xnio { private static final XnioMock INSTANCE = new XnioMock("xnio-mock"); protected XnioMock(String name) { super(name); } @Override public XnioWorker createWorker(ThreadGroup threadGroup, OptionMap optionMap, Runnable terminationTask) throws IOException, IllegalArgumentException { return new XnioWorkerMock(this, threadGroup, optionMap, terminationTask); } public static class Provider implements XnioProvider { @Override public Xnio getInstance() { return INSTANCE; } @Override public String getName() { return INSTANCE.getName(); } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/mock/XnioWorkerMock.java000066400000000000000000000142171257016060700252560ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.mock; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.List; import java.util.concurrent.TimeUnit; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.LocalSocketAddress; import org.xnio.OptionMap; import org.xnio.StreamConnection; import org.xnio.Xnio; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.MulticastMessageChannel; /** * {@link XnioWorker} mock. * * @author Flavia Rainone */ public class XnioWorkerMock extends XnioWorker { /** * Extra info set on created channel mocks if the channel mock was created as a tcp channel. * @see Mock#getInfo() */ public static final String TCP_CHANNEL_INFO = "tcp"; /** * Extra info set on created channel mocks if the channel mock was created as a udp channel. * @see Mock#getInfo() */ public static final String UDP_CHANNEL_INFO = "udp"; /** * Extra info set on created channel mocks if the channel mock was created as a local channel. * @see Mock#getInfo() */ public static final String LOCAL_CHANNEL_INFO = "local"; /** * The thread mock. */ private final XnioIoThreadMock mockThread = new XnioIoThreadMock(this); // indicates which action should be taken if a request to connect is performed enum ConnectBehavior {SUCCEED, FAIL, CANCEL} // by default, every request to connectil will succeed private ConnectBehavior connectBehavior = ConnectBehavior.SUCCEED; // has this worker been shut down private boolean shutdown; protected XnioWorkerMock() { this(Xnio.getInstance(), null, OptionMap.EMPTY, null); } protected XnioWorkerMock(ThreadGroup threadGroup, OptionMap optionMap, Runnable terminationTask) { super(Xnio.getInstance(), threadGroup, optionMap, terminationTask); } protected XnioWorkerMock(Xnio xnio, ThreadGroup threadGroup, OptionMap optionMap, Runnable terminationTask) { super(xnio, threadGroup, optionMap, terminationTask); } @Override public int getIoThreadCount() { return 0; } @Override protected XnioIoThread chooseThread() { return mockThread; } /** * Returns the connect behavior of this worker mock. */ ConnectBehavior getConnectBehavior() { return this.connectBehavior; } /** * Sets this worker mock to fail every request to connect. Used for emulating failure to connect behavior. */ public void failConnection() { connectBehavior = ConnectBehavior.FAIL; } /** * Sets this worker mock to behave as if every request to connect has been cancelled by a third party, whenever * applicable. Used for emulating cancellation of connection futures. */ public void cancelConnection() { connectBehavior = ConnectBehavior.CANCEL; } @SuppressWarnings({ "rawtypes", "unchecked" }) private AcceptingChannel internalCreateStreamServer(SocketAddress bindAddress, ChannelListener> acceptListener, OptionMap optionMap, String channelInfo) throws IOException { AcceptingChannelMock channel = new AcceptingChannelMock(); channel.setLocalAddress(bindAddress); channel.setOptionMap(optionMap); channel.setWorker(this); channel.setInfo(channelInfo); if (connectBehavior == ConnectBehavior.FAIL) channel.enableAcceptance(false); ((AcceptingChannel)channel).getAcceptSetter().set(acceptListener); return channel; } @Override protected AcceptingChannel createTcpConnectionServer(InetSocketAddress bindAddress, ChannelListener> acceptListener, OptionMap optionMap) throws IOException { return internalCreateStreamServer(bindAddress, acceptListener, optionMap, TCP_CHANNEL_INFO); } @Override protected AcceptingChannel createLocalStreamConnectionServer(LocalSocketAddress bindAddress, ChannelListener> acceptListener, OptionMap optionMap) throws IOException { return internalCreateStreamServer(bindAddress, acceptListener, optionMap, LOCAL_CHANNEL_INFO); } @Override public MulticastMessageChannel createUdpServer(InetSocketAddress bindAddress, ChannelListener bindListener, OptionMap optionMap) throws IOException { MulticastMessageChannel channel = new MulticastMessageChannelMock(bindAddress, optionMap); ChannelListeners.invokeChannelListener(channel, bindListener); return channel; } @Override public void shutdown() { shutdown = true; } @Override public List shutdownNow() { throw new RuntimeException("not implemented"); } @Override public boolean isShutdown() { throw new RuntimeException("not implemented"); } @Override public boolean isTerminated() { throw new RuntimeException("not implemented"); } @Override public boolean awaitTermination(long timeout, TimeUnit unit) throws InterruptedException { if (shutdown) { return true; } return false; } @Override public void awaitTermination() throws InterruptedException { } } xnio-3.3.2.Final/api/src/test/java/org/xnio/racecondition/000077500000000000000000000000001257016060700233555ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/org/xnio/racecondition/CloseReadingSslChannelTestCase.java000066400000000000000000000067321257016060700321760ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.racecondition; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import org.jboss.byteman.contrib.bmunit.BMScript; import org.jboss.byteman.contrib.bmunit.BMUnitRunner; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.xnio.channels.ConnectedSslStreamChannel; import org.xnio.ssl.AbstractConnectedSslStreamChannelTest; import org.xnio.ssl.mock.SSLEngineMock.HandshakeAction; /** * Close an JsseConnectedSslStreamChannel that is executing a read request. * The close action takes place at the exact moment the channel is attempting to wrap to handle handshake. * * @author Flavia Rainone */ @Ignore @RunWith(BMUnitRunner.class) @BMScript(dir="src/test/resources") public class CloseReadingSslChannelTestCase extends AbstractConnectedSslStreamChannelTest { @Test public void test() throws InterruptedException { conduitMock.setReadData("read data"); conduitMock.enableReads(true); engineMock.setHandshakeActions(HandshakeAction.NEED_WRAP, HandshakeAction.FINISH); ReadFromChannel readRunnable = new ReadFromChannel(sslChannel); Thread readThread = new Thread(readRunnable); Thread closeThread = new Thread(new CloseChannel(sslChannel)); readThread.start(); closeThread.start(); readThread.join(); closeThread.join(); assertTrue(readRunnable.hasFailed()); } private static class ReadFromChannel implements Runnable { private final ConnectedSslStreamChannel channel; private boolean failed = false; public ReadFromChannel(ConnectedSslStreamChannel channel) { this.channel = channel; } @Override public void run() { try { assertEquals(9, channel.read(ByteBuffer.allocate(10))); } catch (ClosedChannelException e) { failed = true; } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } public boolean hasFailed() { return failed; } } private static class CloseChannel implements Runnable { private final ConnectedSslStreamChannel channel; public CloseChannel(ConnectedSslStreamChannel channel) { this.channel = channel; } @Override public void run() { try { channel.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/racecondition/CloseWritingSslChannelTestCase.java000066400000000000000000000101421257016060700322360ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.racecondition; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import org.jboss.byteman.contrib.bmunit.BMScript; import org.jboss.byteman.contrib.bmunit.BMUnitRunner; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.xnio.channels.ConnectedSslStreamChannel; import org.xnio.ssl.AbstractConnectedSslStreamChannelTest; import org.xnio.ssl.mock.SSLEngineMock; import org.xnio.ssl.mock.SSLEngineMock.HandshakeAction; /** * Close an JsseConnectedSslStreamChannel that is executing a write request. * The close action takes place at the exact moment the channel is attempting to unwrap to handle handshake. * * @author Flavia Rainone */ @Ignore @RunWith(BMUnitRunner.class) @BMScript(dir="src/test/resources") public class CloseWritingSslChannelTestCase extends AbstractConnectedSslStreamChannelTest { @Test public void testConnectedChannelAndEngineClosed() throws InterruptedException { test(); } @Test public void testWithEngineClosedOnly() throws InterruptedException { conduitMock.enableClosedCheck(false); test(); } public void test() throws InterruptedException { conduitMock.setReadData(SSLEngineMock.HANDSHAKE_MSG); conduitMock.enableReads(true); engineMock.setHandshakeActions(HandshakeAction.NEED_UNWRAP, HandshakeAction.FINISH); WriteToChannel writeRunnable = new WriteToChannel(sslChannel); Thread readThread = new Thread(writeRunnable); Thread closeThread = new Thread(new CloseChannel(sslChannel)); readThread.start(); closeThread.start(); readThread.join(); closeThread.join(); assertTrue(writeRunnable.hasFailed()); } private static class WriteToChannel implements Runnable { private final ConnectedSslStreamChannel channel; private boolean failed = false; public WriteToChannel(ConnectedSslStreamChannel channel) { this.channel = channel; } @Override public void run() { ByteBuffer buffer = ByteBuffer.allocate(10); try { buffer.put("write data".getBytes("UTF-8")).flip(); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } try { assertEquals(10, channel.write(buffer)); } catch (ClosedChannelException e) { e.printStackTrace(); failed = true; } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } public boolean hasFailed() { return failed; } } private static class CloseChannel implements Runnable { private final ConnectedSslStreamChannel channel; public CloseChannel(ConnectedSslStreamChannel channel) { this.channel = channel; } @Override public void run() { try { channel.close(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } } } ResumeReadsOnHandlingReadableChannelTestCase.java000066400000000000000000000123331257016060700346710ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/org/xnio/racecondition/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.racecondition; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.jboss.byteman.contrib.bmunit.BMScript; import org.jboss.byteman.contrib.bmunit.BMUnitRunner; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.integration.junit4.JUnit4Mockery; import org.junit.Test; import org.junit.runner.RunWith; import org.xnio.ChannelListener; import org.xnio.channels.SuspendableChannel; import org.xnio.channels.TranslatingSuspendableChannel; import org.xnio.mock.ConnectedStreamChannelMock; /** * Resume reads on a channel that is handling readable. Check if the effects of resuming reads are * not mistakenly covered by handleReadable. * * @author Flavia Rainone */ @RunWith(BMUnitRunner.class) @BMScript(dir="src/test/resources") public class ResumeReadsOnHandlingReadableChannelTestCase { @Test public void test() throws Exception { // create mockery context final Mockery context = new JUnit4Mockery(); // creating channel and threads ConnectedStreamChannelMock connectedChannelMock = new ConnectedStreamChannelMock(); final MyTranslatingSuspendableChannel channel = new MyTranslatingSuspendableChannel(connectedChannelMock); final Thread resumeReadsThread = new Thread(new ResumeReads(channel)); final Thread handleReadableThread = new Thread(new InvokeHandleReadable(channel)); // set up scenario @SuppressWarnings("unchecked") final ChannelListener listener = context.mock(ChannelListener.class, "listener1"); context.checking(new Expectations() {{ allowing(listener).handleEvent(channel); }}); channel.getReadSetter().set(listener); channel.suspendReads(); channel.handleReadable(); assertFalse(connectedChannelMock.isReadResumed()); // first, try to invoke handleReadable and then resumeReads System.out.println("Attempt 1: invoke handleReadable before resumeReads"); channel.handleReadable(); channel.resumeReads(); assertTrue(channel.isReadResumed()); assertTrue(connectedChannelMock.isReadResumed()); // clear everything channel.suspendReads(); channel.handleReadable(); assertFalse(channel.isReadResumed()); assertFalse(connectedChannelMock.isReadResumed()); // now, try the opposite, invoke handleReadable after resumeReads() System.out.println("Attempt 2: invoke handleReadable after resumeReads"); channel.resumeReads(); channel.handleReadable(); assertTrue(channel.isReadResumed()); assertTrue(connectedChannelMock.isReadResumed()); // clear everything once more channel.suspendReads(); channel.handleReadable(); assertFalse(channel.isReadResumed()); assertFalse(connectedChannelMock.isReadResumed()); System.out.println("Attempt 3: race condition scenario involving handleReadable and resumeReads"); // finally, create the race condition scenario... handleReadable and resumeReads occur // practically at the same time (see ResumeReadsOnHandlingReadableChannelTestCase.btm) resumeReadsThread.start(); handleReadableThread.start(); // joining threads resumeReadsThread.join(); handleReadableThread.join(); assertTrue(channel.isReadResumed()); assertTrue(connectedChannelMock.isReadResumed()); } private static class ResumeReads implements Runnable { private MyTranslatingSuspendableChannel channel; public ResumeReads(MyTranslatingSuspendableChannel channel) { this.channel = channel; } @Override public void run() { channel.resumeReads(); } } private static class InvokeHandleReadable implements Runnable { private MyTranslatingSuspendableChannel channel; public InvokeHandleReadable(MyTranslatingSuspendableChannel channel) { this.channel = channel; } @Override public void run() { channel.handleReadable(); } } private static class MyTranslatingSuspendableChannel extends TranslatingSuspendableChannel { protected MyTranslatingSuspendableChannel(SuspendableChannel c) { super(c); } public void handleReadable() { super.handleReadable(); } } } ResumeWritesOnHandlingWritableChannelTestCase.java000066400000000000000000000123751257016060700351700ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/org/xnio/racecondition/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.racecondition; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import org.jboss.byteman.contrib.bmunit.BMScript; import org.jboss.byteman.contrib.bmunit.BMUnitRunner; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.integration.junit4.JUnit4Mockery; import org.junit.Test; import org.junit.runner.RunWith; import org.xnio.ChannelListener; import org.xnio.channels.SuspendableChannel; import org.xnio.channels.TranslatingSuspendableChannel; import org.xnio.mock.ConnectedStreamChannelMock; /** * Resume writes on a channel that is handling writable. Check if the effects of resuming writes are * not mistakenly covered by handleWritable. * * @author Flavia Rainone */ @RunWith(BMUnitRunner.class) @BMScript(dir="src/test/resources") public class ResumeWritesOnHandlingWritableChannelTestCase { @Test public void test() throws Exception { // create mockery context final Mockery context = new JUnit4Mockery(); // creating channel and threads ConnectedStreamChannelMock connectedChannelMock = new ConnectedStreamChannelMock(); final MyTranslatingSuspendableChannel channel = new MyTranslatingSuspendableChannel(connectedChannelMock); final Thread resumeWritesThread = new Thread(new ResumeWrites(channel)); final Thread handleWritableThread = new Thread(new InvokeHandleWritable(channel)); // set up scenario @SuppressWarnings("unchecked") final ChannelListener listener = context.mock(ChannelListener.class, "listener1"); context.checking(new Expectations() {{ allowing(listener).handleEvent(channel); }}); channel.getWriteSetter().set(listener); channel.suspendWrites(); channel.handleWritable(); assertFalse(connectedChannelMock.isWriteResumed()); // first, try to invoke handleWritable and then resumeWrites System.out.println("Attempt 1: invoke handleWritable before resumeWrites"); channel.handleWritable(); channel.resumeWrites(); assertTrue(channel.isWriteResumed()); assertTrue(connectedChannelMock.isWriteResumed()); // clear everything channel.suspendWrites(); channel.handleWritable(); assertFalse(channel.isWriteResumed()); assertFalse(connectedChannelMock.isWriteResumed()); // now, try the opposite, invoke handleWritable after resumeWrites() System.out.println("Attempt 2: invoke handleWritable after resumeWrites"); channel.resumeWrites(); channel.handleWritable(); assertTrue(channel.isWriteResumed()); assertTrue(connectedChannelMock.isWriteResumed()); // clear everything once more channel.suspendWrites(); channel.handleWritable(); assertFalse(channel.isWriteResumed()); assertFalse(connectedChannelMock.isWriteResumed()); System.out.println("Attempt 3: race condition scenario involving handleWritable and resumeWrites"); // finally, create the race condition scenario... handleWritable and resumeWrites occur // practically at the same time (see ReusmeWritesOnHandlingWritableChannelTestCase.btm) resumeWritesThread.start(); handleWritableThread.start(); // joining threads resumeWritesThread.join(); handleWritableThread.join(); assertTrue(channel.isWriteResumed()); assertTrue(connectedChannelMock.isWriteResumed()); } private static class ResumeWrites implements Runnable { private MyTranslatingSuspendableChannel channel; public ResumeWrites(MyTranslatingSuspendableChannel channel) { this.channel = channel; } @Override public void run() { channel.resumeWrites(); } } private static class InvokeHandleWritable implements Runnable { private MyTranslatingSuspendableChannel channel; public InvokeHandleWritable(MyTranslatingSuspendableChannel channel) { this.channel = channel; } @Override public void run() { channel.handleWritable(); } } private static class MyTranslatingSuspendableChannel extends TranslatingSuspendableChannel { protected MyTranslatingSuspendableChannel(SuspendableChannel c) { super(c); } public void handleWritable() { super.handleWritable(); } } } SetReadListenerOnHandlingReadableChannelTestCase.java000066400000000000000000000163741257016060700355200ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/org/xnio/racecondition/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.racecondition; import java.io.IOException; import java.util.concurrent.TimeUnit; import org.jboss.byteman.contrib.bmunit.BMScript; import org.jboss.byteman.contrib.bmunit.BMUnitRunner; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.integration.junit4.JUnit4Mockery; import org.jmock.lib.concurrent.Synchroniser; import org.junit.Test; import org.junit.runner.RunWith; import org.xnio.ChannelListener; import org.xnio.Option; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.SuspendableChannel; import org.xnio.channels.TranslatingSuspendableChannel; /** * Change read listener on channel that is handling readable. Check if the channel realizes the listener has * changed. * * @author Flavia Rainone */ @RunWith(BMUnitRunner.class) @BMScript(dir="src/test/resources") public class SetReadListenerOnHandlingReadableChannelTestCase { @Test public void test() throws Exception { // create mockery context final Mockery context = new JUnit4Mockery() {{ setThreadingPolicy(new Synchroniser()); }}; // creating channel and threads final MyTranslatingSuspendableChannel channel = new MyTranslatingSuspendableChannel(); final Thread setReadListenerThread = new Thread(new SetReadListener(channel, context)); final Thread handleReadableThread = new Thread(new InvokeHandleReadable(channel)); // set up scenario System.out.println("Setting scenario with listener1 and reads suspended"); @SuppressWarnings("unchecked") final ChannelListener listener = context.mock(ChannelListener.class, "listener1"); context.checking(new Expectations() {{ oneOf(listener).handleEvent(channel); }}); channel.getReadSetter().set(listener); channel.resumeReads(); // starting threads setReadListenerThread.start(); handleReadableThread.start(); // joining threads setReadListenerThread.join(); handleReadableThread.join(); // was "listener that must not be called" never called? And what about listener created by setReadListener thread? Was it called exactly once? context.assertIsSatisfied(); } private static class SetReadListener implements Runnable { private MyTranslatingSuspendableChannel channel; private Mockery context; public SetReadListener(MyTranslatingSuspendableChannel channel, Mockery context) { this.channel = channel; this.context = context; } @Override @SuppressWarnings("unchecked") public void run() { // after handleReadable#1 channel.suspendReads(); // after handleReadable#2 final ChannelListener listener = context.mock(ChannelListener.class, "listener2"); context.checking(new Expectations() {{ oneOf(listener).handleEvent(channel); }}); // on the third attempt to call handle readable, this is the scenario the channel should see System.out.println("Setting listener2 and resuming reads"); channel.getReadSetter().set(listener); // after handleReadable#3 channel.resumeReads(); } } private static class InvokeHandleReadable implements Runnable { private MyTranslatingSuspendableChannel channel; public InvokeHandleReadable(MyTranslatingSuspendableChannel channel) { this.channel = channel; } @Override public void run() { System.out.println("Attempt to handle readable number 1"); channel.handleReadable(); System.out.println("Attempt to handle readable number 2"); channel.handleReadable(); System.out.println("Attempt to handle readable number 3"); channel.handleReadable(); System.out.println("Attempt to handle readable number 4"); channel.handleReadable(); } } private static class MyTranslatingSuspendableChannel extends TranslatingSuspendableChannel { protected MyTranslatingSuspendableChannel() { super(new SuspendableChannel() { public XnioWorker getWorker() { return null; } public void close() throws IOException { } public boolean isOpen() { return false; } public boolean supportsOption(Option option) { return false; } public T getOption(Option option) throws IOException { return null; } public T setOption(Option option, T value) throws IllegalArgumentException, IOException { return null; } public void suspendReads() {} public void resumeReads() {} public boolean isReadResumed() { return false; } public void wakeupReads() {} public void shutdownReads() throws IOException {} public void awaitReadable() throws IOException {} public void awaitReadable(long time, TimeUnit timeUnit) throws IOException {} public XnioExecutor getReadThread() { return null; } public void suspendWrites() {} public void resumeWrites() {} public boolean isWriteResumed() {return false;} public void wakeupWrites() {} public void shutdownWrites() throws IOException {} public void awaitWritable() throws IOException {} public void awaitWritable(long time, TimeUnit timeUnit) throws IOException {} public XnioExecutor getWriteThread() { return null; } public boolean flush() throws IOException { return true; } public XnioIoThread getIoThread() { return null; } public ChannelListener.Setter getCloseSetter() {return new ChannelListener.SimpleSetter();} public ChannelListener.Setter getReadSetter() {return new ChannelListener.SimpleSetter();} public ChannelListener.Setter getWriteSetter() {return new ChannelListener.SimpleSetter();} }); } public void handleReadable() { super.handleReadable(); } } } SetReadReadyOnHandlingReadableChannelTestCase.java000066400000000000000000000143151257016060700347700ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/org/xnio/racecondition/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.racecondition; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.lang.reflect.Field; import org.jboss.byteman.contrib.bmunit.BMScript; import org.jboss.byteman.contrib.bmunit.BMUnitRunner; import org.junit.Test; import org.junit.runner.RunWith; import org.xnio.Bits; import org.xnio.ChannelListener; import org.xnio.channels.SuspendableChannel; import org.xnio.channels.TranslatingSuspendableChannel; import org.xnio.mock.ConnectedStreamChannelMock; /** * Set read ready on a channel that is handling readable. Check if the effects of setting read ready are * not mistakenly covered by handleReadable. * * @author Flavia Rainone */ @RunWith(BMUnitRunner.class) @BMScript(dir="src/test/resources") public class SetReadReadyOnHandlingReadableChannelTestCase { @Test public void test() throws Exception { // creating channel and threads ConnectedStreamChannelMock connectedChannelMock = new ConnectedStreamChannelMock(); final MyTranslatingSuspendableChannel channel = new MyTranslatingSuspendableChannel(connectedChannelMock); final Thread setReadReadyThread = new Thread(new SetReadReady(channel)); final Thread handleReadableThread = new Thread(new InvokeHandleReadable(channel)); // set up scenario final ChannelListener listener = new ChannelListener() { @Override public void handleEvent(SuspendableChannel c) { channel.clearReadReady(); } }; channel.getReadSetter().set(listener); channel.resumeReads(); channel.setReadRequiresWrite(); channel.handleReadable(); assertFalse(channel.isReadReady()); assertFalse(connectedChannelMock.isReadResumed()); // first, try to invoke handleReadable and then setReadReady System.out.println("Attempt 1: invoke handleReadable before setReadReady"); channel.handleReadable(); channel.setReadReady(); assertTrue(channel.isReadReady()); assertTrue(connectedChannelMock.isReadAwaken()); // clear everything channel.clearReadReady(); channel.handleReadable(); assertFalse(channel.isReadReady()); assertFalse(connectedChannelMock.isReadResumed()); // now, try the opposite, invoke handleReadable after setReadReady() System.out.println("Attempt 2: invoke handleReadable after setReadReady"); channel.setReadReady(); channel.handleReadable(); assertFalse(channel.isReadReady()); assertTrue(connectedChannelMock.isReadAwaken()); channel.clearReadReady(); channel.handleReadable(); assertFalse(channel.isReadReady()); assertFalse(connectedChannelMock.isReadResumed()); System.out.println("Attempt 3: race condition scenario involving handleReadable and setReadReady"); // finally, create the race condition scenario... handleReadable and setReadReady occur // practically at the same time (see SetReadReadyOnHandlingReadableChannelTestCase.btm) setReadReadyThread.start(); handleReadableThread.start(); // joining threads setReadReadyThread.join(); handleReadableThread.join(); assertFalse(channel.isReadReady()); assertTrue(connectedChannelMock.isReadResumed()); } private static class SetReadReady implements Runnable { private MyTranslatingSuspendableChannel channel; public SetReadReady(MyTranslatingSuspendableChannel channel) { this.channel = channel; } @Override public void run() { channel.setReadReady(); } } private static class InvokeHandleReadable implements Runnable { private MyTranslatingSuspendableChannel channel; public InvokeHandleReadable(MyTranslatingSuspendableChannel channel) { this.channel = channel; } @Override public void run() { channel.handleReadable(); } } private static class MyTranslatingSuspendableChannel extends TranslatingSuspendableChannel { private static final int READ_READY; private static final Field stateField; static { try { Field READ_READY_field = TranslatingSuspendableChannel.class.getDeclaredField("READ_READY"); READ_READY_field.setAccessible(true); READ_READY = READ_READY_field.getInt(null); stateField = TranslatingSuspendableChannel.class.getDeclaredField("state"); stateField.setAccessible(true); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException("Unexpected exception " + e); } } protected MyTranslatingSuspendableChannel(SuspendableChannel c) { super(c); } public void handleReadable() { super.handleReadable(); } public void setReadReady() { super.setReadReady(); } public void clearReadReady() { super.clearReadReady(); } public boolean isReadReady() throws Exception { return Bits.allAreSet(stateField.getInt(this), READ_READY); } public void setReadRequiresWrite() { super.setReadRequiresWrite(); } } } SetReadRequiresWriteOnWritingSslChannelTestCase.java000066400000000000000000000067321257016060700355030ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/org/xnio/racecondition/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.racecondition; import static org.junit.Assert.assertEquals; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import org.jboss.byteman.contrib.bmunit.BMScript; import org.jboss.byteman.contrib.bmunit.BMUnitRunner; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.xnio.channels.ConnectedSslStreamChannel; import org.xnio.mock.ConduitMock; import org.xnio.ssl.AbstractConnectedSslStreamChannelTest; import org.xnio.ssl.mock.SSLEngineMock; import org.xnio.ssl.mock.SSLEngineMock.HandshakeAction; /** * Attempt to force a scenario where a read setsReadRequiresWrite on a ssl channel while there is a write * thread attempting to setWriteRequiresRead. * * @author Flavia Rainone * */ @Ignore @RunWith(BMUnitRunner.class) @BMScript(dir="src/test/resources") public class SetReadRequiresWriteOnWritingSslChannelTestCase extends AbstractConnectedSslStreamChannelTest { @Test public void test() throws InterruptedException { engineMock.setHandshakeActions(HandshakeAction.NEED_UNWRAP, HandshakeAction.NEED_WRAP); conduitMock.enableWrites(false); Thread readThread = new Thread(new Read(sslChannel, conduitMock)); Thread writeThread = new Thread(new Write(sslChannel)); readThread.start(); writeThread.start(); readThread.join(); writeThread.join(); } private static class Read implements Runnable { private ConnectedSslStreamChannel channel; private ConduitMock conduitMock; public Read(ConnectedSslStreamChannel channel, ConduitMock conduitMock) { this.channel = channel; this.conduitMock = conduitMock; } public void run() { conduitMock.setReadData(SSLEngineMock.HANDSHAKE_MSG); conduitMock.enableReads(true); try { assertEquals(0, channel.read(ByteBuffer.allocate(15))); } catch (IOException e) { throw new RuntimeException(e); } } } private static class Write implements Runnable { private ConnectedSslStreamChannel channel; public Write(ConnectedSslStreamChannel channel) { this.channel = channel; } public void run() { ByteBuffer buffer = ByteBuffer.allocate(10); try { buffer.put("message".getBytes("UTF-8")).flip(); assertEquals(0, channel.write(buffer)); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } } } SetWriteListenerOnHandlingWritableChannelTestCase.java000066400000000000000000000164161257016060700360060ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/org/xnio/racecondition/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.racecondition; import java.io.IOException; import java.util.concurrent.TimeUnit; import org.jboss.byteman.contrib.bmunit.BMScript; import org.jboss.byteman.contrib.bmunit.BMUnitRunner; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.integration.junit4.JUnit4Mockery; import org.jmock.lib.concurrent.Synchroniser; import org.junit.Test; import org.junit.runner.RunWith; import org.xnio.ChannelListener; import org.xnio.Option; import org.xnio.XnioExecutor; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.SuspendableChannel; import org.xnio.channels.TranslatingSuspendableChannel; /** * Change write listener on a channel that is handling writable. Check if the channel realizes the listener has * changed. * * @author Flavia Rainone */ @RunWith(BMUnitRunner.class) @BMScript(dir="src/test/resources") public class SetWriteListenerOnHandlingWritableChannelTestCase { @Test public void test() throws Exception { // create mockery context final Mockery context = new JUnit4Mockery() {{ setThreadingPolicy(new Synchroniser()); }}; // creating channel and threads final MyTranslatingSuspendableChannel channel = new MyTranslatingSuspendableChannel(); final Thread setWriteListenerThread = new Thread(new SetWriteListener(channel, context)); final Thread handleWritableThread = new Thread(new InvokeHandleWritable(channel)); // set up scenario System.out.println("Setting scenario with listener1 and writes suspended"); @SuppressWarnings("unchecked") final ChannelListener listener = context.mock(ChannelListener.class, "listener1"); context.checking(new Expectations() {{ oneOf(listener).handleEvent(channel); }}); channel.getWriteSetter().set(listener); channel.resumeWrites(); // starting threads setWriteListenerThread.start(); handleWritableThread.start(); // joining threads setWriteListenerThread.join(); handleWritableThread.join(); // was "listener that must not be called" never called? And what about listener created by setWriteListener thread? Was it called exactly once? context.assertIsSatisfied(); } private static class SetWriteListener implements Runnable { private MyTranslatingSuspendableChannel channel; private Mockery context; public SetWriteListener(MyTranslatingSuspendableChannel channel, Mockery context) { this.channel = channel; this.context = context; } @Override @SuppressWarnings("unchecked") public void run() { // after handleWritable#1 channel.suspendWrites(); // after handleWritable#2 final ChannelListener listener = context.mock(ChannelListener.class, "listener2"); context.checking(new Expectations() {{ oneOf(listener).handleEvent(channel); }}); // on the third attempt to call handle writable, this is the scenario the channel should see System.out.println("Setting listener2 and resuming writes"); channel.getWriteSetter().set(listener); // after handleWritable#3 channel.resumeWrites(); } } private static class InvokeHandleWritable implements Runnable { private MyTranslatingSuspendableChannel channel; public InvokeHandleWritable(MyTranslatingSuspendableChannel channel) { this.channel = channel; } @Override public void run() { System.out.println("Attempt to handle writable number 1"); channel.handleWritable(); System.out.println("Attempt to handle writable number 2"); channel.handleWritable(); System.out.println("Attempt to handle writable number 3"); channel.handleWritable(); System.out.println("Attempt to handle writable number 4"); channel.handleWritable(); } } private static class MyTranslatingSuspendableChannel extends TranslatingSuspendableChannel { protected MyTranslatingSuspendableChannel() { super(new SuspendableChannel() { public XnioWorker getWorker() { return null; } public void close() throws IOException { } public boolean isOpen() { return false; } public boolean supportsOption(Option option) { return false; } public T getOption(Option option) throws IOException { return null; } public T setOption(Option option, T value) throws IllegalArgumentException, IOException { return null; } public void suspendReads() {} public void resumeReads() {} public boolean isReadResumed() { return false; } public void wakeupReads() {} public void shutdownReads() throws IOException {} public void awaitReadable() throws IOException {} public void awaitReadable(long time, TimeUnit timeUnit) throws IOException {} public XnioExecutor getReadThread() { return null; } public void suspendWrites() {} public void resumeWrites() {} public boolean isWriteResumed() {return false;} public void wakeupWrites() {} public void shutdownWrites() throws IOException {} public void awaitWritable() throws IOException {} public void awaitWritable(long time, TimeUnit timeUnit) throws IOException {} public XnioExecutor getWriteThread() { return null; } public boolean flush() throws IOException { return true; } public XnioIoThread getIoThread() { return null; } public ChannelListener.Setter getCloseSetter() {return new ChannelListener.SimpleSetter();} public ChannelListener.Setter getReadSetter() {return new ChannelListener.SimpleSetter();} public ChannelListener.Setter getWriteSetter() {return new ChannelListener.SimpleSetter();} }); } public void handleWritable() { super.handleWritable(); } } } SetWriteReadyOnHandlingWritableChannelTestCase.java000066400000000000000000000143761257016060700352700ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/org/xnio/racecondition/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.racecondition; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.lang.reflect.Field; import org.jboss.byteman.contrib.bmunit.BMScript; import org.jboss.byteman.contrib.bmunit.BMUnitRunner; import org.junit.Test; import org.junit.runner.RunWith; import org.xnio.Bits; import org.xnio.ChannelListener; import org.xnio.channels.SuspendableChannel; import org.xnio.channels.TranslatingSuspendableChannel; import org.xnio.mock.ConnectedStreamChannelMock; /** * Set write ready on a channel that is handling writable. Check if the effects of setting write ready are * not mistakenly covered by handleWritable. * * @author Flavia Rainone */ @RunWith(BMUnitRunner.class) @BMScript(dir="src/test/resources") public class SetWriteReadyOnHandlingWritableChannelTestCase { @Test public void test() throws Exception { // creating channel and threads ConnectedStreamChannelMock connectedChannelMock = new ConnectedStreamChannelMock(); final MyTranslatingSuspendableChannel channel = new MyTranslatingSuspendableChannel(connectedChannelMock); final Thread setWriteReadyThread = new Thread(new SetWriteReady(channel)); final Thread handleWritableThread = new Thread(new InvokeHandleWritable(channel)); // set up scenario final ChannelListener listener = new ChannelListener() { @Override public void handleEvent(SuspendableChannel c) { channel.clearWriteReady(); } }; channel.getWriteSetter().set(listener); channel.resumeWrites(); channel.setWriteRequiresRead(); channel.handleWritable(); assertFalse(channel.isWriteReady()); assertFalse(connectedChannelMock.isWriteResumed()); // first, try to invoke handleWritable and then setWriteReady System.out.println("Attempt 1: invoke handleWritable before setWriteReady"); channel.handleWritable(); channel.setWriteReady(); assertTrue(channel.isWriteReady()); assertTrue(connectedChannelMock.isWriteAwaken()); // clear everything channel.clearWriteReady(); channel.handleWritable(); assertFalse(channel.isWriteReady()); assertFalse(connectedChannelMock.isWriteResumed()); // now, try the opposite, invoke handleWritable after setWriteReady() System.out.println("Attempt 2: invoke handleWritable after setWriteReady"); channel.setWriteReady(); channel.handleWritable(); assertFalse(channel.isWriteReady()); assertTrue(connectedChannelMock.isWriteAwaken()); channel.clearWriteReady(); channel.handleWritable(); assertFalse(channel.isWriteReady()); assertFalse(connectedChannelMock.isWriteResumed()); System.out.println("Attempt 3: race condition scenario involving handleWritable and setWriteReady"); // finally, create the race condition scenario... handleWritable and setWriteReady occur // practically at the same time (see SetWriteReadyOnHandlingWritableChannelTestCase.btm) setWriteReadyThread.start(); handleWritableThread.start(); // joining threads setWriteReadyThread.join(); handleWritableThread.join(); assertFalse(channel.isWriteReady()); assertTrue(connectedChannelMock.isWriteResumed()); } private static class SetWriteReady implements Runnable { private MyTranslatingSuspendableChannel channel; public SetWriteReady(MyTranslatingSuspendableChannel channel) { this.channel = channel; } @Override public void run() { channel.setWriteReady(); } } private static class InvokeHandleWritable implements Runnable { private MyTranslatingSuspendableChannel channel; public InvokeHandleWritable(MyTranslatingSuspendableChannel channel) { this.channel = channel; } @Override public void run() { channel.handleWritable(); } } private static class MyTranslatingSuspendableChannel extends TranslatingSuspendableChannel { private static final int WRITE_READY; private static final Field stateField; static { try { Field WRITE_READY_field = TranslatingSuspendableChannel.class.getDeclaredField("WRITE_READY"); WRITE_READY_field.setAccessible(true); WRITE_READY = WRITE_READY_field.getInt(null); stateField = TranslatingSuspendableChannel.class.getDeclaredField("state"); stateField.setAccessible(true); } catch (RuntimeException e) { throw e; } catch (Exception e) { throw new RuntimeException("Unexpected exception " + e); } } protected MyTranslatingSuspendableChannel(SuspendableChannel c) { super(c); } public void handleWritable() { super.handleWritable(); } public void setWriteReady() { super.setWriteReady(); } public void clearWriteReady() { super.clearWriteReady(); } public boolean isWriteReady() throws Exception { return Bits.allAreSet(stateField.getInt(this), WRITE_READY); } public void setWriteRequiresRead() { super.setWriteRequiresRead(); } } } SetWriteRequiresReadOnReadingSslChannelTestCase.java000066400000000000000000000065661257016060700354360ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/org/xnio/racecondition/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.racecondition; import static org.junit.Assert.assertEquals; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import org.jboss.byteman.contrib.bmunit.BMScript; import org.jboss.byteman.contrib.bmunit.BMUnitRunner; import org.junit.Ignore; import org.junit.Test; import org.junit.runner.RunWith; import org.xnio.channels.ConnectedSslStreamChannel; import org.xnio.mock.ConduitMock; import org.xnio.ssl.AbstractConnectedSslStreamChannelTest; import org.xnio.ssl.mock.SSLEngineMock.HandshakeAction; /** * Attempt to force a scenario where a write setsWriteRequiresRead on a ssl channel while there is a read * thread attempting to setReadRequiresWrite. * * @author Flavia Rainone * */ @Ignore @RunWith(BMUnitRunner.class) @BMScript(dir="src/test/resources") public class SetWriteRequiresReadOnReadingSslChannelTestCase extends AbstractConnectedSslStreamChannelTest { @Test public void test() throws InterruptedException { engineMock.setHandshakeActions(HandshakeAction.NEED_WRAP, HandshakeAction.NEED_UNWRAP); conduitMock.enableWrites(false); Thread readThread = new Thread(new Read(sslChannel)); Thread writeThread = new Thread(new Write(sslChannel, conduitMock)); readThread.start(); writeThread.start(); readThread.join(); writeThread.join(); } private static class Read implements Runnable { private ConnectedSslStreamChannel channel; public Read(ConnectedSslStreamChannel channel) { this.channel = channel; } public void run() { try { assertEquals(0, channel.read(ByteBuffer.allocate(15))); } catch (IOException e) { throw new RuntimeException(e); } } } private static class Write implements Runnable { private ConnectedSslStreamChannel channel; private ConduitMock conduitMock; public Write(ConnectedSslStreamChannel channel, ConduitMock conduitMock) { this.channel = channel; this.conduitMock = conduitMock; } public void run() { ByteBuffer buffer = ByteBuffer.allocate(10); try { conduitMock.enableWrites(true); buffer.put("message".getBytes("UTF-8")).flip(); assertEquals(0, channel.write(buffer)); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } catch (IOException e) { throw new RuntimeException(e); } } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/000077500000000000000000000000001257016060700213355ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/AbstractConnectedSslStreamChannelTest.java000066400000000000000000000055331257016060700315630ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import java.io.IOException; import java.nio.ByteBuffer; import org.junit.Before; import org.xnio.AssertReadWrite; import org.xnio.BufferAllocator; import org.xnio.ByteBufferSlicePool; import org.xnio.Pool; import org.xnio.channels.AssembledConnectedSslStreamChannel; import org.xnio.channels.ConnectedSslStreamChannel; import org.xnio.mock.ConduitMock; import org.xnio.mock.StreamConnectionMock; /** * Abstract test for {@link #AssembledConnectedSslStreamChannel}. * * @author Flavia Rainone */ public abstract class AbstractConnectedSslStreamChannelTest extends AbstractSslTest { // the channel to be tested protected ConnectedSslStreamChannel sslChannel; // the underlying connection used as a delegate by the test target protected StreamConnectionMock connectionMock; // the underlying conduit used as a delegate by the test target protected ConduitMock conduitMock; @Override @Before public void createChannelMock() throws IOException { super.createChannelMock(); conduitMock = new ConduitMock(); connectionMock = new StreamConnectionMock(conduitMock); sslChannel = createSslChannel(); } protected ConnectedSslStreamChannel createSslChannel() { final Pool socketBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 17000, 17000 * 16); final Pool applicationBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 17000, 17000 * 16); final SslConnection connection = new JsseSslStreamConnection(connectionMock, engineMock, socketBufferPool, applicationBufferPool, false); return new AssembledConnectedSslStreamChannel(connection, connection.getSourceChannel(), connection.getSinkChannel()); } @Override protected void assertWrittenMessage(String... message) { AssertReadWrite.assertWrittenMessage(conduitMock, message); } protected final void assertWrittenMessage(String[]... interwovenMessages) { super.tempAssertWrittenMessage(conduitMock.getWrittenText(), interwovenMessages); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/AbstractSslConnectionTest.java000066400000000000000000000064071257016060700273140ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import java.io.IOException; import java.nio.ByteBuffer; import org.junit.Before; import org.xnio.AssertReadWrite; import org.xnio.BufferAllocator; import org.xnio.ByteBufferSlicePool; import org.xnio.Pool; import org.xnio.conduits.StreamSinkConduit; import org.xnio.conduits.StreamSourceConduit; import org.xnio.mock.ConduitMock; import org.xnio.mock.StreamConnectionMock; /** * Abstract test for the SSL connection and its conduits. * * @author Flavia Rainone */ public abstract class AbstractSslConnectionTest extends AbstractSslTest { // the conduits to be tested protected ConduitMock conduitMock; protected SslConnection connection; protected StreamSinkConduit sinkConduit; protected StreamSourceConduit sourceConduit; @Override @Before public void createChannelMock() throws IOException { super.createChannelMock(); conduitMock = new ConduitMock(); connection = createSslConnection(); this.sinkConduit = connection.getSinkChannel().getConduit(); this.sourceConduit = connection.getSourceChannel().getConduit(); } protected SslConnection createSslConnection() { final Pool socketBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 17000, 17000 * 16); final Pool applicationBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 17000, 17000 * 16); final StreamConnectionMock connectionMock = new StreamConnectionMock(conduitMock); return new JsseSslStreamConnection(connectionMock, engineMock, socketBufferPool, applicationBufferPool, false); } protected JsseSslConduitEngine createSslConduitEngine(StreamSinkConduit sinkConduit, StreamSourceConduit sourceConduit) { final Pool socketBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 17000, 17000 * 16); final Pool applicationBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 17000, 17000 * 16); return new JsseSslConduitEngine((JsseSslStreamConnection) connection, sinkConduit, sourceConduit, engineMock, socketBufferPool, applicationBufferPool); } @Override protected final void assertWrittenMessage(String... message) { AssertReadWrite.assertWrittenMessage(conduitMock, message); } protected final void assertWrittenMessage(String[]... interwovenMessages) { super.tempAssertWrittenMessage(conduitMock.getWrittenText(), interwovenMessages); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/AbstractSslTest.java000066400000000000000000000120771257016060700252740ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.ssl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.fail; import java.io.IOException; import java.nio.ByteBuffer; import org.jmock.Mockery; import org.jmock.integration.junit4.JUnit4Mockery; import org.jmock.lib.concurrent.Synchroniser; import org.junit.After; import org.junit.Before; import org.xnio.Buffers; import org.xnio.ssl.mock.SSLEngineMock; /** * Abstract test for SSl enabled channels and conduits. * * An SSLEngine mock is used to test different engine behaviors and a channel mock is provided. * * @author Flavia Rainone * */ public abstract class AbstractSslTest { // mockery context protected Mockery context; // the SSLEngine mock, allows to test different engine behavior with channel protected SSLEngineMock engineMock; @Before public void createChannelMock() throws IOException { context = new JUnit4Mockery() {{ setThreadingPolicy(new Synchroniser()); }}; engineMock = new SSLEngineMock(context); } @After public void checkContext() { context.assertIsSatisfied(); } /** * Asserts that the message read by {@code sslChannel}, contained in {@code dst}, equals {@code message}. * @param dst the buffer containing the read message * @param message message expected to have been read into {@code dst} */ protected final void assertReadMessage(ByteBuffer dst, String... message) { StringBuffer stringBuffer = new StringBuffer(); for (String messageString: message) { stringBuffer.append(messageString); } dst.flip(); assertEquals(stringBuffer.toString(), Buffers.getModifiedUtf8(dst)); } /** * Asserts that {@code message} equals the data written by {@code sslChannel} to {@code connectedChannelMock}. * * @param message the message expected to have been written to the channel mock */ protected abstract void assertWrittenMessage(String... message); /** * Asserts that {@code interwovenMessages} have been written by {@code sslChannel} to {@code connectedChannelMock}, * in an interwoven way. In other words, the sequence of messages inside each {@code String[]} message array has * to be kept between its components, but this array can be mixed with other {@code String[]} message arrays * contained in {@code interwovenMessages}. *

* A valid example of usage is when you expect to have two {@link SSLEngineMock#HANDSHAKE_MSG}s mixed with one * {@code "testMessage"}. In this case, calling this method like below:
* assertWrittenMessage(new String[] {HANDSHAKE_MSG, HANDSHAKE_MSG}, new String[] {"testMessage"}) *
* will consider valid the sequences below:
* {@code HANDSHAKE_MSG, HANDSHAKE_MSG, "testMessage"}
* {@code HANDSHAKE_MSG, "testMessage", HANDSHAKE_MSG}
* {@code "testMessage", HANDSHAKE_MSG, HANDSHAKE_MSG}
* but will invalidate, for example, the next two sequences:
* {@code "testMessage, HANDSHAKE_MSG *
{@code HANDSHAKE_MSG, "testMessage", HANDSHAKE_MSG, HANDSHAKE_MSG}. * * @param interwovenMessages messages expected to have been written to {@code connectedChannelMock} */ // TODO fix this javadoc and class once we get rid of JsseConnectedSslStreamChannel protected final void tempAssertWrittenMessage(String writtenMessage, String[]... interwovenMessages) { //String writtenMessage = connectedChannelMock.getWrittenText(); for (String[] messages: interwovenMessages) { StringBuffer stringBuffer = new StringBuffer(); String writtenMessageSuffix = writtenMessage; for (String message: messages) { int indexOfMessage = writtenMessageSuffix.indexOf(message); if (indexOfMessage == -1) { fail("Couldn't find message " + message + " at " + writtenMessageSuffix + "\n Complete written message: "+ writtenMessage); } stringBuffer.append(writtenMessageSuffix.substring(0, indexOfMessage)); writtenMessageSuffix = writtenMessageSuffix.substring(indexOfMessage + message.length()); } stringBuffer.append(writtenMessageSuffix); writtenMessage = stringBuffer.toString(); } assertEquals(0, writtenMessage.length()); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/ChannelDelegationTestCase.java000066400000000000000000000123751257016060700272100ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import org.junit.Test; import org.xnio.FileAccess; import org.xnio.LocalSocketAddress; import org.xnio.OptionMap; import org.xnio.Options; /** * Asserts that the SSL channel delegates some operations such as getLocalAddress to the underlying connection. * * @author Flavia Rainone */ public class ChannelDelegationTestCase extends AbstractConnectedSslStreamChannelTest { @Test public void getLocalAddress() { SocketAddress address = new LocalSocketAddress("here"); connectionMock.setLocalAddress(address); assertSame(address, sslChannel.getLocalAddress()); address = new InetSocketAddress(100); connectionMock.setLocalAddress(address); assertSame(address, connectionMock.getLocalAddress()); } @Test public void getTypedLocalAddress() { SocketAddress address = new LocalSocketAddress("here"); connectionMock.setLocalAddress(address); assertSame(address, sslChannel.getLocalAddress(LocalSocketAddress.class)); assertSame(address, sslChannel.getLocalAddress(SocketAddress.class)); assertNull(sslChannel.getLocalAddress(InetSocketAddress.class)); address = new InetSocketAddress(1009); connectionMock.setLocalAddress(address); assertSame(address, sslChannel.getLocalAddress(InetSocketAddress.class)); assertSame(address, sslChannel.getLocalAddress(SocketAddress.class)); assertNull(sslChannel.getLocalAddress(LocalSocketAddress.class)); } @Test public void getPeerAddress() { SocketAddress address = new LocalSocketAddress("there"); connectionMock.setPeerAddress(address); assertSame(address, sslChannel.getPeerAddress()); address = new InetSocketAddress(10); connectionMock.setPeerAddress(address); assertSame(address, connectionMock.getPeerAddress()); } @Test public void getTypedPeerAddress() { SocketAddress address = new LocalSocketAddress("there"); connectionMock.setPeerAddress(address); assertSame(address, sslChannel.getPeerAddress(LocalSocketAddress.class)); assertSame(address, sslChannel.getPeerAddress(SocketAddress.class)); assertNull(sslChannel.getPeerAddress(InetSocketAddress.class)); address = new InetSocketAddress(1009); connectionMock.setPeerAddress(address); assertSame(address, sslChannel.getPeerAddress(InetSocketAddress.class)); assertSame(address, sslChannel.getPeerAddress(SocketAddress.class)); assertNull(sslChannel.getPeerAddress(LocalSocketAddress.class)); } @Test public void getWorker() { assertSame(sslChannel.getWorker(), connectionMock.getWorker()); } @Test public void getSslSession() { assertNotNull(sslChannel.getSslSession()); } @Test public void getOption() throws IOException { connectionMock.setOptionMap(OptionMap.create(Options.SSL_ENABLED, Boolean.TRUE, Options.MAX_INBOUND_MESSAGE_SIZE, Integer.valueOf(1000))); assertSame(Boolean.TRUE, sslChannel.getOption(Options.SSL_ENABLED)); assertEquals(1000, sslChannel.getOption(Options.MAX_INBOUND_MESSAGE_SIZE).intValue()); assertNull(sslChannel.getOption(Options.READ_TIMEOUT)); connectionMock.setOptionMap(OptionMap.create(Options.ALLOW_BLOCKING, Boolean.TRUE)); assertSame(Boolean.TRUE, sslChannel.getOption(Options.ALLOW_BLOCKING)); assertNull(sslChannel.getOption(Options.SSL_ENABLED)); } @Test public void supportsOption() throws IOException { connectionMock.setOptionMap(OptionMap.create(Options.FILE_ACCESS, FileAccess.READ_ONLY, Options.CLOSE_ABORT, Boolean.FALSE)); assertTrue(sslChannel.supportsOption(Options.FILE_ACCESS)); assertTrue(sslChannel.supportsOption(Options.CLOSE_ABORT)); assertFalse(sslChannel.supportsOption(Options.SSL_ENABLED)); connectionMock.setOptionMap(OptionMap.create(Options.BROADCAST, Boolean.TRUE)); assertTrue(sslChannel.supportsOption(Options.BROADCAST)); assertFalse(sslChannel.supportsOption(Options.IP_TRAFFIC_CLASS)); assertTrue(sslChannel.supportsOption(Options.SECURE)); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/ConnectedSslStreamChannelBufferOverflowTestCase.java000066400000000000000000000111221257016060700335400ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.nio.ByteBuffer; import javax.net.ssl.SSLSession; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.integration.junit4.JUnit4Mockery; import org.jmock.lib.concurrent.Synchroniser; import org.junit.Test; import org.xnio.BufferAllocator; import org.xnio.ByteBufferSlicePool; import org.xnio.Pool; import org.xnio.channels.AssembledConnectedSslStreamChannel; import org.xnio.channels.ConnectedSslStreamChannel; import org.xnio.mock.ConnectedStreamChannelMock; import org.xnio.ssl.mock.SSLEngineMock; import org.xnio.ssl.mock.SSLEngineMock.HandshakeAction; /** * Tests {@link AssembledConnectedSslStreamChannel} in buffer overflow scenarios. * * @author Flavia Rainone * */ public class ConnectedSslStreamChannelBufferOverflowTestCase extends AbstractConnectedSslStreamChannelTest { // mockery context protected Mockery context; // the underlying channel used by JsseConnectedSslStreamChannel above protected ConnectedStreamChannelMock connectedChannelMock; // the SSLEngine mock, allows to test different engine behavior with channel protected SSLEngineMock engineMock; @Override protected ConnectedSslStreamChannel createSslChannel() { context = new JUnit4Mockery() {{ setThreadingPolicy(new Synchroniser()); }}; connectedChannelMock = new ConnectedStreamChannelMock(); engineMock = new SSLEngineMockSmallPacketSize(context); final Pool socketBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 10, 160); final Pool applicationBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 10, 160); final SslConnection connection = new JsseSslStreamConnection(connectionMock, engineMock, socketBufferPool, applicationBufferPool, false); return new AssembledConnectedSslStreamChannel(connection, connection.getSourceChannel(), connection.getSinkChannel()); } @Test public void bufferOverflowOnWrite() throws IOException { boolean fail = false; final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("12345678901234567890".getBytes("UTF-8")).flip(); // attempt to write... channel is expected to write to throw an IOException // SSLEngine required a bigger send buffer but out buffer was already big enough try { sslChannel.write(buffer); } catch (IOException e) { fail = true; } assertTrue(fail); } @Test public void bufferOverflowOnRead() throws IOException { engineMock.setHandshakeActions(HandshakeAction.NEED_UNWRAP, HandshakeAction.FINISH); connectedChannelMock.setReadData(SSLEngineMock.HANDSHAKE_MSG); connectedChannelMock.enableRead(true); // attempt to read... channel is expected to not be able to read the message because HANDSHAKE_MSG does not fit // in a 10 byte buffer assertEquals(0, sslChannel.read(ByteBuffer.allocate(50))); } private static class SSLEngineMockSmallPacketSize extends SSLEngineMock { public SSLEngineMockSmallPacketSize (Mockery mockery) { super(mockery); } @Override public SSLSession getSession() { synchronized (mockery) { final SSLSession sessionMock = mockery.mock(SSLSession.class, "SmallPacketsSession"); mockery.checking(new Expectations() {{ oneOf(sessionMock).getPacketBufferSize(); will(returnValue(10)); oneOf(sessionMock).getApplicationBufferSize(); will(returnValue(5)); }}); return sessionMock; } } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/ConnectedSslStreamChannelReadTestCase.java000066400000000000000000000435251257016060700314720ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.xnio.ssl.mock.SSLEngineMock.CLOSE_MSG; import static org.xnio.ssl.mock.SSLEngineMock.HANDSHAKE_MSG; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.FINISH; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_FAULTY_TASK; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_TASK; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_UNWRAP; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_WRAP; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.PERFORM_REQUESTED_ACTION; import java.io.IOException; import java.nio.ByteBuffer; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import org.jmock.integration.junit4.JMock; import org.jmock.integration.junit4.JUnitRuleMockery; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.xnio.ssl.mock.SSLEngineMock; /** * Test for read operations on a {@link AssembledConnectedSslStreamChannel}. * * @author Flavia Rainone */ public class ConnectedSslStreamChannelReadTestCase extends AbstractConnectedSslStreamChannelTest{ @Rule public final JUnitRuleMockery context = new JUnitRuleMockery(); @Test public void readWithoutHandshake() throws IOException { // no handshake actions for engineMock this time, meaning it will just wrap and unwrap without any handshake // the message we want to write conduitMock.setReadData("MockTest", CLOSE_MSG); conduitMock.enableReads(true); final ByteBuffer buffer = ByteBuffer.allocate(100); // attempt to read... channel is expected to read the entire message without any issues assertEquals(8, sslChannel.read(buffer)); // shutdown reads sslChannel.shutdownReads(); // close channel sslChannel.close(); // data expected to have been copied to buffer by channel assertReadMessage(buffer, "MockTest"); } @Test public void readWithoutHandshakeMappedUnwrap() throws IOException { // map the wrap engineMock.addWrapEntry("MockTest", "WRAPPED_MOCK_TEST"); // no handshake actions for engineMock this time, meaning it will just wrap and unwrap without any handshake // the message we want to read conduitMock.setReadData("WRAPPED_MOCK_TEST", CLOSE_MSG); conduitMock.enableReads(true); // attempt to read... channel is expected to read the entire message without any handshake issues final ByteBuffer buffer = ByteBuffer.allocate(100); assertEquals(8, sslChannel.read(buffer)); // shutdown reads sslChannel.shutdownReads(); // close channel sslChannel.close(); // data expected to have been read to 'buffer' by 'sslChannel' assertReadMessage(buffer, "MockTest"); } @Test public void readWithSimpleHandshake() throws IOException { // map all data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "handshake"); engineMock.addWrapEntry("MockTest", "mock test works!"); engineMock.addWrapEntry(CLOSE_MSG, "channel closed"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH); // set ReadData on connectedChannelMock, including the wrapped version of message we want to read conduitMock.setReadData("handshake", "mock test works!", "channel closed"); conduitMock.enableReads(true); // channel is expected to read all data from connectedChannelMock final ByteBuffer buffer = ByteBuffer.allocate(100); assertEquals(8, sslChannel.read(buffer)); // shutdown reads sslChannel.shutdownReads(); // close channel sslChannel.close(); assertReadMessage(buffer, "MockTest"); // data expected to have been written to 'connectedChannelMock' by 'sslChannel' assertWrittenMessage("handshake", "channel closed"); } @Test public void readWithTasklessHandshake() throws IOException { // map data to be read and written engineMock.addWrapEntry("Mock Test", "{testReadWithTasklessHandshake}"); engineMock.addWrapEntry(CLOSE_MSG, " _ "); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, FINISH); // set ReadData on connectedChannelMock conduitMock.setReadData(SSLEngineMock.HANDSHAKE_MSG, "{testReadWithTasklessHandshake}", " _ "); conduitMock.enableReads(true); // channel is expected to read "Mock Test" from connectedChannelMock final ByteBuffer buffer = ByteBuffer.allocate(100); assertEquals(9, sslChannel.read(buffer)); // channel should be able to shutdown writes sslChannel.shutdownReads(); // close channel sslChannel.close(); // data expected to have been read from 'connectedChannelMock' by 'sslChannel' assertReadMessage(buffer, "Mock Test"); // data expected to have been written to 'connectedChannelMock' by 'sslChannel' assertWrittenMessage(HANDSHAKE_MSG, " _ "); } @Test public void multipleReadsWithSimpleHandshake() throws IOException { // map data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "{handshake data}"); engineMock.addWrapEntry("Mock Read Test", "{data}"); engineMock.addWrapEntry("it works!", "{more data}"); engineMock.addWrapEntry(CLOSE_MSG, "{message closed}"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH); // set ReadData on connectedChannelMock conduitMock.setReadData("{handshake data}", "{data}", "{data}", "{more data}"); // enable read on connectedChannelMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // try to read message final ByteBuffer buffer = ByteBuffer.allocate(30); assertEquals(30, sslChannel.read(buffer)); // data expected to have been read from 'connectedChannelMock' by 'sslChannel' so far assertReadMessage(buffer, "Mock Read Test", "Mock Read Test", "it"); buffer.clear(); // set more read data conduitMock.setReadData("{data}", "{more data}"); conduitMock.enableReads(true); // and read again assertEquals(30, sslChannel.read(buffer)); // data expected to have been read from 'connectedChannelMock' by 'sslChannel' assertReadMessage(buffer, " works!", "Mock Read Test", "it works!"); buffer.clear(); // set more read data conduitMock.setReadData("{more data}", "{message closed}"); conduitMock.enableReads(true); // and read again assertEquals(9, sslChannel.read(buffer)); // data expected to have been read from 'connectedChannelMock' by 'sslChannel' assertReadMessage(buffer, "it works!"); buffer.clear(); // channel should be able to shutdown reads sslChannel.shutdownReads(); // close channel sslChannel.close(); // data expected to have been written to 'connectedChannelMock' by 'sslChannel' assertWrittenMessage("{handshake data}", "{message closed}"); } @Test public void readWithAbruptClose() throws IOException { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_UNWRAP, NEED_WRAP, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH); // message buffer final ByteBuffer buffer = ByteBuffer.allocate(100); conduitMock.setReadData(HANDSHAKE_MSG, CLOSE_MSG); conduitMock.enableReads(true); // attempt to read several times... channel is expected to stop on the second NEED_UNWRAP actoin, as // connectedChannelMock will read an abrupt CLOSE_MSG assertEquals(-1, sslChannel.read(buffer)); assertEquals(-1, sslChannel.read(buffer)); assertEquals(-1, sslChannel.read(buffer)); // channel should be able to shutdown writes sslChannel.shutdownReads(); // close channel sslChannel.close(); // data expected to have been written to 'connectedChannelMock' by 'sslChannel' assertWrittenMessage(HANDSHAKE_MSG, CLOSE_MSG); } @Test public void readWithConstantHandshake() throws IOException { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_WRAP, NEED_WRAP, NEED_UNWRAP, NEED_TASK, NEED_TASK, NEED_TASK, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION); // set ReadData on connectedChannelMock conduitMock.setReadData(HANDSHAKE_MSG, "read a lot", HANDSHAKE_MSG, " read a lot ", HANDSHAKE_MSG, "read a lot ", HANDSHAKE_MSG, " read a lot", CLOSE_MSG); // enable read on connectedChannelMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // try to read message final ByteBuffer buffer = ByteBuffer.allocate(10); assertEquals(10, sslChannel.read(buffer)); assertReadMessage(buffer, "read a lot"); buffer.clear(); assertEquals(10, sslChannel.read(buffer)); assertReadMessage(buffer, " read a lo"); buffer.clear(); assertEquals(10, sslChannel.read(buffer)); assertReadMessage(buffer, "t read a l"); buffer.clear(); assertEquals(10, sslChannel.read(buffer)); assertReadMessage(buffer, "ot read a"); buffer.clear(); assertEquals(4, sslChannel.read(buffer)); assertReadMessage(buffer, " lot"); // make sure that channel managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // shutdown reads sslChannel.shutdownReads(); // close channel sslChannel.close(); // data expected to have been written to 'connectedChannelMock' by 'sslChannel' assertWrittenMessage(HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, CLOSE_MSG); } @Test public void readWithConstantHandshakeAndMappedData() throws IOException { // map data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "HANDSHAKE_MSG"); engineMock.addWrapEntry("a lot", "read a lot"); engineMock.addWrapEntry("read", "read"); engineMock.addWrapEntry("lot", "a lot"); engineMock.addWrapEntry("nothing", "read nothing"); engineMock.addWrapEntry(CLOSE_MSG, "CLOSE_MSG"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_WRAP, NEED_WRAP, NEED_UNWRAP, NEED_TASK, NEED_TASK, NEED_TASK, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION); // set ReadData on connectedChannelMock conduitMock.setReadData("HANDSHAKE_MSG", "read a lot", "a lot", "read", "HANDSHAKE_MSG", "a lot", "read a lot", "HANDSHAKE_MSG", "read nothing", "read a lot", "HANDSHAKE_MSG", "read nothing", "CLOSE_MSG"); // enable read on connectedChannelMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // try to read message final ByteBuffer buffer = ByteBuffer.allocate(10); assertEquals(10, sslChannel.read(buffer)); assertReadMessage(buffer, "a lot", "lot", "re"); buffer.clear(); assertEquals(10, sslChannel.read(buffer)); assertReadMessage(buffer, "ad", "lot", "a lot"); buffer.clear(); assertEquals(10, sslChannel.read(buffer)); assertReadMessage(buffer, "nothing", "a l"); buffer.clear(); assertEquals(9, sslChannel.read(buffer)); assertReadMessage(buffer, "ot", "nothing"); buffer.clear(); // make sure that channel managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // shutdown reads sslChannel.shutdownReads(); // close channel sslChannel.close(); // data expected to have been written to 'connectedChannelMock' by 'sslChannel' assertWrittenMessage("HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "CLOSE_MSG"); } @Test public void readWithIntercalatedHandshake() throws IOException { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, FINISH); // set ReadData on connectedChannelMock conduitMock.setReadData(HANDSHAKE_MSG, "read this", "read this", "read this", "read this", HANDSHAKE_MSG, "read this", HANDSHAKE_MSG, "read this", CLOSE_MSG); // enable read on connectedChannelMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); final ByteBuffer buffer = ByteBuffer.allocate(100); // attempt to read... channel is expected to read the message assertEquals(54, sslChannel.read(buffer)); // make sure that channel managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // shutdown reads sslChannel.shutdownReads(); // close channel sslChannel.close(); // data expected to have been read from 'connectedChannelMock' by 'sslChannel' assertReadMessage(buffer, "read this", "read this", "read this", "read this", "read this", "read this"); // data expected to have been written to 'connectedChannelMock' by 'sslChannel' assertWrittenMessage(HANDSHAKE_MSG, HANDSHAKE_MSG, CLOSE_MSG); } @Test public void readWithIntercalatedHandshakeAndMappedData() throws IOException { // map all data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "[!@#$%^&*()_]"); engineMock.addWrapEntry("this", "read this"); engineMock.addWrapEntry(CLOSE_MSG, "[_)(*&^%$#@!]"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, FINISH); // set ReadData on connectedChannelMock conduitMock.setReadData("[!@#$%^&*()_]", "read this", "read this", "read this", "read this", "[!@#$%^&*()_]", "read this", "[!@#$%^&*()_]", "read this", "[_)(*&^%$#@!]"); // enable read on connectedChannelMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); final ByteBuffer buffer = ByteBuffer.allocate(100); // attempt to read... channel is expected to read the message assertEquals(24, sslChannel.read(buffer)); // make sure that channel managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // shutdown reads sslChannel.shutdownReads(); // close channel sslChannel.close(); // data expected to have been read from 'connectedChannelMock' by 'sslChannel' assertReadMessage(buffer, "this", "this", "this", "this", "this", "this"); // data expected to have been written to 'connectedChannelMock' by 'sslChannel' assertWrittenMessage("[!@#$%^&*()_]", "[!@#$%^&*()_]", "[_)(*&^%$#@!]"); } @Test public void attemptToReadWithFaultyTask() throws IOException { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_FAULTY_TASK); // message we plan to write final ByteBuffer buffer = ByteBuffer.allocate(21); // try to write a bunch of times, we will get an IOException at all of the times for (int i = 0; i < 10; i ++) { boolean failed = false; try { sslChannel.read(buffer); } catch (IOException expected) { failed = true; } assertTrue(failed); } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/ConnectedSslStreamChannelReadWriteTestCase.java000066400000000000000000000727321257016060700325070ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.xnio.ssl.mock.SSLEngineMock.CLOSE_MSG; import static org.xnio.ssl.mock.SSLEngineMock.HANDSHAKE_MSG; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.FINISH; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_TASK; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_UNWRAP; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_WRAP; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.PERFORM_REQUESTED_ACTION; import java.io.IOException; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import org.jmock.integration.junit4.JUnitRuleMockery; import org.jmock.lib.concurrent.Synchroniser; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.xnio.Buffers; import org.xnio.ssl.mock.SSLEngineMock; /** * Test for concurrent read and write operations on {@link #AssembledConnectedSslStreamChannel}. * * @author Flavia Rainone */ @Ignore // ignoring for now as these tests hang more consistently than they pass public class ConnectedSslStreamChannelReadWriteTestCase extends AbstractConnectedSslStreamChannelTest{ @Rule public final JUnitRuleMockery context = new JUnitRuleMockery() {{ setThreadingPolicy(new Synchroniser()); }}; @Test public void simpleReadAndWrite() throws Exception { // no handshake actions for engineMock this time, meaning it will just wrap and unwrap without any handshake // the message we want to write conduitMock.setReadData("read data"); conduitMock.enableReads(true); final Future readFuture = triggerReadThread(9); final Future writeFuture = triggerWriteThread("write data"); writeFuture.get(); conduitMock.setReadData(CLOSE_MSG); final ByteBuffer readBuffer = readFuture.get(); // FIXME: move shutdownWrites to write thread, and shutdown reads to read thread after the issue involving // those operations is worked around // MORE INFO: we have to shutdown write and read only after channel has read and written everything... // the mock here only mimics the behavior we find in SSLEngine implementation: the channel cannot do read // nor write after either read or write have been shutdown sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); sslChannel.shutdownReads(); // close channel sslChannel.close(); // data expected to have been copied to buffer by channel assertReadMessage(readBuffer, "read data"); assertWrittenMessage("write data", CLOSE_MSG); } @Test public void readAndWriteMappedWrap() throws Exception { // map the wrap engineMock.addWrapEntry("a very long message", "BLABLABLABLABLABLABLA"); engineMock.addWrapEntry("short msg", "MSG"); // no handshake actions for engineMock this time, meaning that it will just wrap and unwrap without any handshake // the message we want to read conduitMock.setReadData("BLABLABLABLABLABLABLA"); conduitMock.enableReads(true); // attempt to read and write final Future writeFuture = triggerWriteThread("short msg", "short msg"); final Future readFuture = triggerReadThread(19); writeFuture.get(); conduitMock.setReadData(CLOSE_MSG); final ByteBuffer readBuffer = readFuture.get(); // channel should be able to shutdown reads and writes sslChannel.shutdownReads(); sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); // close channel sslChannel.close(); // data expected to have been read to 'buffer' by 'channel' assertReadMessage(readBuffer, "a very long message"); assertWrittenMessage("MSG", "MSG", CLOSE_MSG); } @Test public void readAndWriteWithSimpleHandshake() throws Exception { // map all data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "handshake"); engineMock.addWrapEntry("MockTest", "mock test works!"); engineMock.addWrapEntry(CLOSE_MSG, "channel closed"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH); // set ReadData on connectedChannelMock, including the wrapped version of message we want to read conduitMock.setReadData("handshake", "mock test works!", "mock test works!"); conduitMock.enableReads(true); // attempt to read and write final Future writeFuture = triggerWriteThread("MockTest"); final Future readFuture = triggerReadThread(16); writeFuture.get(); conduitMock.setReadData("channel closed"); final ByteBuffer readBuffer = readFuture.get(); // channel should be able to shutdown reads and writes sslChannel.shutdownReads(); sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); // close channel sslChannel.close(); assertReadMessage(readBuffer, "MockTest", "MockTest"); // data expected to have been written to 'connectedChannelMock' by 'channel' assertWrittenMessage("handshake", "mock test works!", "channel closed"); } @Test public void readAndWriteWithTasklessHandshake() throws Exception { // map data to be read and written engineMock.addWrapEntry("Mock Test", "{testReadWriteWithTasklessHandshake}"); engineMock.addWrapEntry(CLOSE_MSG, " _ "); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, FINISH); // set ReadData on connectedChannelMock conduitMock.setReadData(SSLEngineMock.HANDSHAKE_MSG, "{testReadWriteWithTasklessHandshake}"); conduitMock.enableReads(true); // attempt to read and write final Future writeFuture = triggerWriteThread("Mock Test", "Mock Test", "Mock Test", "Mock Test"); final Future readFuture = triggerReadThread(9); writeFuture.get(); conduitMock.setReadData(" _ "); final ByteBuffer readBuffer = readFuture.get(); // channel should be able to shutdown reads and writes sslChannel.shutdownReads(); sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); // close channel sslChannel.close(); // data expected to have been read from 'connectedChannelMock' by 'channel' assertReadMessage(readBuffer, "Mock Test"); // data expected to have been written to 'connectedChannelMock' by 'channel' assertWrittenMessage(HANDSHAKE_MSG, "{testReadWriteWithTasklessHandshake}", "{testReadWriteWithTasklessHandshake}", "{testReadWriteWithTasklessHandshake}", "{testReadWriteWithTasklessHandshake}", " _ "); } @Test public void multipleFeedReadAndWriteWithSimpleHandshake() throws Exception { // map data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "{handshake data}"); engineMock.addWrapEntry("Mock Read/Write Test", "{data}"); engineMock.addWrapEntry("it works!", "{more data}"); engineMock.addWrapEntry(CLOSE_MSG, "{message closed}"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH); // set ReadData on connectedChannelMock conduitMock.setReadData(); // enable read on connectedChannelMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // attempt to read and write final Future writeFuture = triggerWriteThread("it works!", "Mock Read/Write Test", "it works!", "Mock Read/Write Test", "it works!", "it works!", "Mock Read/Write Test"); final Future readFuture = triggerReadThread(67); Thread.sleep(20); conduitMock.setReadData("{handshake data}"); Thread.sleep(10); conduitMock.setReadData( "{data}", "{data}", "{more data}"); Thread.sleep(10); conduitMock.setReadData("{more data}", "{more data}"); Thread.sleep(10); writeFuture.get(); conduitMock.setReadData("{message closed}"); final ByteBuffer readBuffer = readFuture.get(); assertNotNull(readBuffer); // channel should be able to shutdown reads and writes sslChannel.shutdownReads(); sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); // close channel sslChannel.close(); // data expected to have been read from 'connectedChannelMock' by 'channel' so far assertReadMessage(readBuffer, "Mock Read/Write Test", "Mock Read/Write Test", "it works!", "it works!", "it works!"); // data expected to have been written to 'connectedChannelMock' by 'channel' assertWrittenMessage("{handshake data}", "{more data}", "{data}", "{more data}", "{data}", "{more data}", "{more data}", "{data}", "{message closed}"); } @Test public void readAndWriteWithConstantHandshake() throws Exception { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_WRAP, NEED_WRAP, NEED_UNWRAP, NEED_TASK, NEED_TASK, NEED_TASK, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION); // set ReadData on connectedChannelMock conduitMock.setReadData(HANDSHAKE_MSG, "read a lot"); // enable read on connectedChannelMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // attempt to read and write final Future writeFuture = triggerMultipleWriteThread("write a lot", "write a lot", "write a lot", "write it", "a lot", "write it down", "a lot"); final Future readFuture = triggerReadThread(54); Thread.sleep(20); conduitMock.setReadData(HANDSHAKE_MSG, HANDSHAKE_MSG); Thread.sleep(10); conduitMock.setReadData( "this is a lot", "lot", "lot", "lot", "lot", "lot", "lot", "lot"); Thread.sleep(10); conduitMock.setReadData("read a lot", HANDSHAKE_MSG); Thread.sleep(10); writeFuture.get(); sslChannel.shutdownWrites(); // FIXME workaround for bug found in SSLEngine assertFalse(sslChannel.flush()); conduitMock.setReadData(CLOSE_MSG); final ByteBuffer readBuffer = readFuture.get(); assertNotNull(readBuffer); // make sure that channel managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // shutdown reads sslChannel.shutdownReads(); sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); // close channel sslChannel.close(); // data expected to have been read from 'connectedChannelMock' by 'channel' so far assertReadMessage(readBuffer, "read a lot", "this is a lot", "lot", "lot", "lot" , "lot", "lot", "lot", "lot", "read a lot"); // data expected to have been written to 'connectedChannelMock' by 'channel' assertWrittenMessage(new String[]{HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, CLOSE_MSG}, new String[] {"write a lot", "write a lot", "write a lot", "write it", "a lot", "write it down", "a lot"}); } @Test public void readAndWriteWithConstantHandshakeAndMappedData() throws Exception { // map data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "HANDSHAKE_MSG"); engineMock.addWrapEntry("MockTest1", "MOCK 1"); engineMock.addWrapEntry("MockTest2", "MOCK 2"); engineMock.addWrapEntry("MockTest3", "MOCK 3"); engineMock.addWrapEntry("MockTest4", "MOCK 4"); engineMock.addWrapEntry(CLOSE_MSG, "CLOSE_MSG"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_WRAP, NEED_WRAP, NEED_UNWRAP, NEED_TASK, NEED_TASK, NEED_TASK, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION); // set ReadData on connectedChannelMock conduitMock.setReadData("HANDSHAKE_MSG", "MOCK 3"); // enable read on connectedChannelMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // attempt to read and write final Future writeFuture = triggerMultipleWriteThread("MockTest1", "MockTest2", "MockTest2", "MockTest1", "MockTest2", "MockTest3", "MockTest4"); final Future readFuture = triggerMultipleReadThread(99); Thread.sleep(40); conduitMock.setReadData("HANDSHAKE_MSG", "HANDSHAKE_MSG", "MOCK 3", "HANDSHAKE_MSG"); Thread.sleep(10); conduitMock.setReadData( "MOCK 2", "MOCK 2", "HANDSHAKE_MSG", "MOCK 4"); Thread.sleep(10); conduitMock.setReadData("MOCK 4", "MOCK 1", "MOCK 3", "MOCK 2", "MOCK 4"); Thread.sleep(10); conduitMock.setReadData("MOCK 1", "HANDSHAKE_MSG", "HANDSHAKE_MSG"); Thread.sleep(10); writeFuture.get(); sslChannel.shutdownWrites(); // FIXME workaround for bug found in SSLEngine assertFalse(sslChannel.flush()); conduitMock.setReadData("CLOSE_MSG"); final ByteBuffer readBuffer = readFuture.get(); assertNotNull(readBuffer); // make sure that channel managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // shutdown reads sslChannel.shutdownReads(); sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); // close channel sslChannel.close(); // make sure that channel managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // data expected to have been read from 'connectedChannelMock' by 'channel' so far assertReadMessage(readBuffer, "MockTest3", "MockTest3", "MockTest2", "MockTest2", "MockTest4", "MockTest4", "MockTest1", "MockTest3", "MockTest2", "MockTest4", "MockTest1"); // data expected to have been written to 'connectedChannelMock' by 'channel' assertWrittenMessage(new String[]{"HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "CLOSE_MSG"}, new String[] {"MOCK 1", "MOCK 2", "MOCK 2", "MOCK 1", "MOCK 2", "MOCK 3", "MOCK 4"}); } @Test public void readAndWriteWithIntercalatedHandshake() throws Exception { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, FINISH); // set ReadData on connectedChannelMock conduitMock.setReadData(HANDSHAKE_MSG, "read this", "read this", "read this", "read this", HANDSHAKE_MSG, "read this", HANDSHAKE_MSG, "read this"); // attempt to read and write final Future writeFuture = triggerMultipleWriteThread("write this", "write this", "write this", "write this", "write this"); final Future readFuture = triggerReadThread(54); // enable read on connectedChannelMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); writeFuture.get(); sslChannel.shutdownWrites(); // FIXME workaround for bug found in SSLEngine assertFalse(sslChannel.flush()); conduitMock.setReadData(CLOSE_MSG); final ByteBuffer readBuffer = readFuture.get(); assertNotNull(readBuffer); // make sure that channel managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // shutdown reads sslChannel.shutdownReads(); sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); // close channel sslChannel.close(); // make sure that channel managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // data expected to have been read from 'connectedChannelMock' by 'channel' so far assertReadMessage(readBuffer, "read this", "read this", "read this", "read this", "read this", "read this"); // data expected to have been written to 'connectedChannelMock' by 'channel' assertWrittenMessage(new String[]{HANDSHAKE_MSG, HANDSHAKE_MSG, CLOSE_MSG}, new String[] {"write this", "write this", "write this", "write this", "write this"}); } @Test public void readAndWriteWithIntercalatedHandshakeAndMappedData() throws Exception { // map all data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "[!@#$%^&*()_]"); engineMock.addWrapEntry("this", "read this"); engineMock.addWrapEntry("write this", "this"); engineMock.addWrapEntry(CLOSE_MSG, "[_)(*&^%$#@!]"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, FINISH); // set ReadData on connectedChannelMock conduitMock.setReadData("[!@#$%^&*()_]", "read this", "read this", "read this", "read this", "[!@#$%^&*()_]", "read this", "[!@#$%^&*()_]", "read this"); // enable read on connectedChannelMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // attempt to read and write final Future writeFuture = triggerMultipleWriteThread("write this", "write this", "write this", "write this", "write this"); final Future readFuture = triggerMultipleReadThread(24); writeFuture.get(); sslChannel.shutdownWrites(); // FIXME workaround for bug found in SSLEngine assertFalse(sslChannel.flush()); conduitMock.setReadData("[_)(*&^%$#@!]"); final ByteBuffer readBuffer = readFuture.get(); assertNotNull(readBuffer); // make sure that channel managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // shutdown reads sslChannel.shutdownReads(); sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); // close channel sslChannel.close(); // make sure that channel managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // data expected to have been read from 'connectedChannelMock' by 'channel' so far assertReadMessage(readBuffer, "this", "this", "this", "this", "this", "this"); // data expected to have been written to 'connectedChannelMock' by 'channel' assertWrittenMessage(new String[]{"[!@#$%^&*()_]", "[!@#$%^&*()_]", "[_)(*&^%$#@!]"}, new String[] {"this", "this", "this", "this", "this"}); } private Future triggerReadThread(int expectedReadLength) { ReadRunnable readRunnable = new ReadRunnable(expectedReadLength); Thread newThread = new Thread(readRunnable); newThread.start(); return readRunnable.getResultFuture(); } private Future triggerWriteThread(String... text) { WriteRunnable writeRunnable = new WriteRunnable(text); Thread newThread = new Thread(writeRunnable); newThread.start(); return writeRunnable.getResultFuture(); } private Future triggerMultipleReadThread(int expectedReadLength) { MultipleReadRunnable readRunnable = new MultipleReadRunnable(expectedReadLength); Thread newThread = new Thread(readRunnable); newThread.start(); return readRunnable.getResultFuture(); } private Future triggerMultipleWriteThread(String... text) { MultipleWriteRunnable writeRunnable = new MultipleWriteRunnable(text); Thread newThread = new Thread(writeRunnable); newThread.start(); return writeRunnable.getResultFuture(); } private class ReadRunnable implements Runnable { private ResultFuture resultFuture; private int expectedReadLength; public ReadRunnable(int expectedReadLength) { this.expectedReadLength = expectedReadLength; this.resultFuture = new ResultFuture(); } public Future getResultFuture() { return resultFuture; } @Override public void run() { final ByteBuffer buffer = ByteBuffer.allocate(100); final ByteBuffer[] buffers = new ByteBuffer[10]; for (int i = 0; i < 10; i++) { buffers[i] = ByteBuffer.allocate(10); } // attempt to read... channel is expected to read the entire message without any issues try { int totalLength = 0; long length = 0; while ((length = sslChannel.read(buffers)) >= 0) { totalLength += length; } assertEquals(-1, sslChannel.read(buffers, 0, 10)); assertEquals(-1, sslChannel.read(buffers, 0, 10)); assertEquals(-1, sslChannel.read(buffers, 0, 10)); for (ByteBuffer b: buffers) { b.flip(); } Buffers.copy(buffer, buffers, 0, 10); buffer.flip(); assertEquals("This is what we read '" + Buffers.getModifiedUtf8(buffer) + "'", expectedReadLength, totalLength); } catch (IOException e) { throw new RuntimeException("Unexpected IOException while reading", e); } resultFuture.setResult(buffer); } } private class WriteRunnable implements Runnable { private ResultFuture resultFuture; private String[] text; public WriteRunnable(String... text) { this.text = text; this.resultFuture = new ResultFuture(); } public Future getResultFuture() { return resultFuture; } @Override public void run() { final ByteBuffer[] buffer = new ByteBuffer[text.length]; int totalBytes = 0; try { for (int i = 0; i < text.length; i++) { // attempt to write... channel is expected to write the entire message without any issues buffer[i] = ByteBuffer.allocate(50); buffer[i].put(text[i].getBytes("UTF-8")).flip(); totalBytes += text[i].length(); } final int attemptsLimit = 10000; int attempts = 0; long bytes = 0; while ((bytes += sslChannel.write(buffer)) < totalBytes && (++ attempts) < attemptsLimit); assertEquals(totalBytes, bytes); } catch (IOException e) { throw new RuntimeException("Unexpected exception while writing", e); } resultFuture.setResult(null); } } private class MultipleReadRunnable implements Runnable { private ResultFuture resultFuture; private int expectedReadLength; public MultipleReadRunnable(int expectedReadLength) { this.expectedReadLength = expectedReadLength; this.resultFuture = new ResultFuture(); } public Future getResultFuture() { return resultFuture; } @Override public void run() { final ByteBuffer buffer = ByteBuffer.allocate(100); // attempt to read... channel is expected to read the entire message without any issues try { int totalLength = 0; int length = 0; while ((length = sslChannel.read(buffer)) >= 0) { totalLength += length; } assertEquals(-1, sslChannel.read(buffer)); assertEquals(-1, sslChannel.read(buffer)); assertEquals(-1, sslChannel.read(buffer)); buffer.flip(); assertEquals("This is what we read '" + Buffers.getModifiedUtf8(buffer) + "'", expectedReadLength, totalLength); } catch (IOException e) { throw new RuntimeException("Unexpected IOException while reading", e); } resultFuture.setResult(buffer); } } private class MultipleWriteRunnable implements Runnable { private ResultFuture resultFuture; private String[] text; public MultipleWriteRunnable(String... text) { this.text = text; this.resultFuture = new ResultFuture(); } public Future getResultFuture() { return resultFuture; } @Override public void run() { final ByteBuffer buffer = ByteBuffer.allocate(100); try { // attempt to write... channel is expected to write the entire message without any issues for (String textStr: text) { buffer.put(textStr.getBytes("UTF-8")).flip(); int bytes = 0; while ((bytes = sslChannel.write(buffer)) == 0); assertEquals(textStr.length(), bytes); buffer.compact(); } } catch (IOException e) { throw new RuntimeException("Unexpected exception while writing", e); } resultFuture.setResult(null); } } private static class ResultFuture implements Future { private T result; private final CountDownLatch countDownLatch = new CountDownLatch(1); private final long delay; private final TimeUnit delayTimeUnit; ResultFuture() { delay = 500000L; delayTimeUnit = TimeUnit.MILLISECONDS; } @Override public boolean cancel(boolean mayInterruptIfRunning) { return false; } @Override public boolean isCancelled() { return false; } @Override public boolean isDone() { return result != null; } @Override public T get() throws InterruptedException, ExecutionException { try { return get(delay, delayTimeUnit); } catch (TimeoutException e) { throw new RuntimeException("Could not get start exception in " + delay + " " + delayTimeUnit + " timeout."); } } @Override public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { countDownLatch.await(timeout, unit); return result; } private void setResult(final T result) { this.result = result; countDownLatch.countDown(); } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/ConnectedSslStreamChannelWriteTestCase.java000066400000000000000000000553221257016060700317070ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.xnio.ssl.mock.SSLEngineMock.CLOSE_MSG; import static org.xnio.ssl.mock.SSLEngineMock.HANDSHAKE_MSG; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.FINISH; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_FAULTY_TASK; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_TASK; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_UNWRAP; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_WRAP; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.PERFORM_REQUESTED_ACTION; import java.io.IOException; import java.nio.ByteBuffer; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import org.jmock.integration.junit4.JMock; import org.jmock.integration.junit4.JUnitRuleMockery; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.xnio.ssl.mock.SSLEngineMock; /** * Test write operations on {@link JsseConnectedSslStreamChannel}. * * @author Flavia Rainone */ public class ConnectedSslStreamChannelWriteTestCase extends AbstractConnectedSslStreamChannelTest { @Rule public final JUnitRuleMockery context = new JUnitRuleMockery(); @Test public void writeWithoutHandshake() throws IOException { // no handshake actions for engineMock this time, meaning that it will just wrap and unwrap without any handshake // the message we want to write final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MockTest".getBytes("UTF-8")).flip(); // attempt to write... channel is expected to write the entire message without any issues assertEquals(8, sslChannel.write(buffer)); assertFalse(buffer.hasRemaining()); // channel should not be able to shutdown writes... for that, it must receive a close message sslChannel.shutdownWrites(); // FIXME workaround for bug found in SSLEngine assertFalse(sslChannel.flush()); // send the close message conduitMock.setReadData(CLOSE_MSG); conduitMock.enableReads(true); sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); // close channel sslChannel.close(); // data expected to have been written to 'conduitMock' by 'sslChannel' assertWrittenMessage("MockTest", CLOSE_MSG); } @Test public void writeWithoutHandshakeMappedWrap() throws IOException { // map the wrap engineMock.addWrapEntry("MockTest", "WRAPPED_MOCK_TEST"); // no handshake actions for engineMock this time, meaning that it will just wrap and unwrap without any handshake // the message we want to write final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MockTest".getBytes("UTF-8")).flip(); // attempt to write... channel is expected to write the entire message without any issues assertEquals(8, sslChannel.write(buffer)); assertFalse(buffer.hasRemaining()); // channel should not be able to shutdown writes... for that, it must receive a close message sslChannel.shutdownWrites(); // FIXME workaround for bug found in SSLEngine assertFalse(sslChannel.flush()); // send the close message conduitMock.setReadData(CLOSE_MSG); conduitMock.enableReads(true); sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); // close channel sslChannel.close(); // data expected to have bee written to 'conduitMock' by 'sslChannel' assertWrittenMessage("WRAPPED_MOCK_TEST", CLOSE_MSG); } @Test public void writeWithSimpleHandshake() throws IOException { // map all data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "handshake"); engineMock.addWrapEntry("MockTest", "mock test works!"); engineMock.addWrapEntry(CLOSE_MSG, "channel closed"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH); // set ReadData on conduitMock conduitMock.setReadData("handshake", "channel closed"); conduitMock.enableFlush(false); // message we want to write final ByteBuffer buffer = ByteBuffer.allocate(100); final ByteBuffer[] buffers = new ByteBuffer[]{buffer}; buffer.put("MockTest".getBytes("UTF-8")).flip(); // attempt to write... channel is expected to stop on NEED_WRAP, as flush is disabled on conduitMock assertEquals(0, sslChannel.write(buffers, 0, 1)); assertFalse(conduitMock.isFlushed()); conduitMock.enableFlush(true); assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); // attempt to write... channel is expected to stop on NEED_UNWRAP, as read on conduitMock is not available assertEquals(0, sslChannel.write(buffers, 0, 1)); assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); assertTrue(conduitMock.isFlushed()); // enable read, now read data will be available to JsseConnectedSslStreamChannel conduitMock.enableReads(true); // channel is expected to write all data from buffer assertEquals(8, sslChannel.write(new ByteBuffer[]{buffer, ByteBuffer.allocate(0)}, 0, 2)); assertFalse(buffer.hasRemaining()); // for coverage purposes, attempt to write empty buffers assertEquals(0, sslChannel.write(new ByteBuffer[]{buffer, ByteBuffer.allocate(0)}, 0, 2)); // channel should be able to shutdown writes sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); // close channel sslChannel.close(); // data expected to have been written to 'conduitMock' by 'sslChannel' assertWrittenMessage("handshake", "mock test works!", "channel closed"); } @Test public void writeWithTasklessHandshake() throws IOException { // map data to be read and written engineMock.addWrapEntry("MockTest", "{testWriteWithTasklessHandshake}"); engineMock.addWrapEntry(CLOSE_MSG, " _ "); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, FINISH); // set ReadData on conduitMock conduitMock.setReadData(SSLEngineMock.HANDSHAKE_MSG, " _ "); // message we want to write final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MockTest".getBytes("UTF-8")).flip(); // attempt to write... channel is expected to stop on NEED_UNWRAP, as read on conduitMock is not available assertEquals(0, sslChannel.write(buffer)); assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); // enable read, now read data will be available to JsseConnectedSslStreamChannel conduitMock.enableReads(true); // channel is expected to write all data from buffer assertEquals(8, sslChannel.write(buffer)); assertFalse(buffer.hasRemaining()); // channel should be able to shutdown writes sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); // close channel sslChannel.close(); // data expected to have been written to 'conduitMock' by 'sslChannel' assertWrittenMessage(HANDSHAKE_MSG, "{testWriteWithTasklessHandshake}", " _ "); } @Test public void multipleWritesWithSimpleHandshake() throws IOException { // map data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "{handshake data}"); engineMock.addWrapEntry("MockTest", "{data}"); engineMock.addWrapEntry(CLOSE_MSG, "{message closed}"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH); // set ReadData on conduitMock conduitMock.setReadData("{handshake data}"); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // message we want to write final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MockTest".getBytes("UTF-8")).flip(); // attempt to write... channel is expected to write all messages without any issues for (int i = 0; i < 10; i++) { while(buffer.hasRemaining()) { assertEquals(8, sslChannel.write(buffer)); assertFalse(buffer.hasRemaining()); } buffer.flip(); } // channel should not be able to shutdown writes... for that, it must receive a close message sslChannel.shutdownWrites(); // FIXME workaround for bug found in SSLEngine assertFalse(sslChannel.flush()); // send the close message conduitMock.setReadData("{message closed}"); conduitMock.enableReads(true); sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); // close channel sslChannel.close(); // data expected to have been written to 'conduitMock' by 'sslChannel' assertWrittenMessage("{handshake data}", "{data}", "{data}", "{data}", "{data}", "{data}", "{data}", "{data}", "{data}", "{data}", "{data}", "{message closed}"); } @Test public void writeWithConnectionWithoutReadData() throws IOException { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH); // message we want to write final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MockTest".getBytes("UTF-8")).flip(); // attempt to write several times... channel is expected to stop on NEED_UNWRAP, as read on conduitMock is disabled assertEquals(0, sslChannel.write(buffer)); assertEquals(0, sslChannel.write(buffer)); assertEquals(0, sslChannel.write(buffer)); // make sure that channel managed to do the WRAP and got stalled on NEED_UNWRAP handshake status assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); // channel should not be able to shutdown writes... for that, it must receive a close message sslChannel.shutdownWrites(); // FIXME workaround for bug found in SSLEngine assertFalse(sslChannel.flush()); // close channel sslChannel.close(); // data expected to have been written to 'conduitMock' by 'sslChannel' assertWrittenMessage(HANDSHAKE_MSG, CLOSE_MSG); } @Test public void writeWithConstantHandshake() throws IOException { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_WRAP, NEED_WRAP, NEED_UNWRAP, NEED_TASK, NEED_TASK, NEED_TASK, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION); // set ReadData on conduitMock conduitMock.setReadData(HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, CLOSE_MSG); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // messages we plan to write final ByteBuffer buffer1 = ByteBuffer.allocate(10); buffer1.put("MockTest1".getBytes("UTF-8")).flip(); final ByteBuffer buffer2 = ByteBuffer.allocate(10); buffer2.put("MockTest2".getBytes("UTF-8")).flip(); final ByteBuffer buffer3 = ByteBuffer.allocate(10); buffer3.put("MockTest3".getBytes("UTF-8")).flip(); final ByteBuffer buffer4 = ByteBuffer.allocate(10); buffer4.put("MockTest4".getBytes("UTF-8")).flip(); // attempt to write... channel is expected to write all messages without any issues despite the constant handshaking action assertEquals(9, sslChannel.write(buffer1)); assertFalse(buffer1.hasRemaining()); assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); // next handshake action is NEED_UNWRAP assertEquals(9, sslChannel.write(buffer2)); assertFalse(buffer2.hasRemaining()); assertSame(HandshakeStatus.NEED_WRAP, engineMock.getHandshakeStatus()); // next handshake action is NEED_WRAP assertEquals(9, sslChannel.write(buffer3)); assertFalse(buffer3.hasRemaining()); assertSame(HandshakeStatus.NEED_WRAP, engineMock.getHandshakeStatus()); // next handshake action is NEED_WRAP assertEquals(9, sslChannel.write(buffer4)); assertFalse(buffer4.hasRemaining()); // make sure that channel managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // channel should be able to shutdown writes sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); // close channel sslChannel.close(); // data expected to have been written to 'conduitMock' by 'sslChannel' assertWrittenMessage(HANDSHAKE_MSG, "MockTest1", HANDSHAKE_MSG, "MockTest2", HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, "MockTest3", HANDSHAKE_MSG, "MockTest4", CLOSE_MSG); } @Test public void writeWithConstantHandshakeAndMappedData() throws IOException { // map data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "HANDSHAKE_MSG"); engineMock.addWrapEntry("MockTest1", "MOCK 1"); engineMock.addWrapEntry("MockTest2", "MOCK 2"); engineMock.addWrapEntry("MockTest3", "MOCK 3"); engineMock.addWrapEntry("MockTest4", "MOCK 4"); engineMock.addWrapEntry(CLOSE_MSG, "CLOSE_MSG"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_WRAP, NEED_WRAP, NEED_UNWRAP, NEED_TASK, NEED_TASK, NEED_TASK, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION); // set ReadData on conduitMock conduitMock.setReadData("HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "CLOSE_MSG"); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // messages we plan to write final ByteBuffer buffer1 = ByteBuffer.allocate(10); buffer1.put("MockTest1".getBytes("UTF-8")).flip(); final ByteBuffer buffer2 = ByteBuffer.allocate(10); buffer2.put("MockTest2".getBytes("UTF-8")).flip(); final ByteBuffer buffer3 = ByteBuffer.allocate(10); buffer3.put("MockTest3".getBytes("UTF-8")).flip(); final ByteBuffer buffer4 = ByteBuffer.allocate(10); buffer4.put("MockTest4".getBytes("UTF-8")).flip(); // attempt to write... channel is expected to write all messages without any issues despite the constant handshaking action assertEquals(9, sslChannel.write(buffer1)); assertFalse(buffer1.hasRemaining()); assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); // next handshake action is NEED_UNWRAP assertEquals(9, sslChannel.write(buffer2)); assertFalse(buffer2.hasRemaining()); assertSame(HandshakeStatus.NEED_WRAP, engineMock.getHandshakeStatus()); // next handshake action is NEED_WRAP assertEquals(9, sslChannel.write(buffer3)); assertFalse(buffer3.hasRemaining()); assertSame(HandshakeStatus.NEED_WRAP, engineMock.getHandshakeStatus()); // next handshake action is NEED_WRAP assertEquals(9, sslChannel.write(buffer4)); assertFalse(buffer4.hasRemaining()); // make sure that channel managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // channel should be able to shutdown writes sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); // close channel sslChannel.close(); // data expected to have been written to 'conduitMock' by 'sslChannel' assertWrittenMessage("HANDSHAKE_MSG", "MOCK 1", "HANDSHAKE_MSG", "MOCK 2", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "MOCK 3", "HANDSHAKE_MSG", "MOCK 4", "CLOSE_MSG"); } @Test public void writeWithIntercalatedHandshake() throws IOException { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, PERFORM_REQUESTED_ACTION, NEED_WRAP, PERFORM_REQUESTED_ACTION, NEED_WRAP, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, NEED_TASK, PERFORM_REQUESTED_ACTION, PERFORM_REQUESTED_ACTION, FINISH); // set ReadData on conduitMock conduitMock.setReadData(HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, CLOSE_MSG); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // message we plan to write final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("write this".getBytes("UTF-8")).flip(); // attempt to write... channel is expected to write all messages without any issues despite the constant handshaking action for (int i = 0; i < 10; i++) { assertEquals("Failed at attempt to write number " + i, 10, sslChannel.write(buffer)); assertFalse(buffer.hasRemaining()); buffer.flip(); } // make sure that channel managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // channel should be able to shutdown writes sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); // close channel sslChannel.close(); // data expected to have been written to 'conduitMock' by 'sslChannel' assertWrittenMessage(HANDSHAKE_MSG, "write this", HANDSHAKE_MSG, "write this", HANDSHAKE_MSG, "write this", HANDSHAKE_MSG, "write this", "write this", "write this", "write this", "write this", "write this", "write this", CLOSE_MSG); } @Test public void writeWithIntercalatedHandshakeAndMappedData() throws IOException { // map all data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "[!@#$%^&*()_]"); engineMock.addWrapEntry("write this", "this"); engineMock.addWrapEntry(CLOSE_MSG, "[_)(*&^%$#@!]"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, PERFORM_REQUESTED_ACTION, NEED_WRAP, PERFORM_REQUESTED_ACTION, NEED_WRAP, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, NEED_TASK, PERFORM_REQUESTED_ACTION, PERFORM_REQUESTED_ACTION, FINISH); // set ReadData on conduitMock conduitMock.setReadData("[!@#$%^&*()_]", "[!@#$%^&*()_]", "[!@#$%^&*()_]", "[_)(*&^%$#@!]"); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // message we plan to write final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("write this".getBytes("UTF-8")).flip(); // attempt to write... channel is expected to write all messages without any issues despite the constant handshaking action for (int i = 0; i < 10; i++) { assertEquals("Failed at attempt to write number " + i, 10, sslChannel.write(buffer)); assertFalse(buffer.hasRemaining()); buffer.flip(); } // make sure that channel managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // channel should be able to shutdown writes sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); // close channel sslChannel.close(); // data expected to have been written to 'conduitMock' by 'sslChannel' assertWrittenMessage("[!@#$%^&*()_]", "this", "[!@#$%^&*()_]", "this", "[!@#$%^&*()_]", "this", "[!@#$%^&*()_]", "this", "this", "this", "this", "this", "this", "this", "[_)(*&^%$#@!]"); } @Test public void attemptToWriteWithFaultyTask() throws IOException { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_FAULTY_TASK); // message we plan to write final ByteBuffer buffer = ByteBuffer.allocate(21); buffer.put("write this if you can".getBytes("UTF-8")).flip(); // try to write a bunch of times, we will get an IOException at all of the times for (int i = 0; i < 10; i ++) { boolean failed = false; try { sslChannel.write(buffer); } catch (IOException expected) { failed = true; } assertTrue(failed); } } // FIXME @Test public void closeWithoutFlushing() throws IOException { ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("abc".getBytes("UTF-8")).flip(); sslChannel.write(buffer); sslChannel.close(); assertWrittenMessage("abc"); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/JsseSslStreamConnectionBufferOverflowTestCase.java000066400000000000000000000113531257016060700332770ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.nio.ByteBuffer; import javax.net.ssl.SSLSession; import org.jmock.Expectations; import org.jmock.Mockery; import org.jmock.integration.junit4.JUnit4Mockery; import org.jmock.lib.concurrent.Synchroniser; import org.junit.Before; import org.junit.Test; import org.xnio.BufferAllocator; import org.xnio.ByteBufferSlicePool; import org.xnio.Pool; import org.xnio.conduits.StreamSinkConduit; import org.xnio.conduits.StreamSourceConduit; import org.xnio.mock.ConduitMock; import org.xnio.mock.StreamConnectionMock; import org.xnio.ssl.mock.SSLEngineMock; import org.xnio.ssl.mock.SSLEngineMock.HandshakeAction; /** * Test the SSL connection in buffer overflow scenarios. * * @author Flavia Rainone * */ public class JsseSslStreamConnectionBufferOverflowTestCase { // mockery context protected Mockery context; // the pair of conduits to be tested protected StreamSinkConduit sinkConduit; protected StreamSourceConduit sourceConduit; // the underlying conduit used as a delegate by the conduits above protected ConduitMock conduitMock; // the SSLEngine mock, allows to test different engine behavior with channel protected SSLEngineMock engineMock; @Before public void createChannelMock() throws IOException { context = new JUnit4Mockery() {{ setThreadingPolicy(new Synchroniser()); }}; engineMock = new SSLEngineMockSmallPacketSize(context); final Pool socketBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 10, 160); final Pool applicationBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 10, 160); conduitMock = new ConduitMock(); final StreamConnectionMock connectionMock = new StreamConnectionMock(conduitMock); final JsseSslStreamConnection connection = new JsseSslStreamConnection(connectionMock, engineMock, socketBufferPool, applicationBufferPool, false); this.sinkConduit = connection.getSinkChannel().getConduit(); this.sourceConduit = connection.getSourceChannel().getConduit(); } @Test public void bufferOverflowOnWrite() throws IOException { boolean fail = false; final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("12345678901234567890".getBytes("UTF-8")).flip(); // attempt to write... conduit is expected to write to throw an IOException // SSLEngine required a bigger send buffer but out buffer was already big enough try { sinkConduit.write(buffer); } catch (IOException e) { fail = true; } assertTrue(fail); } @Test public void bufferOverflowOnRead() throws IOException { engineMock.setHandshakeActions(HandshakeAction.NEED_UNWRAP, HandshakeAction.FINISH); conduitMock.setReadData(SSLEngineMock.HANDSHAKE_MSG); conduitMock.enableReads(true); // attempt to read... conduit is expected to not be able to read the message because HANDSHAKE_MSG does not fit // in a 10 byte buffer assertEquals(0, sourceConduit.read(ByteBuffer.allocate(50))); } private static class SSLEngineMockSmallPacketSize extends SSLEngineMock { public SSLEngineMockSmallPacketSize (Mockery mockery) { super(mockery); } @Override public SSLSession getSession() { synchronized (mockery) { final SSLSession sessionMock = mockery.mock(SSLSession.class, "SmallPacketsSession"); mockery.checking(new Expectations() {{ oneOf(sessionMock).getPacketBufferSize(); will(returnValue(10)); oneOf(sessionMock).getApplicationBufferSize(); will(returnValue(5)); }}); return sessionMock; } } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/JsseSslStreamConnectionTestCase.java000066400000000000000000000716141257016060700304270ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.xnio.ssl.mock.SSLEngineMock.CLOSE_MSG; import static org.xnio.ssl.mock.SSLEngineMock.HANDSHAKE_MSG; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.FINISH; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_TASK; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_UNWRAP; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_WRAP; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.PERFORM_REQUESTED_ACTION; import java.io.IOException; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.ExecutionException; import java.util.concurrent.Future; import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeoutException; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import org.jmock.integration.junit4.JUnitRuleMockery; import org.junit.Ignore; import org.junit.Rule; import org.junit.Test; import org.xnio.Buffers; import org.xnio.ssl.mock.SSLEngineMock; /** * Test for concurrent read and write operations on a pair of connections. * * @author Flavia Rainone */ @Ignore // ignoring for now as these tests hang more consistently than they pass public class JsseSslStreamConnectionTestCase extends AbstractSslConnectionTest{ @Rule public final JUnitRuleMockery context = new JUnitRuleMockery(); @Test public void simpleReadAndWrite() throws Exception { // no handshake actions for engineMock this time, meaning it will just wrap and unwrap without any handshake // the message we want to write conduitMock.setReadData("read data"); conduitMock.enableReads(true); final Future readFuture = triggerReadThread(9); final Future writeFuture = triggerWriteThread("write data"); writeFuture.get(); conduitMock.setReadData(CLOSE_MSG); final ByteBuffer readBuffer = readFuture.get(); // FIXME: move terminateWrites to write thread, and terminateReads to read thread after the issue involving // those operations is worked around // MORE INFO: we have to terminate write and read only after conduit has read and written everything... // the mock here only mimics the behavior we find in SSLEngine implementation: the connection cannot do read // nor write after either read or write have been terminated sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); sourceConduit.terminateReads(); // data expected to have been copied to buffer by conduits assertReadMessage(readBuffer, "read data"); assertWrittenMessage("write data", CLOSE_MSG); } @Test public void readAndWriteMappedWrap() throws Exception { // map the wrap engineMock.addWrapEntry("a very long message", "BLABLABLABLABLABLABLA"); engineMock.addWrapEntry("short msg", "MSG"); // no handshake actions for engineMock this time, meaning that it will just wrap and unwrap without any handshake // the message we want to read conduitMock.setReadData("BLABLABLABLABLABLABLA"); conduitMock.enableReads(true); // attempt to read and write final Future writeFuture = triggerWriteThread("short msg", "short msg"); final Future readFuture = triggerReadThread(19); writeFuture.get(); conduitMock.setReadData(CLOSE_MSG); final ByteBuffer readBuffer = readFuture.get(); // conduits should be able to terminate reads and writes sourceConduit.terminateReads(); sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); // data expected to have been read to 'buffer' by 'sourceConduit'' assertReadMessage(readBuffer, "a very long message"); assertWrittenMessage("MSG", "MSG", CLOSE_MSG); } @Test public void readAndWriteWithSimpleHandshake() throws Exception { // map all data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "handshake"); engineMock.addWrapEntry("MockTest", "mock test works!"); engineMock.addWrapEntry(CLOSE_MSG, "channel closed"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH); // set ReadData on conduitMock, including the wrapped version of message we want to read conduitMock.setReadData("handshake", "mock test works!", "mock test works!"); conduitMock.enableReads(true); // attempt to read and write final Future writeFuture = triggerWriteThread("MockTest"); final Future readFuture = triggerReadThread(16); writeFuture.get(); conduitMock.setReadData("channel closed"); final ByteBuffer readBuffer = readFuture.get(); // conduits should be able to terminate reads and writes sourceConduit.terminateReads(); sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); assertReadMessage(readBuffer, "MockTest", "MockTest"); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage("handshake", "mock test works!", "channel closed"); } @Test public void readAndWriteWithTasklessHandshake() throws Exception { // map data to be read and written engineMock.addWrapEntry("Mock Test", "{testReadWriteWithTasklessHandshake}"); engineMock.addWrapEntry(CLOSE_MSG, " _ "); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, FINISH); // set ReadData on conduitMock conduitMock.setReadData(SSLEngineMock.HANDSHAKE_MSG, "{testReadWriteWithTasklessHandshake}"); conduitMock.enableReads(true); // attempt to read and write final Future writeFuture = triggerWriteThread("Mock Test", "Mock Test", "Mock Test", "Mock Test"); final Future readFuture = triggerReadThread(9); writeFuture.get(); conduitMock.setReadData(" _ "); final ByteBuffer readBuffer = readFuture.get(); // conduits should be able to terminate reads and writes sourceConduit.terminateReads(); sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); // data expected to have been read from 'conduitMock' by 'sourceConduit' assertReadMessage(readBuffer, "Mock Test"); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage(HANDSHAKE_MSG, "{testReadWriteWithTasklessHandshake}", "{testReadWriteWithTasklessHandshake}", "{testReadWriteWithTasklessHandshake}", "{testReadWriteWithTasklessHandshake}", " _ "); } @Test public void multipleFeedReadAndWriteWithSimpleHandshake() throws Exception { // map data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "{handshake data}"); engineMock.addWrapEntry("Mock Read/Write Test", "{data}"); engineMock.addWrapEntry("it works!", "{more data}"); engineMock.addWrapEntry(CLOSE_MSG, "{message closed}"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH); // set ReadData on conduitMock conduitMock.setReadData(); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // attempt to read and write final Future writeFuture = triggerWriteThread("it works!", "Mock Read/Write Test", "it works!", "Mock Read/Write Test", "it works!", "it works!", "Mock Read/Write Test"); final Future readFuture = triggerReadThread(67); Thread.sleep(20); conduitMock.setReadData("{handshake data}"); Thread.sleep(10); conduitMock.setReadData( "{data}", "{data}", "{more data}"); Thread.sleep(10); conduitMock.setReadData("{more data}", "{more data}"); Thread.sleep(10); writeFuture.get(); conduitMock.setReadData("{message closed}"); final ByteBuffer readBuffer = readFuture.get(); assertNotNull(readBuffer); // conduits should be able to terminate reads and writes sourceConduit.terminateReads(); sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); // data expected to have been read from 'conduitMock' by 'sourceConduit' so far assertReadMessage(readBuffer, "Mock Read/Write Test", "Mock Read/Write Test", "it works!", "it works!", "it works!"); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage("{handshake data}", "{more data}", "{data}", "{more data}", "{data}", "{more data}", "{more data}", "{data}", "{message closed}"); } @Test public void readAndWriteWithConstantHandshake() throws Exception { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_WRAP, NEED_WRAP, NEED_UNWRAP, NEED_TASK, NEED_TASK, NEED_TASK, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION); // set ReadData on conduitMock conduitMock.setReadData(HANDSHAKE_MSG, "read a lot"); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // attempt to read and write final Future writeFuture = triggerMultipleWriteThread("write a lot", "write a lot", "write a lot", "write it", "a lot", "write it down", "a lot"); final Future readFuture = triggerReadThread(54); Thread.sleep(20); conduitMock.setReadData(HANDSHAKE_MSG, HANDSHAKE_MSG); Thread.sleep(10); conduitMock.setReadData( "this is a lot", "lot", "lot", "lot", "lot", "lot", "lot", "lot"); Thread.sleep(10); conduitMock.setReadData("read a lot", HANDSHAKE_MSG); Thread.sleep(10); writeFuture.get(); sinkConduit.terminateWrites(); // FIXME workaround for bug found in SSLEngine assertFalse(sinkConduit.flush()); conduitMock.setReadData(CLOSE_MSG); final ByteBuffer readBuffer = readFuture.get(); assertNotNull(readBuffer); // make sure that the conduits managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // terminate reads sourceConduit.terminateReads(); sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); // data expected to have been read from 'conduitMock' by 'sourceConduit' so far assertReadMessage(readBuffer, "read a lot", "this is a lot", "lot", "lot", "lot" , "lot", "lot", "lot", "lot", "read a lot"); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage(new String[]{HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, CLOSE_MSG}, new String[] {"write a lot", "write a lot", "write a lot", "write it", "a lot", "write it down", "a lot"}); } @Test public void readAndWriteWithConstantHandshakeAndMappedData() throws Exception { // map data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "HANDSHAKE_MSG"); engineMock.addWrapEntry("MockTest1", "MOCK 1"); engineMock.addWrapEntry("MockTest2", "MOCK 2"); engineMock.addWrapEntry("MockTest3", "MOCK 3"); engineMock.addWrapEntry("MockTest4", "MOCK 4"); engineMock.addWrapEntry(CLOSE_MSG, "CLOSE_MSG"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_WRAP, NEED_WRAP, NEED_UNWRAP, NEED_TASK, NEED_TASK, NEED_TASK, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION); // set ReadData on conduitMock conduitMock.setReadData("HANDSHAKE_MSG", "MOCK 3"); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // attempt to read and write final Future writeFuture = triggerMultipleWriteThread("MockTest1", "MockTest2", "MockTest2", "MockTest1", "MockTest2", "MockTest3", "MockTest4"); final Future readFuture = triggerMultipleReadThread(99); Thread.sleep(40); conduitMock.setReadData("HANDSHAKE_MSG", "HANDSHAKE_MSG", "MOCK 3", "HANDSHAKE_MSG"); Thread.sleep(10); conduitMock.setReadData( "MOCK 2", "MOCK 2", "HANDSHAKE_MSG", "MOCK 4"); Thread.sleep(10); conduitMock.setReadData("MOCK 4", "MOCK 1", "MOCK 3", "MOCK 2", "MOCK 4"); Thread.sleep(10); conduitMock.setReadData("MOCK 1", "HANDSHAKE_MSG", "HANDSHAKE_MSG"); Thread.sleep(10); writeFuture.get(); sinkConduit.terminateWrites(); // FIXME workaround for bug found in SSLEngine assertFalse(sinkConduit.flush()); conduitMock.setReadData("CLOSE_MSG"); final ByteBuffer readBuffer = readFuture.get(); assertNotNull(readBuffer); // make sure that conduits managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // terminate reads sourceConduit.terminateReads(); sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); // make sure that conduits managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // data expected to have been read from 'conduitMock' by 'sourceConduit' so far assertReadMessage(readBuffer, "MockTest3", "MockTest3", "MockTest2", "MockTest2", "MockTest4", "MockTest4", "MockTest1", "MockTest3", "MockTest2", "MockTest4", "MockTest1"); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage(new String[]{"HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "CLOSE_MSG"}, new String[] {"MOCK 1", "MOCK 2", "MOCK 2", "MOCK 1", "MOCK 2", "MOCK 3", "MOCK 4"}); } @Test public void readAndWriteWithIntercalatedHandshake() throws Exception { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, FINISH); // set ReadData on conduitMock conduitMock.setReadData(HANDSHAKE_MSG, "read this", "read this", "read this", "read this", HANDSHAKE_MSG, "read this", HANDSHAKE_MSG, "read this"); // attempt to read and write final Future writeFuture = triggerMultipleWriteThread("write this", "write this", "write this", "write this", "write this"); final Future readFuture = triggerReadThread(54); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); writeFuture.get(); sinkConduit.terminateWrites(); // FIXME workaround for bug found in SSLEngine assertFalse(sinkConduit.flush()); conduitMock.setReadData(CLOSE_MSG); final ByteBuffer readBuffer = readFuture.get(); assertNotNull(readBuffer); // make sure that the conduits managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // terminate reads sourceConduit.terminateReads(); sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); // make sure that the conduits managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // data expected to have been read from 'conduitMock' by 'sourceConduit' so far assertReadMessage(readBuffer, "read this", "read this", "read this", "read this", "read this", "read this"); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage(new String[]{HANDSHAKE_MSG, HANDSHAKE_MSG, CLOSE_MSG}, new String[] {"write this", "write this", "write this", "write this", "write this"}); } @Test public void readAndWriteWithIntercalatedHandshakeAndMappedData() throws Exception { // map all data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "[!@#$%^&*()_]"); engineMock.addWrapEntry("this", "read this"); engineMock.addWrapEntry("write this", "this"); engineMock.addWrapEntry(CLOSE_MSG, "[_)(*&^%$#@!]"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, FINISH); // set ReadData on conduitMock conduitMock.setReadData("[!@#$%^&*()_]", "read this", "read this", "read this", "read this", "[!@#$%^&*()_]", "read this", "[!@#$%^&*()_]", "read this"); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // attempt to read and write final Future writeFuture = triggerMultipleWriteThread("write this", "write this", "write this", "write this", "write this"); final Future readFuture = triggerMultipleReadThread(24); writeFuture.get(); sinkConduit.terminateWrites(); // FIXME workaround for bug found in SSLEngine assertFalse(sinkConduit.flush()); conduitMock.setReadData("[_)(*&^%$#@!]"); final ByteBuffer readBuffer = readFuture.get(); assertNotNull(readBuffer); // make sure that the conduits managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // terminate reads sourceConduit.terminateReads(); sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); // make sure that the conduits managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // data expected to have been read from 'conduitMock' by 'sourceConduit' so far assertReadMessage(readBuffer, "this", "this", "this", "this", "this", "this"); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage(new String[]{"[!@#$%^&*()_]", "[!@#$%^&*()_]", "[_)(*&^%$#@!]"}, new String[] {"this", "this", "this", "this", "this"}); } private Future triggerReadThread(int expectedReadLength) { ReadRunnable readRunnable = new ReadRunnable(expectedReadLength); Thread newThread = new Thread(readRunnable); newThread.start(); return readRunnable.getResultFuture(); } private Future triggerWriteThread(String... text) { WriteRunnable writeRunnable = new WriteRunnable(text); Thread newThread = new Thread(writeRunnable); newThread.start(); return writeRunnable.getResultFuture(); } private Future triggerMultipleReadThread(int expectedReadLength) { MultipleReadRunnable readRunnable = new MultipleReadRunnable(expectedReadLength); Thread newThread = new Thread(readRunnable); newThread.start(); return readRunnable.getResultFuture(); } private Future triggerMultipleWriteThread(String... text) { MultipleWriteRunnable writeRunnable = new MultipleWriteRunnable(text); Thread newThread = new Thread(writeRunnable); newThread.start(); return writeRunnable.getResultFuture(); } private class ReadRunnable implements Runnable { private ResultFuture resultFuture; private int expectedReadLength; public ReadRunnable(int expectedReadLength) { this.expectedReadLength = expectedReadLength; this.resultFuture = new ResultFuture(); } public Future getResultFuture() { return resultFuture; } @Override public void run() { final ByteBuffer buffer = ByteBuffer.allocate(100); final ByteBuffer[] buffers = new ByteBuffer[10]; for (int i = 0; i < 10; i++) { buffers[i] = ByteBuffer.allocate(10); } // attempt to read... sourceConduit is expected to read the entire message without any issues try { int totalLength = 0; long length = 0; while ((length = sourceConduit.read(buffers, 0, 10)) >= 0) { totalLength += length; } assertEquals(-1, sourceConduit.read(buffers, 0, 10)); assertEquals(-1, sourceConduit.read(buffers, 0, 10)); assertEquals(-1, sourceConduit.read(buffers, 0, 10)); for (ByteBuffer b: buffers) { b.flip(); } Buffers.copy(buffer, buffers, 0, 10); buffer.flip(); assertEquals("This is what we read '" + Buffers.getModifiedUtf8(buffer) + "'", expectedReadLength, totalLength); } catch (IOException e) { throw new RuntimeException("Unexpected IOException while reading", e); } resultFuture.setResult(buffer); } } private class WriteRunnable implements Runnable { private ResultFuture resultFuture; private String[] text; public WriteRunnable(String... text) { this.text = text; this.resultFuture = new ResultFuture(); } public Future getResultFuture() { return resultFuture; } @Override public void run() { final ByteBuffer[] buffer = new ByteBuffer[text.length]; int totalBytes = 0; try { for (int i = 0; i < text.length; i++) { // attempt to write... sinkConduit is expected to write the entire message without any issues buffer[i] = ByteBuffer.allocate(50); buffer[i].put(text[i].getBytes("UTF-8")).flip(); totalBytes += text[i].length(); } final int attemptsLimit = 10000; int attempts = 0; long bytes = 0; while ((bytes += sinkConduit.write(buffer, 0, text.length)) < totalBytes && (++ attempts) < attemptsLimit); assertEquals(totalBytes, bytes); } catch (IOException e) { throw new RuntimeException("Unexpected exception while writing", e); } resultFuture.setResult(null); } } private class MultipleReadRunnable implements Runnable { private ResultFuture resultFuture; private int expectedReadLength; public MultipleReadRunnable(int expectedReadLength) { this.expectedReadLength = expectedReadLength; this.resultFuture = new ResultFuture(); } public Future getResultFuture() { return resultFuture; } @Override public void run() { final ByteBuffer buffer = ByteBuffer.allocate(100); // attempt to read... sourceConduit is expected to read the entire message without any issues try { int totalLength = 0; int length = 0; while ((length = sourceConduit.read(buffer)) >= 0) { totalLength += length; } assertEquals(-1, sourceConduit.read(buffer)); assertEquals(-1, sourceConduit.read(buffer)); assertEquals(-1, sourceConduit.read(buffer)); buffer.flip(); assertEquals("This is what we read '" + Buffers.getModifiedUtf8(buffer) + "'", expectedReadLength, totalLength); } catch (IOException e) { throw new RuntimeException("Unexpected IOException while reading", e); } resultFuture.setResult(buffer); } } private class MultipleWriteRunnable implements Runnable { private ResultFuture resultFuture; private String[] text; public MultipleWriteRunnable(String... text) { this.text = text; this.resultFuture = new ResultFuture(); } public Future getResultFuture() { return resultFuture; } @Override public void run() { final ByteBuffer buffer = ByteBuffer.allocate(100); try { // attempt to write... sinkConduit is expected to write the entire message without any issues for (String textStr: text) { buffer.put(textStr.getBytes("UTF-8")).flip(); int bytes = 0; while ((bytes = sinkConduit.write(buffer)) == 0); assertEquals(textStr.length(), bytes); buffer.compact(); } } catch (IOException e) { throw new RuntimeException("Unexpected exception while writing", e); } resultFuture.setResult(null); } } private static class ResultFuture implements Future { private T result; private final CountDownLatch countDownLatch = new CountDownLatch(1); private final long delay; private final TimeUnit delayTimeUnit; ResultFuture() { delay = 500000L; delayTimeUnit = TimeUnit.MILLISECONDS; } @Override public boolean cancel(boolean mayInterruptIfRunning) { return false; } @Override public boolean isCancelled() { return false; } @Override public boolean isDone() { return result != null; } @Override public T get() throws InterruptedException, ExecutionException { try { return get(delay, delayTimeUnit); } catch (TimeoutException e) { throw new RuntimeException("Could not get start exception in " + delay + " " + delayTimeUnit + " timeout."); } } @Override public T get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException { countDownLatch.await(timeout, unit); return result; } private void setResult(final T result) { this.result = result; countDownLatch.countDown(); } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/JsseSslStreamSinkConduitTestCase.java000066400000000000000000000555001257016060700305560ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.xnio.ssl.mock.SSLEngineMock.CLOSE_MSG; import static org.xnio.ssl.mock.SSLEngineMock.HANDSHAKE_MSG; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.FINISH; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_FAULTY_TASK; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_TASK; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_UNWRAP; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_WRAP; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.PERFORM_REQUESTED_ACTION; import java.io.IOException; import java.nio.ByteBuffer; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import org.jmock.integration.junit4.JUnitRuleMockery; import org.junit.Rule; import org.junit.Test; import org.xnio.ssl.mock.SSLEngineMock; /** * Test write operations on {@link JsseSslStreamSinkConduit}. * * @author Flavia Rainone */ public class JsseSslStreamSinkConduitTestCase extends AbstractSslConnectionTest { @Rule public final JUnitRuleMockery context = new JUnitRuleMockery(); @Test public void writeWithoutHandshake() throws IOException { // no handshake actions for engineMock this time, meaning that it will just wrap and unwrap without any handshake // the message we want to write final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MockTest".getBytes("UTF-8")).flip(); // attempt to write... conduit is expected to write the entire message without any issues assertEquals(8, sinkConduit.write(buffer)); assertFalse(buffer.hasRemaining()); // conduit should not be able to shutdown writes... for that, it must receive a close message sinkConduit.terminateWrites(); // FIXME workaround for bug found in SSLEngine assertFalse(sinkConduit.flush()); // send the close message conduitMock.setReadData(CLOSE_MSG); conduitMock.enableReads(true); sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); // close connection sourceConduit.terminateReads(); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage("MockTest", CLOSE_MSG); } @Test public void writeWithoutHandshakeMappedWrap() throws IOException { // map the wrap engineMock.addWrapEntry("MockTest", "WRAPPED_MOCK_TEST"); // no handshake actions for engineMock this time, meaning that it will just wrap and unwrap without any handshake // the message we want to write final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MockTest".getBytes("UTF-8")).flip(); // attempt to write... conduit is expected to write the entire message without any issues assertEquals(8, sinkConduit.write(buffer)); assertFalse(buffer.hasRemaining()); // conduit should not be able to shutdown writes... for that, it must receive a close message sinkConduit.terminateWrites(); // FIXME workaround for bug found in SSLEngine assertFalse(sinkConduit.flush()); // send the close message conduitMock.setReadData(CLOSE_MSG); conduitMock.enableReads(true); sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); // close connection sourceConduit.terminateReads(); // data expected to have bee written to 'conduitMock' by 'sinkConduit' assertWrittenMessage("WRAPPED_MOCK_TEST", CLOSE_MSG); } @Test public void writeWithSimpleHandshake() throws IOException { // map all data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "handshake"); engineMock.addWrapEntry("MockTest", "mock test works!"); engineMock.addWrapEntry(CLOSE_MSG, "channel closed"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH); // set ReadData on conduitMock conduitMock.setReadData("handshake", "channel closed"); conduitMock.enableFlush(false); // message we want to write final ByteBuffer buffer = ByteBuffer.allocate(100); final ByteBuffer[] buffers = new ByteBuffer[]{buffer}; buffer.put("MockTest".getBytes("UTF-8")).flip(); // attempt to write... conduit is expected to stop on NEED_WRAP, as flush is disabled on conduitMock assertEquals(0, sinkConduit.write(buffers, 0, 1)); assertFalse(conduitMock.isFlushed()); conduitMock.enableFlush(true); assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); // attempt to write... conduit is expected to stop on NEED_UNWRAP, as read on conduitMock is not available assertEquals(0, sinkConduit.write(buffers, 0, 1)); assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); assertTrue(conduitMock.isFlushed()); // enable read, now read data will be available to the source conduit conduitMock.enableReads(true); // conduit is expected to write all data from buffer assertEquals(8, sinkConduit.write(new ByteBuffer[]{buffer, ByteBuffer.allocate(0)}, 0, 2)); assertFalse(buffer.hasRemaining()); // for coverage purposes, attempt to write empty buffers assertEquals(0, sinkConduit.write(new ByteBuffer[]{buffer, ByteBuffer.allocate(0)}, 0, 2)); // conduit should be able to terminate writes sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); // close connection sourceConduit.terminateReads(); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage("handshake", "mock test works!", "channel closed"); } @Test public void writeWithTasklessHandshake() throws IOException { // map data to be read and written engineMock.addWrapEntry("MockTest", "{testWriteWithTasklessHandshake}"); engineMock.addWrapEntry(CLOSE_MSG, " _ "); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, FINISH); // set ReadData on conduitMock conduitMock.setReadData(SSLEngineMock.HANDSHAKE_MSG, " _ "); // message we want to write final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MockTest".getBytes("UTF-8")).flip(); // attempt to write... conduit is expected to stop on NEED_UNWRAP, as read on conduitMock is not available assertEquals(0, sinkConduit.write(buffer)); assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); // enable read, now read data will be available to the source conduit conduitMock.enableReads(true); // conduit is expected to write all data from buffer assertEquals(8, sinkConduit.write(buffer)); assertFalse(buffer.hasRemaining()); // conduit should be able to shutdown writes sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); // close connection sourceConduit.terminateReads(); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage(HANDSHAKE_MSG, "{testWriteWithTasklessHandshake}", " _ "); } @Test public void multipleWritesWithSimpleHandshake() throws IOException { // map data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "{handshake data}"); engineMock.addWrapEntry("MockTest", "{data}"); engineMock.addWrapEntry(CLOSE_MSG, "{message closed}"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH); // set ReadData on conduitMock conduitMock.setReadData("{handshake data}"); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // message we want to write final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MockTest".getBytes("UTF-8")).flip(); // attempt to write... conduit is expected to write all messages without any issues for (int i = 0; i < 10; i++) { while(buffer.hasRemaining()) { assertEquals(8, sinkConduit.write(buffer)); assertFalse(buffer.hasRemaining()); } buffer.flip(); } // conduit should not be able to terminate writes... for that, it must receive a close message sinkConduit.terminateWrites(); // FIXME workaround for bug found in SSLEngine assertFalse(sinkConduit.flush()); // send the close message conduitMock.setReadData("{message closed}"); conduitMock.enableReads(true); sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); // close connection sourceConduit.terminateReads(); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage("{handshake data}", "{data}", "{data}", "{data}", "{data}", "{data}", "{data}", "{data}", "{data}", "{data}", "{data}", "{message closed}"); } @Test public void writeWithConnectionWithoutReadData() throws IOException { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH); // message we want to write final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MockTest".getBytes("UTF-8")).flip(); // attempt to write several times... conduit is expected to stop on NEED_UNWRAP, as read on conduitMock is disabled assertEquals(0, sinkConduit.write(buffer)); assertEquals(0, sinkConduit.write(buffer)); assertEquals(0, sinkConduit.write(buffer)); // make sure that conduit managed to do the WRAP and got stalled on NEED_UNWRAP handshake status assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); // conduit should not be able to shutdown writes... for that, it must receive a close message sinkConduit.terminateWrites(); // FIXME workaround for bug found in SSLEngine assertFalse(sinkConduit.flush()); // close connection sourceConduit.terminateReads(); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage(HANDSHAKE_MSG, CLOSE_MSG); } @Test public void writeWithConstantHandshake() throws IOException { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_WRAP, NEED_WRAP, NEED_UNWRAP, NEED_TASK, NEED_TASK, NEED_TASK, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION); // set ReadData on conduitMock conduitMock.setReadData(HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, CLOSE_MSG); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // messages we plan to write final ByteBuffer buffer1 = ByteBuffer.allocate(10); buffer1.put("MockTest1".getBytes("UTF-8")).flip(); final ByteBuffer buffer2 = ByteBuffer.allocate(10); buffer2.put("MockTest2".getBytes("UTF-8")).flip(); final ByteBuffer buffer3 = ByteBuffer.allocate(10); buffer3.put("MockTest3".getBytes("UTF-8")).flip(); final ByteBuffer buffer4 = ByteBuffer.allocate(10); buffer4.put("MockTest4".getBytes("UTF-8")).flip(); // attempt to write... conduit is expected to write all messages without any issues despite the constant handshaking action assertEquals(9, sinkConduit.write(buffer1)); assertFalse(buffer1.hasRemaining()); assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); // next handshake action is NEED_UNWRAP assertEquals(9, sinkConduit.write(buffer2)); assertFalse(buffer2.hasRemaining()); assertSame(HandshakeStatus.NEED_WRAP, engineMock.getHandshakeStatus()); // next handshake action is NEED_WRAP assertEquals(9, sinkConduit.write(buffer3)); assertFalse(buffer3.hasRemaining()); assertSame(HandshakeStatus.NEED_WRAP, engineMock.getHandshakeStatus()); // next handshake action is NEED_WRAP assertEquals(9, sinkConduit.write(buffer4)); assertFalse(buffer4.hasRemaining()); // make sure that conduit managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // conduit should be able to shutdown writes sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); // close connection sourceConduit.terminateReads(); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage(HANDSHAKE_MSG, "MockTest1", HANDSHAKE_MSG, "MockTest2", HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, "MockTest3", HANDSHAKE_MSG, "MockTest4", CLOSE_MSG); } @Test public void writeWithConstantHandshakeAndMappedData() throws IOException { // map data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "HANDSHAKE_MSG"); engineMock.addWrapEntry("MockTest1", "MOCK 1"); engineMock.addWrapEntry("MockTest2", "MOCK 2"); engineMock.addWrapEntry("MockTest3", "MOCK 3"); engineMock.addWrapEntry("MockTest4", "MOCK 4"); engineMock.addWrapEntry(CLOSE_MSG, "CLOSE_MSG"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_WRAP, NEED_WRAP, NEED_UNWRAP, NEED_TASK, NEED_TASK, NEED_TASK, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION); // set ReadData on conduitMock conduitMock.setReadData("HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "CLOSE_MSG"); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // messages we plan to write final ByteBuffer buffer1 = ByteBuffer.allocate(10); buffer1.put("MockTest1".getBytes("UTF-8")).flip(); final ByteBuffer buffer2 = ByteBuffer.allocate(10); buffer2.put("MockTest2".getBytes("UTF-8")).flip(); final ByteBuffer buffer3 = ByteBuffer.allocate(10); buffer3.put("MockTest3".getBytes("UTF-8")).flip(); final ByteBuffer buffer4 = ByteBuffer.allocate(10); buffer4.put("MockTest4".getBytes("UTF-8")).flip(); // attempt to write... conduit is expected to write all messages without any issues despite the constant handshaking action assertEquals(9, sinkConduit.write(buffer1)); assertFalse(buffer1.hasRemaining()); assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); // next handshake action is NEED_UNWRAP assertEquals(9, sinkConduit.write(buffer2)); assertFalse(buffer2.hasRemaining()); assertSame(HandshakeStatus.NEED_WRAP, engineMock.getHandshakeStatus()); // next handshake action is NEED_WRAP assertEquals(9, sinkConduit.write(buffer3)); assertFalse(buffer3.hasRemaining()); assertSame(HandshakeStatus.NEED_WRAP, engineMock.getHandshakeStatus()); // next handshake action is NEED_WRAP assertEquals(9, sinkConduit.write(buffer4)); assertFalse(buffer4.hasRemaining()); // make sure that conduit managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // conduit should be able to terminate writes sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); // close connection sourceConduit.terminateReads(); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage("HANDSHAKE_MSG", "MOCK 1", "HANDSHAKE_MSG", "MOCK 2", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "MOCK 3", "HANDSHAKE_MSG", "MOCK 4", "CLOSE_MSG"); } @Test public void writeWithIntercalatedHandshake() throws IOException { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, PERFORM_REQUESTED_ACTION, NEED_WRAP, PERFORM_REQUESTED_ACTION, NEED_WRAP, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, NEED_TASK, PERFORM_REQUESTED_ACTION, PERFORM_REQUESTED_ACTION, FINISH); // set ReadData on conduitMock conduitMock.setReadData(HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, CLOSE_MSG); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // message we plan to write final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("write this".getBytes("UTF-8")).flip(); // attempt to write... conduit is expected to write all messages without any issues despite the constant handshaking action for (int i = 0; i < 10; i++) { assertEquals("Failed at attempt to write number " + i, 10, sinkConduit.write(buffer)); assertFalse(buffer.hasRemaining()); buffer.flip(); } // make sure that conduit managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // conduit should be able to terminate writes sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); // close connection sourceConduit.terminateReads(); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage(HANDSHAKE_MSG, "write this", HANDSHAKE_MSG, "write this", HANDSHAKE_MSG, "write this", HANDSHAKE_MSG, "write this", "write this", "write this", "write this", "write this", "write this", "write this", CLOSE_MSG); } @Test public void writeWithIntercalatedHandshakeAndMappedData() throws IOException { // map all data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "[!@#$%^&*()_]"); engineMock.addWrapEntry("write this", "this"); engineMock.addWrapEntry(CLOSE_MSG, "[_)(*&^%$#@!]"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, PERFORM_REQUESTED_ACTION, NEED_WRAP, PERFORM_REQUESTED_ACTION, NEED_WRAP, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, NEED_TASK, PERFORM_REQUESTED_ACTION, PERFORM_REQUESTED_ACTION, FINISH); // set ReadData on conduitMock conduitMock.setReadData("[!@#$%^&*()_]", "[!@#$%^&*()_]", "[!@#$%^&*()_]", "[_)(*&^%$#@!]"); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // message we plan to write final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("write this".getBytes("UTF-8")).flip(); // attempt to write... conduit is expected to write all messages without any issues despite the constant handshaking action for (int i = 0; i < 10; i++) { assertEquals("Failed at attempt to write number " + i, 10, sinkConduit.write(buffer)); assertFalse(buffer.hasRemaining()); buffer.flip(); } // make sure that conduit managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // conduit should be able to terminate writes sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); // close connection sourceConduit.terminateReads(); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage("[!@#$%^&*()_]", "this", "[!@#$%^&*()_]", "this", "[!@#$%^&*()_]", "this", "[!@#$%^&*()_]", "this", "this", "this", "this", "this", "this", "this", "[_)(*&^%$#@!]"); } @Test public void attemptToWriteWithFaultyTask() throws IOException { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_FAULTY_TASK); // message we plan to write final ByteBuffer buffer = ByteBuffer.allocate(21); buffer.put("write this if you can".getBytes("UTF-8")).flip(); // try to write a bunch of times, we will get an IOException at all of the times for (int i = 0; i < 10; i ++) { boolean failed = false; try { sinkConduit.write(buffer); } catch (IOException expected) { failed = true; } assertTrue(failed); } } @Test public void closeWithoutFlushing() throws IOException { ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("abc".getBytes("UTF-8")).flip(); sinkConduit.write(buffer); sourceConduit.terminateReads(); assertWrittenMessage("abc"); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/JsseSslStreamSourceConduitTestCase.java000066400000000000000000000435431257016060700311160ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.xnio.ssl.mock.SSLEngineMock.CLOSE_MSG; import static org.xnio.ssl.mock.SSLEngineMock.HANDSHAKE_MSG; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.FINISH; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_FAULTY_TASK; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_TASK; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_UNWRAP; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_WRAP; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.PERFORM_REQUESTED_ACTION; import java.io.IOException; import java.nio.ByteBuffer; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import org.jmock.integration.junit4.JMock; import org.jmock.integration.junit4.JUnitRuleMockery; import org.junit.Rule; import org.junit.Test; import org.junit.runner.RunWith; import org.xnio.ssl.mock.SSLEngineMock; /** * Test for read operations on {@link #JsseSslStreamSourceConduit}. * * @author Flavia Rainone */ public class JsseSslStreamSourceConduitTestCase extends AbstractSslConnectionTest{ @Rule public final JUnitRuleMockery context = new JUnitRuleMockery(); @Test public void readWithoutHandshake() throws IOException { // no handshake actions for engineMock this time, meaning it will just wrap and unwrap without any handshake // the message we want to write conduitMock.setReadData("MockTest", CLOSE_MSG); conduitMock.enableReads(true); final ByteBuffer buffer = ByteBuffer.allocate(100); // attempt to read... sourceConduit is expected to read the entire message without any issues assertEquals(8, sourceConduit.read(buffer)); // terminate reads sourceConduit.terminateReads(); // close connection sinkConduit.terminateWrites(); // data expected to have been copied to buffer by sourceConduit assertReadMessage(buffer, "MockTest"); } @Test public void readWithoutHandshakeMappedUnwrap() throws IOException { // map the wrap engineMock.addWrapEntry("MockTest", "WRAPPED_MOCK_TEST"); // no handshake actions for engineMock this time, meaning it will just wrap and unwrap without any handshake // the message we want to read conduitMock.setReadData("WRAPPED_MOCK_TEST", CLOSE_MSG); conduitMock.enableReads(true); // attempt to read... conduit is expected to read the entire message without any handshake issues final ByteBuffer buffer = ByteBuffer.allocate(100); assertEquals(8, sourceConduit.read(buffer)); // terminate reads sourceConduit.terminateReads(); // close connection sinkConduit.terminateWrites(); // data expected to have been read to 'buffer' by 'sourceConduit' assertReadMessage(buffer, "MockTest"); } @Test public void readWithSimpleHandshake() throws IOException { // map all data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "handshake"); engineMock.addWrapEntry("MockTest", "mock test works!"); engineMock.addWrapEntry(CLOSE_MSG, "channel closed"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH); // set ReadData on conduitMock, including the wrapped version of message we want to read conduitMock.setReadData("handshake", "mock test works!", "channel closed"); conduitMock.enableReads(true); // conduit is expected to read all data from conduitMock final ByteBuffer buffer = ByteBuffer.allocate(100); assertEquals(8, sourceConduit.read(buffer)); // terminate reads sourceConduit.terminateReads(); // close connection sinkConduit.terminateWrites(); assertReadMessage(buffer, "MockTest"); // data expected to have been written to 'conduitMock' by 'sourceConduit' assertWrittenMessage("handshake", "channel closed"); } @Test public void readWithTasklessHandshake() throws IOException { // map data to be read and written engineMock.addWrapEntry("Mock Test", "{testReadWithTasklessHandshake}"); engineMock.addWrapEntry(CLOSE_MSG, " _ "); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, FINISH); // set ReadData on conduitMock conduitMock.setReadData(SSLEngineMock.HANDSHAKE_MSG, "{testReadWithTasklessHandshake}", " _ "); conduitMock.enableReads(true); // conduit is expected to read "Mock Test" from conduitMock final ByteBuffer buffer = ByteBuffer.allocate(100); assertEquals(9, sourceConduit.read(buffer)); // conduit should be able to terminate reads sourceConduit.terminateReads(); // close connection sinkConduit.terminateWrites(); // data expected to have been read from 'conduitMock' by 'sourceConduit' assertReadMessage(buffer, "Mock Test"); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage(HANDSHAKE_MSG, " _ "); } @Test public void multipleReadsWithSimpleHandshake() throws IOException { // map data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "{handshake data}"); engineMock.addWrapEntry("Mock Read Test", "{data}"); engineMock.addWrapEntry("it works!", "{more data}"); engineMock.addWrapEntry(CLOSE_MSG, "{message closed}"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH); // set ReadData on conduitMock conduitMock.setReadData("{handshake data}", "{data}", "{data}", "{more data}"); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // try to read message final ByteBuffer buffer = ByteBuffer.allocate(30); assertEquals(30, sourceConduit.read(buffer)); // data expected to have been read from 'conduitMock' by 'sourceConduit' so far assertReadMessage(buffer, "Mock Read Test", "Mock Read Test", "it"); buffer.clear(); // set more read data conduitMock.setReadData("{data}", "{more data}"); conduitMock.enableReads(true); // and read again assertEquals(30, sourceConduit.read(buffer)); // data expected to have been read from 'conduitMock' by 'sourceConduit' assertReadMessage(buffer, " works!", "Mock Read Test", "it works!"); buffer.clear(); // set more read data conduitMock.setReadData("{more data}", "{message closed}"); conduitMock.enableReads(true); // and read again assertEquals(9, sourceConduit.read(buffer)); // data expected to have been read from 'conduitMock' by 'sourceConduit' assertReadMessage(buffer, "it works!"); buffer.clear(); // conduit should be able to terminate reads sourceConduit.terminateReads(); // close connection sinkConduit.terminateWrites(); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage("{handshake data}", "{message closed}"); } @Test public void readWithAbruptClose() throws IOException { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_UNWRAP, NEED_WRAP, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH); // message buffer final ByteBuffer buffer = ByteBuffer.allocate(100); conduitMock.setReadData(HANDSHAKE_MSG, CLOSE_MSG); conduitMock.enableReads(true); // attempt to read several times... conduit is expected to stop on the second NEED_UNWRAP action, as // conduitMock will read an abrupt CLOSE_MSG assertEquals(-1, sourceConduit.read(buffer)); assertEquals(-1, sourceConduit.read(buffer)); assertEquals(-1, sourceConduit.read(buffer)); // conduit should be able to terminate writes sourceConduit.terminateReads(); // close connection sinkConduit.terminateWrites(); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage(HANDSHAKE_MSG, CLOSE_MSG); } @Test public void readWithConstantHandshake() throws IOException { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_WRAP, NEED_WRAP, NEED_UNWRAP, NEED_TASK, NEED_TASK, NEED_TASK, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION); // set ReadData on conduitMock conduitMock.setReadData(HANDSHAKE_MSG, "read a lot", HANDSHAKE_MSG, " read a lot ", HANDSHAKE_MSG, "read a lot ", HANDSHAKE_MSG, " read a lot", CLOSE_MSG); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // try to read message final ByteBuffer buffer = ByteBuffer.allocate(10); assertEquals(10, sourceConduit.read(buffer)); assertReadMessage(buffer, "read a lot"); buffer.clear(); assertEquals(10, sourceConduit.read(buffer)); assertReadMessage(buffer, " read a lo"); buffer.clear(); assertEquals(10, sourceConduit.read(buffer)); assertReadMessage(buffer, "t read a l"); buffer.clear(); assertEquals(10, sourceConduit.read(buffer)); assertReadMessage(buffer, "ot read a"); buffer.clear(); assertEquals(4, sourceConduit.read(buffer)); assertReadMessage(buffer, " lot"); // make sure that conduit managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // terminate reads sourceConduit.terminateReads(); // close connection sinkConduit.terminateWrites(); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage(HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, HANDSHAKE_MSG, CLOSE_MSG); } @Test public void readWithConstantHandshakeAndMappedData() throws IOException { // map data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "HANDSHAKE_MSG"); engineMock.addWrapEntry("a lot", "read a lot"); engineMock.addWrapEntry("read", "read"); engineMock.addWrapEntry("lot", "a lot"); engineMock.addWrapEntry("nothing", "read nothing"); engineMock.addWrapEntry(CLOSE_MSG, "CLOSE_MSG"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, NEED_WRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_WRAP, NEED_WRAP, NEED_UNWRAP, NEED_TASK, NEED_TASK, NEED_TASK, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION); // set ReadData on conduitMock conduitMock.setReadData("HANDSHAKE_MSG", "read a lot", "a lot", "read", "HANDSHAKE_MSG", "a lot", "read a lot", "HANDSHAKE_MSG", "read nothing", "read a lot", "HANDSHAKE_MSG", "read nothing", "CLOSE_MSG"); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); // try to read message final ByteBuffer buffer = ByteBuffer.allocate(10); assertEquals(10, sourceConduit.read(buffer)); assertReadMessage(buffer, "a lot", "lot", "re"); buffer.clear(); assertEquals(10, sourceConduit.read(buffer)); assertReadMessage(buffer, "ad", "lot", "a lot"); buffer.clear(); assertEquals(10, sourceConduit.read(buffer)); assertReadMessage(buffer, "nothing", "a l"); buffer.clear(); assertEquals(9, sourceConduit.read(buffer)); assertReadMessage(buffer, "ot", "nothing"); buffer.clear(); // make sure that conduit managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // terminate reads sourceConduit.terminateReads(); // close connection sinkConduit.terminateWrites(); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage("HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "HANDSHAKE_MSG", "CLOSE_MSG"); } @Test public void readWithIntercalatedHandshake() throws IOException { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, FINISH); // set ReadData on conduitMock conduitMock.setReadData(HANDSHAKE_MSG, "read this", "read this", "read this", "read this", HANDSHAKE_MSG, "read this", HANDSHAKE_MSG, "read this", CLOSE_MSG); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); final ByteBuffer buffer = ByteBuffer.allocate(100); // attempt to read... conduit is expected to read the message assertEquals(54, sourceConduit.read(buffer)); // make sure that conduit managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // terminate reads sourceConduit.terminateReads(); // close connection sinkConduit.terminateWrites(); // data expected to have been read from 'conduitMock' by 'sourceConduit' assertReadMessage(buffer, "read this", "read this", "read this", "read this", "read this", "read this"); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage(HANDSHAKE_MSG, HANDSHAKE_MSG, CLOSE_MSG); } @Test public void readWithIntercalatedHandshakeAndMappedData() throws IOException { // map all data to be read and written engineMock.addWrapEntry(HANDSHAKE_MSG, "[!@#$%^&*()_]"); engineMock.addWrapEntry("this", "read this"); engineMock.addWrapEntry(CLOSE_MSG, "[_)(*&^%$#@!]"); // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_WRAP, NEED_UNWRAP, NEED_TASK, FINISH, PERFORM_REQUESTED_ACTION, NEED_WRAP, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, NEED_UNWRAP, PERFORM_REQUESTED_ACTION, FINISH); // set ReadData on conduitMock conduitMock.setReadData("[!@#$%^&*()_]", "read this", "read this", "read this", "read this", "[!@#$%^&*()_]", "read this", "[!@#$%^&*()_]", "read this", "[_)(*&^%$#@!]"); // enable read on conduitMock, meaning that data above will be available to be read right away conduitMock.enableReads(true); final ByteBuffer buffer = ByteBuffer.allocate(100); // attempt to read... conduit is expected to read the message assertEquals(24, sourceConduit.read(buffer)); // make sure that conduit managed to do the WRAP and there is no more handshake actions left assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); // terminate reads sourceConduit.terminateReads(); // close connection sinkConduit.terminateWrites(); // data expected to have been read from 'conduitMock' by 'sourceConduit' assertReadMessage(buffer, "this", "this", "this", "this", "this", "this"); // data expected to have been written to 'conduitMock' by 'sinkConduit' assertWrittenMessage("[!@#$%^&*()_]", "[!@#$%^&*()_]", "[_)(*&^%$#@!]"); } @Test public void attemptToReadWithFaultyTask() throws IOException { // set the handshake actions that engineMock will emulate engineMock.setHandshakeActions(NEED_FAULTY_TASK); // message we plan to write final ByteBuffer buffer = ByteBuffer.allocate(21); // try to write a bunch of times, we will get an IOException at all of the times for (int i = 0; i < 10; i ++) { boolean failed = false; try { sourceConduit.read(buffer); } catch (IOException expected) { failed = true; } assertTrue(failed); } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/JsseXnioSslTestCase.java000066400000000000000000000643441257016060700260730ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.lang.reflect.Field; import java.net.Inet4Address; import java.net.InetSocketAddress; import java.net.URL; import java.nio.channels.Channel; import java.util.concurrent.CancellationException; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLEngine; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.IoFuture; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.Sequence; import org.xnio.StreamConnection; import org.xnio.Xnio; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.BoundChannel; import org.xnio.channels.ConnectedSslStreamChannel; import org.xnio.channels.ConnectedStreamChannel; import org.xnio.mock.XnioWorkerMock; /** * Test for {@link JsseXnioSsl}. * * @author Flavia Rainone */ @SuppressWarnings("deprecation") public class JsseXnioSslTestCase { private static final Field setterField; private static final Field connectionEngineField; private static final Field conduitEngineField; private static final String KEY_STORE_PROPERTY = "javax.net.ssl.keyStore"; private static final String KEY_STORE_PASSWORD_PROPERTY = "javax.net.ssl.keyStorePassword"; private static final String TRUST_STORE_PROPERTY = "javax.net.ssl.trustStore"; private static final String TRUST_STORE_PASSWORD_PROPERTY = "javax.net.ssl.trustStorePassword"; private static final String DEFAULT_KEY_STORE = "keystore.jks"; private static final String DEFAULT_KEY_STORE_PASSWORD = "apiTest"; private static final int SERVER_PORT = 23456; static { try { Class delegateSetterClass = JsseXnioSslTestCase.class.getClassLoader().loadClass(ChannelListeners.class.getName()+ "$DelegatingSetter"); setterField = delegateSetterClass.getDeclaredField("setter"); setterField.setAccessible(true); connectionEngineField = JsseSslStreamConnection.class.getDeclaredField("sslConduitEngine"); connectionEngineField.setAccessible(true); conduitEngineField = JsseSslConduitEngine.class.getDeclaredField("engine"); conduitEngineField.setAccessible(true); } catch (ClassNotFoundException e) { throw new RuntimeException(e); } catch (NoSuchFieldException e) { throw new RuntimeException(e); } catch (SecurityException e) { throw new RuntimeException(e); } } @BeforeClass public static void setKeyStoreAndTrustStore() { final URL storePath = JsseXnioSslTestCase.class.getClassLoader().getResource(DEFAULT_KEY_STORE); if (System.getProperty(KEY_STORE_PROPERTY) == null) { System.setProperty(KEY_STORE_PROPERTY, storePath.getFile()); } if (System.getProperty(KEY_STORE_PASSWORD_PROPERTY) == null) { System.setProperty(KEY_STORE_PASSWORD_PROPERTY, DEFAULT_KEY_STORE_PASSWORD); } if (System.getProperty(TRUST_STORE_PROPERTY) == null) { System.setProperty(TRUST_STORE_PROPERTY, storePath.getFile()); } if (System.getProperty(TRUST_STORE_PASSWORD_PROPERTY) == null) { System.setProperty(TRUST_STORE_PASSWORD_PROPERTY, DEFAULT_KEY_STORE_PASSWORD); } } private InetSocketAddress serverAddress; private Xnio xnio; private XnioWorkerMock worker; private XnioSsl xnioSsl; @Before public void init() throws Exception { serverAddress = new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), SERVER_PORT); xnio = Xnio.getInstance("xnio-mock", JsseXnioSslTestCase.class.getClassLoader()); worker = (XnioWorkerMock) xnio.createWorker(OptionMap.EMPTY); xnioSsl = xnio.getSslProvider(OptionMap.EMPTY); } @Test public void testCreateSslConnectionServer() throws Exception { final TestChannelListener> openListener = new TestChannelListener>(); // IDEA thinks this is unchecked because of http://youtrack.jetbrains.net/issue/IDEA-59290 @SuppressWarnings("unchecked") final AcceptingChannel server = xnioSsl.createSslConnectionServer(worker, serverAddress, openListener, OptionMap.create(Options.REUSE_ADDRESSES, Boolean.TRUE, Options.WORKER_NAME, "dummy")); assertNotNull(server); // try accepting to make sure the listener is invoked assertNotNull(server.accept()); assertSame(server, openListener.getChannel()); assertEquals(serverAddress, server.getLocalAddress()); assertSame(worker, server.getWorker()); assertTrue(server.getOption(Options.REUSE_ADDRESSES)); assertEquals("dummy", server.getOption(Options.WORKER_NAME)); assertNull(server.getOption(Options.BROADCAST)); } @Test public void testCreateSslTcpServer() throws Exception { final TestChannelListener> openListener = new TestChannelListener>(); // IDEA thinks this is unchecked because of http://youtrack.jetbrains.net/issue/IDEA-59290 @SuppressWarnings("unchecked") final AcceptingChannel server = xnioSsl.createSslTcpServer(worker, serverAddress, openListener, OptionMap.create(Options.REUSE_ADDRESSES, Boolean.TRUE, Options.WORKER_NAME, "dummy")); assertNotNull(server); // try accepting to make sure the listener is correctly invoked final ConnectedStreamChannel channel = server.accept(); assertNotNull(channel); assertSame(server, openListener.getChannel()); assertSame(server, openListener.getChannel()); assertEquals(serverAddress, server.getLocalAddress()); assertSame(worker, server.getWorker()); assertTrue(server.getOption(Options.REUSE_ADDRESSES)); assertEquals("dummy", server.getOption(Options.WORKER_NAME)); assertNull(server.getOption(Options.BROADCAST)); } @Test public void testCreateSslConnectionServerWithDirectBuffers() throws Exception { //for (Provider p: Security.getProviders()) { // System.out.println("Provider " + p + " - " + p.getName()); //} //final TestListener listener = new TestListener(); xnioSsl = xnio.getSslProvider(OptionMap.create(Options.USE_DIRECT_BUFFERS, true)); // IDEA thinks this is unchecked because of http://youtrack.jetbrains.net/issue/IDEA-59290 @SuppressWarnings("unchecked") final AcceptingChannel server = xnioSsl.createSslConnectionServer(worker, serverAddress, null, OptionMap.create(Options.REUSE_ADDRESSES, Boolean.FALSE)); assertNotNull(server); final StreamConnection connection = server.accept(); assertNotNull(connection); // try calling the listener to make sure that openListener is invoked, i.e., testing that the openlistener is set correctly: assertEquals(serverAddress, server.getLocalAddress()); assertSame(worker, server.getWorker()); assertFalse(server.getOption(Options.REUSE_ADDRESSES)); assertNull(server.getOption(Options.WORKER_NAME)); } @Test public void testCreateSslTcpServerWithDirectBuffers() throws Exception { //for (Provider p: Security.getProviders()) { // System.out.println("Provider " + p + " - " + p.getName()); //} //final TestListener listener = new TestListener(); xnioSsl = xnio.getSslProvider(OptionMap.create(Options.USE_DIRECT_BUFFERS, true)); // IDEA thinks this is unchecked because of http://youtrack.jetbrains.net/issue/IDEA-59290 @SuppressWarnings("unchecked") final AcceptingChannel server = xnioSsl.createSslTcpServer(worker, serverAddress, null, OptionMap.create(Options.REUSE_ADDRESSES, Boolean.FALSE)); assertNotNull(server); ConnectedStreamChannel channel = server.accept(); assertNotNull(channel); // try calling the listener to make sure that openListener is invoked, i.e., testing that the openlistener is set correctly: assertEquals(serverAddress, server.getLocalAddress()); assertSame(worker, server.getWorker()); assertFalse(server.getOption(Options.REUSE_ADDRESSES)); assertNull(server.getOption(Options.WORKER_NAME)); } @Test public void connectSsl1() throws Exception { final TestChannelListener openListener = new TestChannelListener(); final IoFuture ioFuture = xnioSsl.openSslConnection(worker, serverAddress, openListener, OptionMap.EMPTY); final StreamConnection connection = ioFuture.get(); assertNotNull(connection); assertSame(connection, openListener.getChannel()); assertSame(worker, connection.getWorker()); assertNotNull(connection.getLocalAddress()); assertEquals(serverAddress, connection.getPeerAddress()); assertNull(connection.getOption(Options.ALLOW_BLOCKING)); assertNull(connection.getOption(Options.FILE_ACCESS)); assertNull(connection.getOption(Options.RECEIVE_BUFFER)); assertNull(connection.getOption(Options.STACK_SIZE)); } @Test public void connectSsl2() throws Exception { final TestChannelListener openListener = new TestChannelListener(); final TestChannelListener bindListener = new TestChannelListener(); xnioSsl = xnio.getSslProvider(OptionMap.create(Options.SSL_PROTOCOL, "TLSv1.2")); final IoFuture ioFuture = xnioSsl.openSslConnection(worker, serverAddress, openListener, bindListener, OptionMap.create(Options.KEEP_ALIVE, true)); final StreamConnection connection = ioFuture.get(); assertNotNull(connection); assertSame(connection, openListener.getChannel()); final BoundChannel boundChannel = bindListener.getChannel(); assertNotNull(boundChannel); assertSame(worker, connection.getWorker()); assertNotNull(connection.getLocalAddress()); assertSame(connection.getLocalAddress(), boundChannel.getLocalAddress()); assertEquals(serverAddress, connection.getPeerAddress()); assertTrue(connection.getOption(Options.KEEP_ALIVE)); assertTrue(boundChannel.getOption(Options.KEEP_ALIVE)); assertNull(connection.getOption(Options.ALLOW_BLOCKING)); assertNull(boundChannel.getOption(Options.ALLOW_BLOCKING)); assertNull(connection.getOption(Options.FILE_ACCESS)); assertNull(boundChannel.getOption(Options.FILE_ACCESS)); assertNull(connection.getOption(Options.RECEIVE_BUFFER)); assertNull(boundChannel.getOption(Options.RECEIVE_BUFFER)); assertNull(connection.getOption(Options.STACK_SIZE)); assertNull(boundChannel.getOption(Options.STACK_SIZE)); } @Test public void connectSsl3() throws Exception { final InetSocketAddress localAddress = new InetSocketAddress(500); final OptionMap.Builder builder = OptionMap.builder(); builder.set(Options.SSL_PROTOCOL, "TLSv1"); builder.set(Options.SSL_PROVIDER, "SunJSSE"); builder.set(Options.SSL_CLIENT_SESSION_CACHE_SIZE, 20000); builder.set(Options.SSL_CLIENT_SESSION_TIMEOUT, 80); builder.set(Options.SSL_SERVER_SESSION_CACHE_SIZE, 30000); builder.set(Options.SSL_SERVER_SESSION_TIMEOUT, 130); final TestChannelListener openListener = new TestChannelListener(); xnioSsl = xnio.getSslProvider(builder.getMap()); final IoFuture ioFuture = xnioSsl.openSslConnection(worker, localAddress , serverAddress, openListener, OptionMap.create(Options.TCP_NODELAY, true)); final StreamConnection connection = ioFuture.get(); assertNotNull(connection); assertSame(connection, openListener.getChannel()); assertSame(worker, connection.getWorker()); assertEquals(localAddress, connection.getLocalAddress()); assertEquals(serverAddress, connection.getPeerAddress()); assertTrue(connection.getOption(Options.TCP_NODELAY)); final SSLEngine engine = (SSLEngine) conduitEngineField.get((JsseSslConduitEngine) connectionEngineField.get(connection)); assertTrue(engine.getEnableSessionCreation()); } @Test @Ignore public void connectSsl4() throws Exception { final InetSocketAddress localAddress = new InetSocketAddress(600); final TestChannelListener bindListener = new TestChannelListener(); final TestChannelListener openListener = new TestChannelListener(); final String[] enabledCipherSuites = new String[] {"SSL_DH_anon_WITH_RC4_128_MD5", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_RC4_128_MD5", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA", "nothing"}; final String[] validCipherSuites = new String[] {"SSL_DH_anon_WITH_RC4_128_MD5", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_RC4_128_MD5", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA"}; final String[] enabledProtocols = new String[] {"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "inexistent"}; final String[] validProtocols = new String[] {"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; final OptionMap.Builder optionMapBuilder = OptionMap.builder(); optionMapBuilder.set(Options.SSL_ENABLE_SESSION_CREATION, false); optionMapBuilder.set(Options.SSL_ENABLED_CIPHER_SUITES, Sequence.of(enabledCipherSuites)); optionMapBuilder.set(Options.MULTICAST, true); optionMapBuilder.set(Options.READ_TIMEOUT, 1000); optionMapBuilder.set(Options.SSL_ENABLED_PROTOCOLS, Sequence.of(enabledProtocols)); final IoFuture ioFuture = xnioSsl.openSslConnection(worker, localAddress, serverAddress, openListener, bindListener, optionMapBuilder.getMap()); final StreamConnection connection = ioFuture.get(); assertNotNull(connection); final BoundChannel boundChannel = bindListener.getChannel(); assertNotNull(boundChannel); assertSame(connection, openListener.getChannel()); assertSame(worker, connection.getWorker()); assertEquals(localAddress, connection.getLocalAddress()); assertEquals(localAddress, boundChannel.getLocalAddress()); assertTrue(connection.getOption(Options.MULTICAST)); assertTrue(boundChannel.getOption(Options.MULTICAST)); assertEquals(1000, (int) connection.getOption(Options.READ_TIMEOUT)); assertEquals(1000, (int) boundChannel.getOption(Options.READ_TIMEOUT)); final SSLEngine engine = (SSLEngine) conduitEngineField.get((JsseSslConduitEngine) connectionEngineField.get(connection)); assertFalse(engine.getEnableSessionCreation()); assertArrayEquals(validCipherSuites, engine.getEnabledCipherSuites()); assertArrayEquals(validProtocols, engine.getEnabledProtocols()); } @Test public void connectSslChannel1() throws Exception { final TestChannelListener openListener = new TestChannelListener(); final IoFuture ioFuture = xnioSsl.connectSsl(worker, serverAddress, openListener, OptionMap.EMPTY); final ConnectedStreamChannel channel = ioFuture.get(); assertNotNull(channel); assertSame(channel, openListener.getChannel()); assertSame(worker, channel.getWorker()); assertNotNull(channel.getLocalAddress()); assertEquals(serverAddress, channel.getPeerAddress()); assertNull(channel.getOption(Options.ALLOW_BLOCKING)); assertNull(channel.getOption(Options.FILE_ACCESS)); assertNull(channel.getOption(Options.RECEIVE_BUFFER)); assertNull(channel.getOption(Options.STACK_SIZE)); } @Test public void connectSslChannel2() throws Exception { final TestChannelListener openListener = new TestChannelListener(); final TestChannelListener bindListener = new TestChannelListener(); xnioSsl = xnio.getSslProvider(OptionMap.create(Options.SSL_PROTOCOL, "TLSv1.2")); final IoFuture ioFuture = xnioSsl.connectSsl(worker, serverAddress, openListener, bindListener, OptionMap.create(Options.KEEP_ALIVE, true)); final ConnectedStreamChannel channel = ioFuture.get(); assertNotNull(channel); assertSame(channel, openListener.getChannel()); final BoundChannel boundChannel = bindListener.getChannel(); assertNotNull(boundChannel); assertSame(worker, channel.getWorker()); assertNotNull(channel.getLocalAddress()); assertSame(channel.getLocalAddress(), boundChannel.getLocalAddress()); assertEquals(serverAddress, channel.getPeerAddress()); assertTrue(channel.getOption(Options.KEEP_ALIVE)); assertTrue(boundChannel.getOption(Options.KEEP_ALIVE)); assertNull(channel.getOption(Options.ALLOW_BLOCKING)); assertNull(boundChannel.getOption(Options.ALLOW_BLOCKING)); assertNull(channel.getOption(Options.FILE_ACCESS)); assertNull(boundChannel.getOption(Options.FILE_ACCESS)); assertNull(channel.getOption(Options.RECEIVE_BUFFER)); assertNull(boundChannel.getOption(Options.RECEIVE_BUFFER)); assertNull(channel.getOption(Options.STACK_SIZE)); assertNull(boundChannel.getOption(Options.STACK_SIZE)); } @Test public void connectSslChannel3() throws Exception { final InetSocketAddress localAddress = new InetSocketAddress(500); final OptionMap.Builder builder = OptionMap.builder(); builder.set(Options.SSL_PROTOCOL, "TLSv1"); builder.set(Options.SSL_PROVIDER, "SunJSSE"); builder.set(Options.SSL_CLIENT_SESSION_CACHE_SIZE, 20000); builder.set(Options.SSL_CLIENT_SESSION_TIMEOUT, 80); builder.set(Options.SSL_SERVER_SESSION_CACHE_SIZE, 30000); builder.set(Options.SSL_SERVER_SESSION_TIMEOUT, 130); final TestChannelListener openListener = new TestChannelListener(); xnioSsl = xnio.getSslProvider(builder.getMap()); final IoFuture ioFuture = xnioSsl.connectSsl(worker, localAddress , serverAddress, openListener, OptionMap.create(Options.TCP_NODELAY, true)); final ConnectedStreamChannel channel = ioFuture.get(); assertNotNull(channel); assertSame(channel, openListener.getChannel()); assertSame(worker, channel.getWorker()); assertEquals(localAddress, channel.getLocalAddress()); assertEquals(serverAddress, channel.getPeerAddress()); assertTrue(channel.getOption(Options.TCP_NODELAY)); } @Test public void connectSslChannel4() throws Exception { final InetSocketAddress localAddress = new InetSocketAddress(600); final TestChannelListener bindListener = new TestChannelListener(); final TestChannelListener openListener = new TestChannelListener(); final String[] enabledCipherSuites = new String[] {"SSL_DH_anon_WITH_RC4_128_MD5", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_RC4_128_MD5", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA", "nothing"}; final String[] validCipherSuites = new String[] {"SSL_DH_anon_WITH_RC4_128_MD5", "TLS_RSA_WITH_AES_128_CBC_SHA256", "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_RC4_128_MD5", "TLS_DHE_DSS_WITH_AES_128_CBC_SHA", "SSL_DHE_DSS_WITH_3DES_EDE_CBC_SHA", "SSL_RSA_WITH_3DES_EDE_CBC_SHA"}; final String[] enabledProtocols = new String[] {"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2", "inexistent"}; final String[] validProtocols = new String[] {"SSLv3", "TLSv1", "TLSv1.1", "TLSv1.2"}; final OptionMap.Builder optionMapBuilder = OptionMap.builder(); optionMapBuilder.set(Options.SSL_ENABLE_SESSION_CREATION, false); optionMapBuilder.set(Options.SSL_ENABLED_CIPHER_SUITES, Sequence.of(enabledCipherSuites)); optionMapBuilder.set(Options.MULTICAST, true); optionMapBuilder.set(Options.READ_TIMEOUT, 1000); optionMapBuilder.set(Options.SSL_ENABLED_PROTOCOLS, Sequence.of(enabledProtocols)); final IoFuture ioFuture = xnioSsl.connectSsl(worker, localAddress, serverAddress, openListener, bindListener, optionMapBuilder.getMap()); final ConnectedStreamChannel channel = ioFuture.get(); assertNotNull(channel); final BoundChannel boundChannel = bindListener.getChannel(); assertNotNull(boundChannel); assertSame(channel, openListener.getChannel()); assertSame(worker, channel.getWorker()); assertEquals(localAddress, channel.getLocalAddress()); assertEquals(localAddress, boundChannel.getLocalAddress()); assertTrue(channel.getOption(Options.MULTICAST)); assertTrue(boundChannel.getOption(Options.MULTICAST)); assertEquals(1000, (int) channel.getOption(Options.READ_TIMEOUT)); assertEquals(1000, (int) boundChannel.getOption(Options.READ_TIMEOUT)); } @Test public void failedConnection() throws Exception { worker.failConnection(); final IoFuture connectionFuture = xnioSsl.openSslConnection(worker, new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), SERVER_PORT), new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), SERVER_PORT), null, null, OptionMap.EMPTY); boolean failed = false; try { connectionFuture.get(); } catch (IOException e) { failed = true; } assertTrue(failed); failed = false; final IoFuture channelFuture = xnioSsl.connectSsl(worker, new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), SERVER_PORT), new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), SERVER_PORT), null, null, OptionMap.EMPTY); try { channelFuture.get(); } catch (IOException e) { failed = true; } assertTrue(failed); } @Test public void cancelledConnection() throws Exception { worker.cancelConnection(); final IoFuture connectionFuture = xnioSsl.openSslConnection(worker, new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), SERVER_PORT), new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), SERVER_PORT), null, null, OptionMap.EMPTY); boolean cancelled = false; try { connectionFuture.get(); } catch (CancellationException e) { cancelled = true; } assertTrue(cancelled); cancelled = false; final IoFuture channelFuture = xnioSsl.connectSsl(worker, new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), SERVER_PORT), new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), SERVER_PORT), null, null, OptionMap.EMPTY); try { channelFuture.get(); } catch (CancellationException e) { cancelled = true; } assertTrue(cancelled); } @Test public void getSslContext() throws Exception { final Xnio xnio = Xnio.getInstance("xnio-mock", JsseXnioSslTestCase.class.getClassLoader()); final JsseXnioSsl xnioSsl = (JsseXnioSsl) xnio.getSslProvider(OptionMap.EMPTY); SSLContext context = xnioSsl.getSslContext(); assertNotNull(context); } private static class TestChannelListener implements ChannelListener { private C channel; @Override public void handleEvent(C channel) { this.channel = channel; } public C getChannel() { return channel; } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/SslStreamConnectionValidationTestCase.java000066400000000000000000000303331257016060700316060ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import org.jmock.Expectations; import org.junit.After; import org.junit.Test; import org.xnio.BufferAllocator; import org.xnio.ByteBufferSlicePool; import org.xnio.Pool; import org.xnio.ssl.mock.SSLEngineMock; /** * Test invalid scenarios involving the SSL connection. * * @author Flavia Rainone * */ public class SslStreamConnectionValidationTestCase extends AbstractSslConnectionTest { @After @Override public void checkContext() { // do not check context... not all methods will be invoked on sessions created for invalid scenarios } @Test public void invalidSinkConduitConstructorParameters() { final JsseSslConduitEngine conduitEngine = createSslConduitEngine(sinkConduit, sourceConduit); // null next conduit boolean failed = false; try { new JsseSslStreamSinkConduit(null, conduitEngine, true); } catch (IllegalArgumentException e) { failed = true; } assertTrue(failed); // null ssl conduit engine failed = false; try { new JsseSslStreamSinkConduit(sinkConduit, null, true); } catch (IllegalArgumentException e) { failed = true; } assertTrue(failed); } @Test public void invalidSourceConduitConstructorParameters() { final JsseSslConduitEngine conduitEngine = createSslConduitEngine(sinkConduit, sourceConduit); // null next conduit boolean failed = false; try { new JsseSslStreamSourceConduit(null, conduitEngine, true); } catch (IllegalArgumentException e) { failed = true; } assertTrue(failed); // null ssl conduit engine failed = false; try { new JsseSslStreamSourceConduit(sourceConduit, null, true); } catch (IllegalArgumentException e) { failed = true; } assertTrue(failed); } @Test public void invalidConduitEngineParameters() { final JsseSslStreamConnection connection = (JsseSslStreamConnection) this.connection; final Pool socketBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 17000, 17000 * 16); final Pool applicationBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 17000, 17000 * 16); // null connection boolean failed = false; try { new JsseSslConduitEngine(null, sinkConduit, sourceConduit, engineMock, socketBufferPool, applicationBufferPool); } catch (IllegalArgumentException e) { failed = true; } assertTrue(failed); // null sinkConduit failed = false; try { new JsseSslConduitEngine(connection, null, sourceConduit, engineMock, socketBufferPool, applicationBufferPool); } catch (IllegalArgumentException e) { failed = true; } assertTrue(failed); // null source conduit failed = false; try { new JsseSslConduitEngine(connection, sinkConduit, null, engineMock, socketBufferPool, applicationBufferPool); } catch (IllegalArgumentException e) { failed = true; } assertTrue(failed); // null engine failed = false; try { new JsseSslConduitEngine(connection, sinkConduit, sourceConduit, null, socketBufferPool, applicationBufferPool); } catch (IllegalArgumentException e) { failed = true; } assertTrue(failed); // null socket buffer pool failed = false; try { new JsseSslConduitEngine(connection, sinkConduit, sourceConduit, engineMock, null, applicationBufferPool); } catch (IllegalArgumentException e) { failed = true; } assertTrue(failed); // null application buffer pool failed = false; try { new JsseSslConduitEngine(connection, sinkConduit, sourceConduit, engineMock, socketBufferPool, null); } catch (IllegalArgumentException e) { failed = true; } assertTrue(failed); // small length for socket buffer pool failed = false; final Pool smallBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 16000, 16000 * 16); try { new JsseSslConduitEngine(connection, sinkConduit, sourceConduit, engineMock, smallBufferPool, applicationBufferPool); } catch (IllegalArgumentException e) { failed = true; } assertTrue(failed); // socket buffer pool will create a good sized receiveBuffer, but a small sized sendBuffer failed = false; @SuppressWarnings("unchecked") final Pool invalidReadBufferPool = context.mock(Pool.class, "PoolByteBuffer allocates different buffer sizes"); context.checking(new Expectations() {{ oneOf(invalidReadBufferPool).allocate(); will(returnValue(socketBufferPool.allocate())); oneOf(invalidReadBufferPool).allocate(); will(returnValue(smallBufferPool.allocate())); }}); try { new JsseSslConduitEngine(connection, sinkConduit, sourceConduit, engineMock, invalidReadBufferPool, applicationBufferPool); } catch (IllegalArgumentException e) { failed = true; } assertTrue(failed); // applicationBufferPool creates buffers too short failed = false; try { new JsseSslConduitEngine(connection, sinkConduit, sourceConduit, engineMock, socketBufferPool, smallBufferPool); } catch (IllegalArgumentException e) { failed = true; } assertTrue(failed); // applicationBufferPool will produce a buffer that is greater than SslEngine.session's packet buffer size, // but smaller than SslEngine.session's application buffer size failed = false; final Pool mediumBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 16920, 16920 * 16); try { new JsseSslConduitEngine(connection, sinkConduit, sourceConduit, engineMock, socketBufferPool, mediumBufferPool); } catch (IllegalArgumentException e) { failed = true; } assertTrue(failed); } @Test public void writeAfterShutdown() throws IOException { conduitMock.setReadData(SSLEngineMock.CLOSE_MSG); conduitMock.enableReads(true); sinkConduit.terminateWrites(); final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("MSG!!!!!!!".getBytes("UTF-8")).flip(); boolean failed = false; try { sinkConduit.write(buffer); } catch (ClosedChannelException e) { failed = true; } assertTrue(failed); } @Test public void invalidWriteBufferArray() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("invalid".getBytes("UTF-8")).flip(); // the conduit should simply return 0 if length is 0 or a negative number assertEquals(0, sinkConduit.write(new ByteBuffer[]{buffer}, 0, 0)); assertEquals(0, sinkConduit.write(new ByteBuffer[]{buffer}, 0, -1)); // conduit should throw ArrayIndexOutOfBoundsException if position is < 0, or if length is larger than it should boolean failed = false; try { assertEquals(0, sinkConduit.write(new ByteBuffer[] { buffer }, -1, 1)); } catch (ArrayIndexOutOfBoundsException e) { failed = true; } assertTrue(failed); failed = false; try { assertEquals(0, sinkConduit.write(new ByteBuffer[] { buffer }, 0, 2)); } catch (ArrayIndexOutOfBoundsException e) { failed = true; } assertTrue(failed); } @Test public void writeNullBuffer() throws IOException { // null buffer boolean failed = false; try { sinkConduit.write((ByteBuffer) null); } catch (NullPointerException e) { failed = true; } assertTrue(failed); // null buffer array failed = false; try { sinkConduit.write((ByteBuffer[]) null, 4, 20); } catch (NullPointerException e) { failed = true; } assertTrue(failed); // null buffer in buffer array failed = false; try { sinkConduit.write(new ByteBuffer[] {null}, 0, 1); } catch (NullPointerException e) { failed = true; } assertTrue(failed); } @Test public void invalidReadBufferArray() throws IOException { conduitMock.setReadData("invalid read buffer array"); conduitMock.enableReads(true); final ByteBuffer buffer = ByteBuffer.allocate(10); // the conduit should simply return 0 if length is 0 assertEquals(0, sourceConduit.read(new ByteBuffer[]{buffer}, 0, 0)); // conduit should throw ArrayIndexOutOfBoundsException if offs or len is < 0, or if length is larger than it should boolean failed = false; try { assertEquals(0, sourceConduit.read(new ByteBuffer[]{buffer}, 0, -1)); } catch (ArrayIndexOutOfBoundsException e) { failed = true; } assertTrue(failed); failed = false; try { assertEquals(0, sourceConduit.read(new ByteBuffer[]{buffer}, -1, 1)); } catch (ArrayIndexOutOfBoundsException e) { failed = true; } assertTrue(failed); failed = false; try { assertEquals(0, sourceConduit.read(new ByteBuffer[]{buffer}, 0, 2)); } catch (ArrayIndexOutOfBoundsException e) { failed = true; } assertTrue(failed); failed = false; try { assertEquals(0, sourceConduit.read(new ByteBuffer[0], 0, 50)); } catch (ArrayIndexOutOfBoundsException e) { failed = true; } assertTrue(failed); } @Test public void readToNullBuffer() throws IOException { conduitMock.setReadData("null read buffer"); conduitMock.enableReads(true); // read to a null buffer boolean failed = false; try { sourceConduit.read((ByteBuffer) null); } catch (NullPointerException e) { failed = true; } assertTrue(failed); // read to a null buffer array failed = false; try { sourceConduit.read((ByteBuffer[]) null, 1, 3); } catch (NullPointerException e) { failed = true; } assertTrue(failed); // read to a null buffer in a buffer array failed = false; try { sourceConduit.read(new ByteBuffer[]{null}, 0, 1); } catch (NullPointerException e) { failed = true; } assertTrue(failed); } @Test public void terminateWritesCantFlush() throws IOException { conduitMock.enableFlush(false); ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("abc".getBytes("UTF-8")).flip(); sinkConduit.write(buffer); sinkConduit.terminateWrites(); assertWrittenMessage("abc", SSLEngineMock.CLOSE_MSG); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/StartTLSChannelTestCase.java000066400000000000000000000473371257016060700266230ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.xnio.ssl.mock.SSLEngineMock.CLOSE_MSG; import static org.xnio.ssl.mock.SSLEngineMock.HANDSHAKE_MSG; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.FINISH; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_UNWRAP; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_WRAP; import java.io.IOException; import java.nio.ByteBuffer; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import org.jmock.Expectations; import org.junit.Test; import org.xnio.BufferAllocator; import org.xnio.ByteBufferSlicePool; import org.xnio.ChannelListener; import org.xnio.Options; import org.xnio.Pool; import org.xnio.channels.AssembledConnectedSslStreamChannel; import org.xnio.channels.ConnectedSslStreamChannel; import org.xnio.channels.SslChannel; import org.xnio.ssl.mock.SSLEngineMock.HandshakeAction; /** * Test for AssembledConnectedSslStreamChannel on start tls mode. * * @author Flavia Rainone */ public class StartTLSChannelTestCase extends AbstractConnectedSslStreamChannelTest { @SuppressWarnings("unchecked") @Override protected ConnectedSslStreamChannel createSslChannel() { final Pool socketBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 17000, 17000 * 16); final Pool applicationBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 17000, 17000 * 16); SslConnection connection = new JsseSslStreamConnection(connectionMock, engineMock, socketBufferPool, applicationBufferPool, true); final ConnectedSslStreamChannel channel = new AssembledConnectedSslStreamChannel(connection, connection.getSourceChannel(), connection.getSinkChannel()); channel.getReadSetter().set(context.mock(ChannelListener.class, "read listener")); channel.getWriteSetter().set(context.mock(ChannelListener.class, "write listener")); return channel; } @Test public void getSecureOption() throws IOException { assertFalse(sslChannel.getOption(Options.SECURE)); sslChannel.startHandshake(); assertTrue(sslChannel.getOption(Options.SECURE)); } @Test public void getSslSession() throws IOException { assertNull(sslChannel.getSslSession()); sslChannel.startHandshake(); assertNotNull(sslChannel.getSslSession()); } @Test public void testSimpleFlush() throws IOException { // handshake action: NEED_WRAP conduitMock.enableWrites(true); final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MSG".getBytes("UTF-8")).flip(); assertEquals(3, sslChannel.write(buffer)); assertWrittenMessage("MSG"); assertFalse(conduitMock.isFlushed()); sslChannel.flush(); assertTrue(conduitMock.isFlushed()); assertWrittenMessage("MSG"); } @Test public void testFlushWithHandshaking() throws IOException { // handshake action: NEED_WRAP... this hanshake action will be ignored on START_TLS mode engineMock.setHandshakeActions(NEED_WRAP); conduitMock.enableWrites(true); final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MSG".getBytes("UTF-8")).flip(); assertEquals(3, sslChannel.write(buffer)); assertWrittenMessage("MSG"); assertFalse(conduitMock.isFlushed()); sslChannel.flush(); assertTrue(conduitMock.isFlushed()); assertWrittenMessage("MSG"); } @Test public void readNeedsWrapWriteAndReadDisabled() throws IOException { // handshake action: NEED_WRAP engineMock.setHandshakeActions(NEED_WRAP, FINISH); conduitMock.setReadData(CLOSE_MSG); conduitMock.enableReads(false); conduitMock.enableWrites(false); final ByteBuffer buffer = ByteBuffer.allocate(100); assertFalse(conduitMock.isReadAwaken()); sslChannel.resumeReads(); assertTrue(sslChannel.isReadResumed()); assertFalse(conduitMock.isReadAwaken()); assertFalse(conduitMock.isWriteResumed()); // attempt to read... channel is expected to return 0 as it stumbles upon a NEED_WRAP that cannot be executed assertEquals(0, sslChannel.read(new ByteBuffer[]{buffer})); // everything is kept the same assertTrue(conduitMock.isReadResumed()); assertTrue(sslChannel.isReadResumed()); assertFalse(conduitMock.isWriteResumed()); assertFalse(sslChannel.isWriteResumed()); // no handshake is performed assertSame(HandshakeStatus.NEED_WRAP, engineMock.getHandshakeStatus()); assertEquals(0, sslChannel.read(buffer)); assertSame(HandshakeStatus.NEED_WRAP, engineMock.getHandshakeStatus()); conduitMock.enableReads(true); assertEquals(7, sslChannel.read(buffer)); assertWrittenMessage(new String[0]); // close message is just read as a plain message, as sslChannel.read is simply delegated to conduitMock assertReadMessage(buffer, CLOSE_MSG); assertSame(HandshakeStatus.NEED_WRAP, engineMock.getHandshakeStatus()); sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); assertTrue(conduitMock.isWriteShutdown()); sslChannel.shutdownReads(); assertTrue(conduitMock.isReadShutdown()); conduitMock.enableWrites(true); sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); assertTrue(conduitMock.isWriteShutdown()); assertSame(HandshakeStatus.NEED_WRAP, engineMock.getHandshakeStatus()); assertWrittenMessage(new String[0]); assertTrue(conduitMock.isFlushed()); } @Test public void writeNeedsUnwrapReadAndFlushDisabled () throws IOException { // handshake action: NEED_WRAP engineMock.setHandshakeActions(NEED_UNWRAP, FINISH); conduitMock.setReadData(HANDSHAKE_MSG); conduitMock.enableReads(false); conduitMock.enableWrites(true); conduitMock.enableFlush(false); final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MSG".getBytes("UTF-8")).flip(); assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isWriteResumed()); // attempt to write... channel is expected to write because, on STARTLS mode, it wil simply delegate the // write request to conduitMock assertEquals(3, sslChannel.write(buffer)); // no read/write operation has been resumed either assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isWriteResumed()); // the first handshake action is as before, nothing has changed assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); assertFalse(sslChannel.flush()); assertWrittenMessage("MSG"); assertFalse(conduitMock.isFlushed()); conduitMock.enableFlush(true); assertTrue(sslChannel.flush()); assertWrittenMessage("MSG"); sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); assertWrittenMessage("MSG"); assertTrue(conduitMock.isFlushed()); } @Test public void cantForceResumeReadsOnResumedReadChannel() throws IOException { sslChannel.resumeReads(); sslChannel.resumeWrites(); assertTrue(sslChannel.isReadResumed()); assertTrue(sslChannel.isWriteResumed()); assertFalse(conduitMock.isReadAwaken()); assertFalse(conduitMock.isWriteAwaken()); engineMock.setHandshakeActions(NEED_UNWRAP); final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("COULDNT WRITE WITHOUT UNWRAP".getBytes("UTF-8")).flip(); assertEquals(28, sslChannel.write(buffer)); assertWrittenMessage("COULDNT WRITE WITHOUT UNWRAP"); assertTrue(sslChannel.isWriteResumed()); assertTrue(sslChannel.isReadResumed()); assertTrue(conduitMock.isWriteResumed()); assertFalse(conduitMock.isReadAwaken()); // everything keeps the same at conduitMock when we try to resume reads sslChannel.resumeWrites(); assertTrue(sslChannel.isWriteResumed()); assertTrue(sslChannel.isReadResumed()); assertTrue(conduitMock.isWriteResumed()); assertFalse(conduitMock.isReadAwaken()); } @Test public void cantForceResumeReadsOnSuspendedReadChannel() throws IOException { // resume writes, reads are suspended sslChannel.resumeWrites(); assertFalse(sslChannel.isReadResumed()); assertTrue(sslChannel.isWriteResumed()); assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isWriteAwaken()); // write needs to unwrap... try to write engineMock.setHandshakeActions(NEED_UNWRAP); final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("COULDNT WRITE WITHOUT UNWRAP".getBytes("UTF-8")).flip(); assertEquals(28, sslChannel.write(buffer)); assertWrittenMessage("COULDNT WRITE WITHOUT UNWRAP"); // nothing happens with read/write resumed on START_TLS channel assertTrue(sslChannel.isWriteResumed()); assertFalse(sslChannel.isReadResumed()); assertTrue(conduitMock.isWriteResumed()); assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isReadAwaken()); // everything keeps the same at conduitMock when we try to resume writes sslChannel.resumeWrites(); assertTrue(sslChannel.isWriteResumed()); assertFalse(sslChannel.isReadResumed()); assertTrue(conduitMock.isWriteResumed()); assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isReadAwaken()); } @Test public void resumeAndSuspendReadsOnNewChannel() throws Exception { // brand newly created sslChannel, isReadable returns aLWAYS and resuming read will awakeReads for conduitMock assertFalse(sslChannel.isReadResumed()); assertFalse(conduitMock.isReadResumed()); sslChannel.resumeReads(); assertTrue(sslChannel.isReadResumed()); assertFalse(conduitMock.isReadAwaken()); sslChannel.suspendReads(); assertFalse(sslChannel.isReadResumed()); assertFalse(conduitMock.isReadResumed()); } @Test public void resumeAndSuspendReads() throws IOException { assertEquals(0, sslChannel.read(ByteBuffer.allocate(5))); // not a brand newly created sslChannel, isReadable returns OKAY and resuming read will just reasumeReads for conduitMock assertFalse(sslChannel.isReadResumed()); assertFalse(conduitMock.isReadResumed()); sslChannel.resumeReads(); assertTrue(sslChannel.isReadResumed()); assertFalse(conduitMock.isReadAwaken()); assertTrue(conduitMock.isReadResumed()); sslChannel.suspendReads(); assertFalse(sslChannel.isReadResumed()); assertFalse(conduitMock.isReadResumed()); } @Test public void resumeAndSuspendWritesOnNewChannel() throws Exception { // brand newly created sslChannel, isWritable returns aLWAYS and resuming writes will awakeWrites for conduitMock assertFalse(sslChannel.isWriteResumed()); assertFalse(conduitMock.isWriteResumed()); sslChannel.resumeWrites(); assertTrue(sslChannel.isWriteResumed()); assertFalse(conduitMock.isWriteAwaken()); sslChannel.suspendWrites(); assertFalse(sslChannel.isWriteResumed()); assertFalse(conduitMock.isWriteResumed()); } @Test public void resumeAndSuspendWrites() throws Exception { assertEquals(0, sslChannel.read(ByteBuffer.allocate(5))); // not a brand newly created sslChannel, isWritable returns OKAY and resuming writes will just reasumeWritesfor conduitMock assertFalse(sslChannel.isWriteResumed()); assertFalse(conduitMock.isWriteResumed()); sslChannel.resumeWrites(); assertTrue(sslChannel.isWriteResumed()); assertFalse(conduitMock.isWriteAwaken()); assertTrue(conduitMock.isWriteResumed()); sslChannel.suspendWrites(); assertFalse(sslChannel.isWriteResumed()); assertFalse(conduitMock.isWriteResumed()); } @Test public void resumeAndSuspendWritesOnWriteNeedsUnwrapChannel() throws Exception { // create the read needs wrap channel\ engineMock.setHandshakeActions(HandshakeAction.NEED_UNWRAP, HandshakeAction.FINISH); ByteBuffer buffer = ByteBuffer.allocate(5); buffer.put("12345".getBytes("UTF-8")).flip(); // channel manages to write anyway, because we are on START_TLS mode assertEquals(5, sslChannel.write(new ByteBuffer[]{buffer})); assertWrittenMessage("12345"); // no read action is forced assertFalse(conduitMock.isReadResumed()); assertFalse(sslChannel.isReadResumed()); assertFalse(sslChannel.isWriteResumed()); assertFalse(conduitMock.isWriteResumed()); // try to resume writes sslChannel.resumeWrites(); assertTrue(sslChannel.isWriteResumed()); assertTrue(conduitMock.isWriteResumed()); sslChannel.suspendWrites(); assertFalse(sslChannel.isWriteResumed()); assertFalse(conduitMock.isWriteResumed()); } @Test public void suspendWritesOnResumedWriteNeedsUnwrapChannel() throws Exception { // resume writes first of all sslChannel.resumeWrites(); assertTrue(sslChannel.isWriteResumed()); assertTrue(conduitMock.isWriteResumed()); assertFalse(sslChannel.isReadResumed()); assertFalse(conduitMock.isReadResumed()); // need unwrap is the first handshake action, and conduitMock has read ops disabled engineMock.setHandshakeActions(HandshakeAction.NEED_UNWRAP, HandshakeAction.FINISH); // channel can write regardless of the NEED_UNWRAP handshake action, given START_TLS mode is on ByteBuffer buffer = ByteBuffer.allocate(1); buffer.put((byte) 0).flip(); assertEquals(1, sslChannel.write(buffer)); assertWrittenMessage("\0"); assertTrue(sslChannel.isWriteResumed()); assertTrue(conduitMock.isWriteResumed()); assertFalse(sslChannel.isReadResumed()); assertFalse(conduitMock.isReadResumed()); // suspendWrites sslChannel.suspendWrites(); assertFalse(sslChannel.isWriteResumed()); assertFalse(conduitMock.isWriteResumed()); } @SuppressWarnings("unchecked") @Test public void startTLSWithWriteNeedsUnwrap() throws IOException { //set a handshake listener final ChannelListener listener = context.mock(ChannelListener.class, "write needs unwrap"); context.checking(new Expectations() {{ atLeast(1).of(listener).handleEvent(sslChannel); }}); sslChannel.getHandshakeSetter().set(listener); // handshake action: NEED_WRAP engineMock.setHandshakeActions(NEED_UNWRAP, FINISH); conduitMock.setReadData(HANDSHAKE_MSG); conduitMock.enableReads(false); conduitMock.enableWrites(false); final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MSG".getBytes("UTF-8")).flip(); assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isWriteResumed()); // start tls sslChannel.startHandshake(); // attempt to write... channel is expected to return 0 as it stumbles upon a NEED_UNWRAP that cannot be executed assertEquals(0, sslChannel.write(buffer)); assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isWriteResumed()); assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); assertEquals(0, sslChannel.write(buffer)); assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); conduitMock.enableReads(true); assertEquals(3, sslChannel.write(buffer)); assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); assertWrittenMessage(new String[0]); assertFalse(sslChannel.flush()); assertWrittenMessage(new String[0]); sslChannel.shutdownWrites(); assertFalse(sslChannel.flush()); assertFalse(conduitMock.isWriteShutdown()); conduitMock.enableWrites(true); // FIXME workaround for bug found in SSLEngine assertFalse(sslChannel.flush()); assertFalse(conduitMock.isWriteShutdown()); conduitMock.setReadData(CLOSE_MSG); assertTrue(sslChannel.flush()); assertTrue(conduitMock.isWriteShutdown()); assertTrue(conduitMock.isOpen()); sslChannel.close(); assertFalse(conduitMock.isOpen()); assertWrittenMessage("MSG", CLOSE_MSG); assertTrue(conduitMock.isFlushed()); } @SuppressWarnings("unchecked") @Test public void startTLSWithReadNeedsWrap() throws IOException { //set a handshake listener final ChannelListener listener = context.mock(ChannelListener.class, "read needs unwrap"); context.checking(new Expectations() {{ atLeast(1).of(listener).handleEvent(sslChannel); }}); sslChannel.getHandshakeSetter().set(listener); // handshake action: NEED_WRAP engineMock.setHandshakeActions(NEED_WRAP, FINISH); conduitMock.setReadData("MSG"); conduitMock.enableReads(true); conduitMock.enableWrites(false); final ByteBuffer buffer = ByteBuffer.allocate(100); assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isWriteResumed()); // start tls sslChannel.startHandshake(); // attempt to write... channel is expected to return 0 as it stumbles upon a NEED_UNWRAP that cannot be executed assertEquals(0, sslChannel.read(buffer)); assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isWriteResumed()); assertSame(HandshakeStatus.FINISHED, engineMock.getHandshakeStatus()); conduitMock.enableWrites(true); assertEquals(3, sslChannel.read(new ByteBuffer[]{buffer})); assertReadMessage(buffer, "MSG"); assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); assertWrittenMessage(HANDSHAKE_MSG); assertTrue(sslChannel.flush()); assertWrittenMessage(HANDSHAKE_MSG); sslChannel.shutdownReads(); assertFalse(conduitMock.isWriteShutdown()); conduitMock.setReadData(CLOSE_MSG); sslChannel.shutdownWrites(); assertTrue(sslChannel.flush()); assertTrue(conduitMock.isWriteShutdown()); // channel not yet closed assertTrue(conduitMock.isOpen()); sslChannel.close(); assertFalse(conduitMock.isOpen()); assertWrittenMessage(HANDSHAKE_MSG, CLOSE_MSG); assertTrue(conduitMock.isFlushed()); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/StartTLSConnectionTestCase.java000066400000000000000000000512211257016060700273350ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.xnio.ssl.mock.SSLEngineMock.CLOSE_MSG; import static org.xnio.ssl.mock.SSLEngineMock.HANDSHAKE_MSG; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.FINISH; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_UNWRAP; import static org.xnio.ssl.mock.SSLEngineMock.HandshakeAction.NEED_WRAP; import java.io.IOException; import java.nio.ByteBuffer; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import org.jmock.Expectations; import org.junit.Test; import org.xnio.BufferAllocator; import org.xnio.ByteBufferSlicePool; import org.xnio.ChannelListener; import org.xnio.Options; import org.xnio.Pool; import org.xnio.mock.StreamConnectionMock; import org.xnio.ssl.mock.SSLEngineMock.HandshakeAction; /** * Test for SslConnection on start tls mode. * * @author Flavia Rainone */ public class StartTLSConnectionTestCase extends AbstractSslConnectionTest { @SuppressWarnings("unchecked") @Override protected SslConnection createSslConnection() { final Pool socketBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 17000, 17000 * 16); final Pool applicationBufferPool = new ByteBufferSlicePool(BufferAllocator.BYTE_BUFFER_ALLOCATOR, 17000, 17000 * 16); final StreamConnectionMock connectionMock = new StreamConnectionMock(conduitMock); SslConnection connection = new JsseSslStreamConnection(connectionMock, engineMock, socketBufferPool, applicationBufferPool, true); connection.getSourceChannel().getReadSetter().set(context.mock(ChannelListener.class, "read listener")); connection.getSinkChannel().getWriteSetter().set(context.mock(ChannelListener.class, "write listener")); return connection; } @Test public void getSecureOption() throws IOException { assertFalse(connection.getOption(Options.SECURE)); startHandshake(); assertTrue(connection.getOption(Options.SECURE)); } @Test public void getSslSession() throws IOException { assertNull(connection.getSslSession()); startHandshake(); assertNotNull(connection.getSslSession()); } @Test public void testSimpleFlush() throws IOException { // handshake action: NEED_WRAP conduitMock.enableWrites(true); final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MSG".getBytes("UTF-8")).flip(); assertEquals(3, sinkConduit.write(buffer)); assertWrittenMessage("MSG"); assertFalse(conduitMock.isFlushed()); sinkConduit.flush(); assertTrue(conduitMock.isFlushed()); assertWrittenMessage("MSG"); } @Test public void testFlushWithHandshaking() throws IOException { // handshake action: NEED_WRAP... this hanshake action will be ignored on START_TLS mode engineMock.setHandshakeActions(NEED_WRAP); conduitMock.enableWrites(true); final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MSG".getBytes("UTF-8")).flip(); assertEquals(3, sinkConduit.write(buffer)); assertWrittenMessage("MSG"); assertFalse(conduitMock.isFlushed()); sinkConduit.flush(); assertTrue(conduitMock.isFlushed()); assertWrittenMessage("MSG"); } @Test public void readNeedsWrapWriteAndReadDisabled() throws IOException { // handshake action: NEED_WRAP engineMock.setHandshakeActions(NEED_WRAP, FINISH); conduitMock.setReadData(CLOSE_MSG); conduitMock.enableReads(false); conduitMock.enableWrites(false); final ByteBuffer buffer = ByteBuffer.allocate(100); assertFalse(conduitMock.isReadAwaken()); sourceConduit.resumeReads(); assertTrue(sourceConduit.isReadResumed()); assertFalse(conduitMock.isReadAwaken()); assertFalse(conduitMock.isWriteResumed()); // attempt to read... channel is expected to return 0 as it stumbles upon a NEED_WRAP that cannot be executed assertEquals(0, sourceConduit.read(new ByteBuffer[]{buffer}, 0, 1)); // everything is kept the same assertTrue(conduitMock.isReadResumed()); assertTrue(sourceConduit.isReadResumed()); assertFalse(conduitMock.isWriteResumed()); assertFalse(sinkConduit.isWriteResumed()); // no handshake is performed assertSame(HandshakeStatus.NEED_WRAP, engineMock.getHandshakeStatus()); assertEquals(0, sourceConduit.read(buffer)); assertSame(HandshakeStatus.NEED_WRAP, engineMock.getHandshakeStatus()); conduitMock.enableReads(true); assertEquals(7, sourceConduit.read(buffer)); assertWrittenMessage(new String[0]); // close message is just read as a plain message, as sourceConduit.read is simply delegated to conduitMock assertReadMessage(buffer, CLOSE_MSG); assertSame(HandshakeStatus.NEED_WRAP, engineMock.getHandshakeStatus()); sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); assertTrue(conduitMock.isWriteShutdown()); sourceConduit.terminateReads(); assertTrue(conduitMock.isReadShutdown()); conduitMock.enableWrites(true); sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); assertTrue(conduitMock.isWriteShutdown()); assertSame(HandshakeStatus.NEED_WRAP, engineMock.getHandshakeStatus()); assertWrittenMessage(new String[0]); assertTrue(conduitMock.isFlushed()); } @Test public void writeNeedsUnwrapReadAndFlushDisabled () throws IOException { // handshake action: NEED_WRAP engineMock.setHandshakeActions(NEED_UNWRAP, FINISH); conduitMock.setReadData(HANDSHAKE_MSG); conduitMock.enableReads(false); conduitMock.enableWrites(true); conduitMock.enableFlush(false); final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MSG".getBytes("UTF-8")).flip(); assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isWriteResumed()); // attempt to write... channel is expected to write because, on STARTLS mode, it wil simply delegate the // write request to conduitMock assertEquals(3, sinkConduit.write(buffer)); // no read/write operation has been resumed either assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isWriteResumed()); // the first handshake action is as before, nothing has changed assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); assertFalse(sinkConduit.flush()); assertWrittenMessage("MSG"); assertFalse(conduitMock.isFlushed()); conduitMock.enableFlush(true); assertTrue(sinkConduit.flush()); assertWrittenMessage("MSG"); sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); assertWrittenMessage("MSG"); assertTrue(conduitMock.isFlushed()); } @Test public void cantForceResumeReadsOnResumedReadChannel() throws IOException { sourceConduit.resumeReads(); sinkConduit.resumeWrites(); assertTrue(sourceConduit.isReadResumed()); assertTrue(sinkConduit.isWriteResumed()); assertFalse(conduitMock.isReadAwaken()); assertFalse(conduitMock.isWriteAwaken()); engineMock.setHandshakeActions(NEED_UNWRAP); final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("COULDNT WRITE WITHOUT UNWRAP".getBytes("UTF-8")).flip(); assertEquals(28, sinkConduit.write(buffer)); assertWrittenMessage("COULDNT WRITE WITHOUT UNWRAP"); assertTrue(sinkConduit.isWriteResumed()); assertTrue(sourceConduit.isReadResumed()); assertTrue(conduitMock.isWriteResumed()); assertFalse(conduitMock.isReadAwaken()); // everything keeps the same at conduitMock when we try to resume reads sinkConduit.resumeWrites(); assertTrue(sinkConduit.isWriteResumed()); assertTrue(sourceConduit.isReadResumed()); assertTrue(conduitMock.isWriteResumed()); assertFalse(conduitMock.isReadAwaken()); } @Test public void cantForceResumeReadsOnSuspendedReadChannel() throws IOException { // resume writes, reads are suspended sinkConduit.resumeWrites(); assertFalse(sourceConduit.isReadResumed()); assertTrue(sinkConduit.isWriteResumed()); assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isWriteAwaken()); // write needs to unwrap... try to write engineMock.setHandshakeActions(NEED_UNWRAP); final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("COULDNT WRITE WITHOUT UNWRAP".getBytes("UTF-8")).flip(); assertEquals(28, sinkConduit.write(buffer)); assertWrittenMessage("COULDNT WRITE WITHOUT UNWRAP"); // nothing happens with read/write resumed on START_TLS channel assertTrue(sinkConduit.isWriteResumed()); assertFalse(sourceConduit.isReadResumed()); assertTrue(conduitMock.isWriteResumed()); assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isReadAwaken()); // everything keeps the same at conduitMock when we try to resume writes sinkConduit.resumeWrites(); assertTrue(sinkConduit.isWriteResumed()); assertFalse(sourceConduit.isReadResumed()); assertTrue(conduitMock.isWriteResumed()); assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isReadAwaken()); } @Test public void resumeAndSuspendReadsOnNewChannel() throws Exception { // brand newly created sslChannel, isReadable returns aLWAYS and resuming read will awakeReads for conduitMock assertFalse(sourceConduit.isReadResumed()); assertFalse(conduitMock.isReadResumed()); sourceConduit.resumeReads(); assertTrue(sourceConduit.isReadResumed()); assertFalse(conduitMock.isReadAwaken()); sourceConduit.suspendReads(); assertFalse(sourceConduit.isReadResumed()); assertFalse(conduitMock.isReadResumed()); } @Test public void resumeAndSuspendReads() throws IOException { assertEquals(0, sourceConduit.read(ByteBuffer.allocate(5))); // not a brand newly created sslChannel, isReadable returns OKAY and resuming read will just reasumeReads for conduitMock assertFalse(sourceConduit.isReadResumed()); assertFalse(conduitMock.isReadResumed()); sourceConduit.resumeReads(); assertTrue(sourceConduit.isReadResumed()); assertFalse(conduitMock.isReadAwaken()); assertTrue(conduitMock.isReadResumed()); sourceConduit.suspendReads(); assertFalse(sourceConduit.isReadResumed()); assertFalse(conduitMock.isReadResumed()); } @Test public void resumeAndSuspendWritesOnNewChannel() throws Exception { // brand newly created sslChannel, isWritable returns aLWAYS and resuming writes will awakeWrites for conduitMock assertFalse(sinkConduit.isWriteResumed()); assertFalse(conduitMock.isWriteResumed()); sinkConduit.resumeWrites(); assertTrue(sinkConduit.isWriteResumed()); assertFalse(conduitMock.isWriteAwaken()); sinkConduit.suspendWrites(); assertFalse(sinkConduit.isWriteResumed()); assertFalse(conduitMock.isWriteResumed()); } @Test public void resumeAndSuspendWrites() throws Exception { assertEquals(0, sourceConduit.read(ByteBuffer.allocate(5))); // not a brand newly created sslChannel, isWritable returns OKAY and resuming writes will just reasumeWritesfor conduitMock assertFalse(sinkConduit.isWriteResumed()); assertFalse(conduitMock.isWriteResumed()); sinkConduit.resumeWrites(); assertTrue(sinkConduit.isWriteResumed()); assertFalse(conduitMock.isWriteAwaken()); assertTrue(conduitMock.isWriteResumed()); sinkConduit.suspendWrites(); assertFalse(sinkConduit.isWriteResumed()); assertFalse(conduitMock.isWriteResumed()); } @Test public void resumeAndSuspendWritesOnWriteNeedsUnwrapChannel() throws Exception { // create the read needs wrap channel\ engineMock.setHandshakeActions(HandshakeAction.NEED_UNWRAP, HandshakeAction.FINISH); ByteBuffer buffer = ByteBuffer.allocate(5); buffer.put("12345".getBytes("UTF-8")).flip(); // channel manages to write anyway, because we are on START_TLS mode assertEquals(5, sinkConduit.write(new ByteBuffer[]{buffer}, 0, 1)); assertWrittenMessage("12345"); // no read action is forced assertFalse(conduitMock.isReadResumed()); assertFalse(sourceConduit.isReadResumed()); assertFalse(sinkConduit.isWriteResumed()); assertFalse(conduitMock.isWriteResumed()); // try to resume writes sinkConduit.resumeWrites(); assertTrue(sinkConduit.isWriteResumed()); assertTrue(conduitMock.isWriteResumed()); sinkConduit.suspendWrites(); assertFalse(sinkConduit.isWriteResumed()); assertFalse(conduitMock.isWriteResumed()); } @Test public void suspendWritesOnResumedWriteNeedsUnwrapChannel() throws Exception { // resume writes first of all sinkConduit.resumeWrites(); assertTrue(sinkConduit.isWriteResumed()); assertTrue(conduitMock.isWriteResumed()); assertFalse(sourceConduit.isReadResumed()); assertFalse(conduitMock.isReadResumed()); // need unwrap is the first handshake action, and conduitMock has read ops disabled engineMock.setHandshakeActions(HandshakeAction.NEED_UNWRAP, HandshakeAction.FINISH); // channel can write regardless of the NEED_UNWRAP handshake action, given START_TLS mode is on ByteBuffer buffer = ByteBuffer.allocate(1); buffer.put((byte) 0).flip(); assertEquals(1, sinkConduit.write(buffer)); assertWrittenMessage("\0"); assertTrue(sinkConduit.isWriteResumed()); assertTrue(conduitMock.isWriteResumed()); assertFalse(sourceConduit.isReadResumed()); assertFalse(conduitMock.isReadResumed()); // suspendWrites sinkConduit.suspendWrites(); assertFalse(sinkConduit.isWriteResumed()); assertFalse(conduitMock.isWriteResumed()); assertFalse(sourceConduit.isReadResumed()); assertFalse(conduitMock.isReadResumed()); } @SuppressWarnings("unchecked") @Test public void startTLSWithWriteNeedsUnwrap() throws IOException { //set a handshake listener final ChannelListener listener = context.mock(ChannelListener.class, "write needs unwrap"); context.checking(new Expectations() {{ atLeast(1).of(listener).handleEvent(connection); }}); connection.getHandshakeSetter().set(listener); // handshake action: NEED_WRAP engineMock.setHandshakeActions(NEED_UNWRAP, FINISH); conduitMock.setReadData(HANDSHAKE_MSG); conduitMock.enableReads(false); conduitMock.enableWrites(false); final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("MSG".getBytes("UTF-8")).flip(); assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isWriteResumed()); // start tls startHandshake(); // attempt to write... channel is expected to return 0 as it stumbles upon a NEED_UNWRAP that cannot be executed assertEquals(0, sinkConduit.write(buffer)); assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isWriteResumed()); assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); assertEquals(0, sinkConduit.write(buffer)); assertSame(HandshakeStatus.NEED_UNWRAP, engineMock.getHandshakeStatus()); conduitMock.enableReads(true); assertEquals(3, sinkConduit.write(buffer)); assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); assertWrittenMessage(new String[0]); assertFalse(sinkConduit.flush()); assertWrittenMessage(new String[0]); sinkConduit.terminateWrites(); assertFalse(sinkConduit.flush()); assertFalse(conduitMock.isWriteShutdown()); conduitMock.enableWrites(true); // FIXME workaround for bug found in SSLEngine assertFalse(sinkConduit.flush()); assertFalse(conduitMock.isWriteShutdown()); conduitMock.setReadData(CLOSE_MSG); assertTrue(sinkConduit.flush()); assertTrue(conduitMock.isWriteShutdown()); assertTrue(conduitMock.isOpen()); connection.close(); assertFalse(conduitMock.isOpen()); assertTrue(sourceConduit.isReadShutdown()); assertTrue(sinkConduit.isWriteShutdown()); assertTrue(conduitMock.isReadShutdown()); assertTrue(conduitMock.isWriteShutdown()); assertWrittenMessage("MSG", CLOSE_MSG); assertTrue(conduitMock.isFlushed()); } @SuppressWarnings("unchecked") @Test public void startTLSWithReadNeedsWrap() throws IOException { //set a handshake listener final ChannelListener listener = context.mock(ChannelListener.class, "read needs unwrap"); context.checking(new Expectations() {{ atLeast(1).of(listener).handleEvent(connection); }}); connection.getHandshakeSetter().set(listener); // handshake action: NEED_WRAP engineMock.setHandshakeActions(NEED_WRAP, FINISH); conduitMock.setReadData("MSG"); conduitMock.enableReads(true); conduitMock.enableWrites(false); final ByteBuffer buffer = ByteBuffer.allocate(100); assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isWriteResumed()); // start tls startHandshake(); // attempt to write... channel is expected to return 0 as it stumbles upon a NEED_UNWRAP that cannot be executed assertEquals(0, sourceConduit.read(buffer)); assertFalse(conduitMock.isReadResumed()); assertFalse(conduitMock.isWriteResumed()); assertSame(HandshakeStatus.FINISHED, engineMock.getHandshakeStatus()); conduitMock.enableWrites(true); assertEquals(3, sourceConduit.read(new ByteBuffer[]{buffer}, 0, 1)); assertReadMessage(buffer, "MSG"); assertSame(HandshakeStatus.NOT_HANDSHAKING, engineMock.getHandshakeStatus()); assertWrittenMessage(HANDSHAKE_MSG); assertTrue(sinkConduit.flush()); assertWrittenMessage(HANDSHAKE_MSG); sourceConduit.terminateReads(); assertFalse(conduitMock.isWriteShutdown()); conduitMock.setReadData(CLOSE_MSG); sinkConduit.terminateWrites(); assertTrue(sinkConduit.flush()); assertTrue(conduitMock.isWriteShutdown()); // channel is already closed assertTrue(conduitMock.isOpen()); assertFalse(sourceConduit.isReadShutdown()); assertTrue(sinkConduit.isWriteShutdown()); assertFalse(conduitMock.isReadShutdown()); assertTrue(conduitMock.isWriteShutdown()); connection.close(); assertFalse(conduitMock.isOpen()); assertTrue(sourceConduit.isReadShutdown()); assertTrue(sinkConduit.isWriteShutdown()); assertTrue(conduitMock.isReadShutdown()); assertTrue(conduitMock.isWriteShutdown()); assertWrittenMessage(HANDSHAKE_MSG, CLOSE_MSG); assertTrue(conduitMock.isFlushed()); } private void startHandshake() throws IOException { connection.startHandshake(); // update sinkConduits sinkConduit = connection.getSinkChannel().getConduit(); sourceConduit = connection.getSourceChannel().getConduit(); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/mock/000077500000000000000000000000001257016060700222665ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/mock/SSLContextMock.java000066400000000000000000000055431257016060700257600ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl.mock; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.security.SecureRandom; import javax.net.ssl.KeyManager; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLContextSpi; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLServerSocketFactory; import javax.net.ssl.SSLSessionContext; import javax.net.ssl.SSLSocketFactory; import javax.net.ssl.TrustManager; /** * A {@code SSLContext} mock. * * @author Flavia Rainone */ public class SSLContextMock extends SSLContext { public SSLContextMock(final SSLEngineMock sslEngine) throws NoSuchAlgorithmException { super(new SSLContextSpiMock(sslEngine), SSLContext.getDefault().getProvider(), SSLContext.getDefault().getProtocol()); } private static class SSLContextSpiMock extends SSLContextSpi { private final SSLEngineMock engineMock; public SSLContextSpiMock(SSLEngineMock sslEngine) { engineMock = sslEngine; } @Override protected SSLEngine engineCreateSSLEngine() { return engineMock; } @Override protected SSLEngine engineCreateSSLEngine(String host, int port) { return engineMock; } @Override protected SSLSessionContext engineGetClientSessionContext() { throw new RuntimeException("not implemented"); } @Override protected SSLSessionContext engineGetServerSessionContext() { throw new RuntimeException("not implemented"); } @Override protected SSLServerSocketFactory engineGetServerSocketFactory() { throw new RuntimeException("not implemented"); } @Override protected SSLSocketFactory engineGetSocketFactory() { throw new RuntimeException("not implemented"); } @Override protected void engineInit(KeyManager[] km, TrustManager[] tm, SecureRandom sr) throws KeyManagementException { throw new RuntimeException("not implemented"); } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/ssl/mock/SSLEngineMock.java000066400000000000000000000706231257016060700255420ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.ssl.mock; import java.nio.ByteBuffer; import java.util.HashMap; import java.util.Map; import javax.net.ssl.SSLEngine; import javax.net.ssl.SSLEngineResult; import javax.net.ssl.SSLEngineResult.HandshakeStatus; import javax.net.ssl.SSLEngineResult.Status; import javax.net.ssl.SSLException; import javax.net.ssl.SSLSession; import org.jmock.Expectations; import org.jmock.Mockery; import org.xnio.Buffers; /** * Mocks an SSLEngine for test purposes.

* The handshaking behavior of the mock is defined by a sequence of {@link HandshakeAction}s. On every request to wrap * or unwrap, this mock will take one of the predetermined actions, following the order those actions are {@link * #setHandshakeActions(HandshakeAction...) defined}. If an action cannot be performed at current wrap/unwrap request * (for example, take the case of a {@link HandshakeAction#NEED_WRAP NEED_WRAP} on an unwrap request), the resulting * {@code SSLEngineResult} will point that out and the action will be postponed to the next wrap/unwrap invocation, * until it can be executed. Only then, this mock will move on to the next handshake action. *

* Once this mock reaches the end of the handshake action list, it will no longer perform any handshaking, and will * always fulfill any wrap/unwrap request without failures. If this mock ever unwraps a {@link CLOSE_MSG}, it will * close itself and indicate in the future {@code SSLEngineResult}s it needs to wrap a {@link CLOSE_MSG} until requested * to wrap. *

* Invoking {@link #closeInbound} or {@link #closeOutbound} will also have the effect of closing this engine for both * wrap and unwrap. Notice that after {@code closeOutbound} is invoked, this engine will request to unwrap until it * unwraps a {@link CLOSE_MSG}, unless the engine has already done so. *

* Once closed, no handshake action is taken after this engine is closed, regardless of whether it has executed all * handshake actions or not. The only exception to this rule is that the engine can request to wrap, or unwrap a {@link * CLOSE_MSG} when that happens. *

To mimic wrap and unwrap, this mock uses a wrap/unwrap register. This register works like a map, containing what * is the wrapped equivalent of an unwrapped message and vice-versa. To use this register, you just have to call {@link * #addWrapEntry(String, String)} for every unwrapped/wrapped pair of messages you want to add. That way, when requested * to wrap a message this mock will search for the unwrapped message in its register. If the register contains the * message to be wrapped, this mock will use the wrapped version of it to write that message; if not, the engine will * simply copy the message. Likewise, if a message needs to be unwrapped, this mock will check if this message has a * corresponding wrapped version in the register. If it does, it will use the wrapped message. If not, it will simply * copy the message when wrapping. Each wrap entry can be defined by calling {@link #addWrapEntry(String, String)}. * * @author Flavia Rainone * */ public class SSLEngineMock extends SSLEngine { // every wrapped handshake message generated by this engine is the result of wrapping HANDSHAKE_MSG public static final String HANDSHAKE_MSG = "[handshake data]"; // every wrapped close message generated by this engine is the resujlt of wrapping CLOSE_MSG public static final String CLOSE_MSG = "[close]"; // mockery, to generate task mocks protected final Mockery mockery; // marks the index of current action private int actionIndex; // the sequence of handshake actions private HandshakeAction[] actions; // mapped wrapper, the unwrap/wrap register, performs wrap and unwrap private final MappedWrapper wrapper; // indicates if this engine is closed private boolean closed = false; // indicates if this engine has sent a wrapped CLOSE_MSG private boolean closeMessageWrapped = false; // indicates if this engine has unwrapped a CLOSE_MSG private boolean closeMessageUnwrapped = false; // supported cipher suites private String[] supportedCipherSuites = new String[0]; // supported protocols private String[] supportedProtocols = new String[0]; // enabled cipher suites private String[] enabledCipherSuites = null; // enabled protocols private String[] enabledProtocols = null; // indicates whether session creation is enabled private boolean enableSessionCreation = false; // client mode enabled private boolean useClientMode = false; // need client auth private boolean needClientAuth = false; // want client auth private boolean wantClientAuth = false; /** * Determines the handshake action this mock should take when requested to wrap/unwrap a message */ public static enum HandshakeAction { /** * Will not proceed until client requests this engine to wrap data. * The generated wrapped data will be {@link SSLEngineMock#HANDSHAKE_MSG}. */ NEED_WRAP, /** * Will not proceed until client requests this engine to unwrap non-empty data. * This engine expects to read {@link SSLEngineMock#HANDSHAKE_MSG}. */ NEED_UNWRAP, /** * Will not perform any related handshake action when requested to wrap/unwrap data. */ PERFORM_REQUESTED_ACTION, /** * A task is needed to be executed so handshake can proceed. */ NEED_TASK, /** * A task is needed to be executed so handshake can proceed. This mock will provide a faulty task, * one that will throw an exception when requested to execute. * TODO this action is not supported right now */ NEED_FAULTY_TASK, /** * Engine will finish the handshake. */ FINISH}; /** * Constructor. * * @param mockery mockery to create mocks for internal use */ public SSLEngineMock(Mockery mockery) { this.mockery = mockery; this.wrapper = new MappedWrapper(); this.actions = new HandshakeAction[0]; this.actionIndex = 0; } /** * Sets the handshake actions this engine will take when requested to wrap or unwrap a message. *

* Once all requested actions have been successfully performed, this mock will simply perform any requested action * without any handshaking, which is equivalent to executing a * {@link HandshakeAction#PERFORM_REQUESTED_ACTION PERFORM_REQUESTED_ACTION}. * * @param actions the actions that define the handshake behavior of this mock when it receives a request to unwrap * or wrap new data. */ public void setHandshakeActions(HandshakeAction... actions) { this.actions = actions; } /** * A wrap entry is a pair of texts representing an unwrapped data and its wrapped equivalent. * Once this wrap entry is added to this mock, this mock will start writing {@code wrappedData} whenever it is * requested to wrap {@code unwrappedData}, and it will write {@code unwrappedData} whenever requested to unwrap * {@code wrappedData}. * * @param unwrappedData unwrapped data * @param wrappedData the wrapped equivalent of {@code unwrappedData} */ public void addWrapEntry(String unwrappedData, String wrappedData) { wrapper.put(unwrappedData, wrappedData); } /** * Does nothing. */ @Override public void beginHandshake() throws SSLException { // do nothing } /** * Marks this engine as closed. */ @Override public void closeInbound() throws SSLException { closed = true; } /** * Marks this engine as closed. */ @Override public void closeOutbound() { closed = true; } // count used to differentiate delegated tasks (a requirement of JMock) private int taskCount = 0; /** * Returns:

    *
  • {@code null} if this engine is marked as closed, or if current action is not one of * {@link HandshakeAction#NEED_TASK NEED_TASK}, {@link HandshakeAction#NEED_FAULTY_TASK NEED_FAULTY_TASK}. *
  • a task mock if current action is {@link HandshakeAction#NEED_TASK NEED_TASK}. The mock expects to have its method * {@code run()} invoked exactly once by client *
  • a task mock whose {@code run()} method will throw an exception, if current action is {@link * HandshakeAction#NEED_FAULTY_TASK NEED_FAULTY_TASK}. The mock expects to have its method {@code run()} invoked exactly once. *
* */ @Override public synchronized Runnable getDelegatedTask() { if (!closed && actionIndex < actions.length) { switch (actions[actionIndex]) { case NEED_TASK: { actionIndex ++; synchronized (mockery){ final Runnable task = mockery.mock(Runnable.class, "RunnableMock" + taskCount++); mockery.checking(new Expectations() {{ oneOf(task).run(); }}); return task; } } case NEED_FAULTY_TASK: synchronized (mockery){ final Runnable task = mockery.mock(Runnable.class, "RunnableFaultyMock" + taskCount++); mockery.checking(new Expectations() {{ oneOf(task).run(); will(throwException(new RuntimeException())); }}); return task; } } } return null; } private int sessionCount = 0; @Override public SSLSession getSession() { synchronized (mockery) { final SSLSession sessionMock = mockery.mock(SSLSession.class, "Session" + sessionCount ++); if (sessionCount == 1) { mockery.checking(new Expectations() {{ oneOf(sessionMock).getPacketBufferSize(); will(returnValue(16916)); oneOf(sessionMock).getApplicationBufferSize(); will(returnValue(16921)); }}); } else { mockery.checking(new Expectations() {{ allowing(sessionMock).getPacketBufferSize(); will(returnValue(16916)); allowing(sessionMock).getApplicationBufferSize(); will(returnValue(16921)); }}); } return sessionMock; } } // this method avoids duplicate actionIndex increments for the same action private void actionAccountedFor(HandshakeAction action, int index) { synchronized(this) { if (actionIndex >= actions.length || closed) { return; } if (actionIndex == index && actions[actionIndex] == action) { actionIndex ++; } } } @Override public HandshakeStatus getHandshakeStatus() { final int currentIndex; synchronized (this) { if (closed) { if (!closeMessageWrapped) { return HandshakeStatus.NEED_WRAP; } if (!closeMessageUnwrapped) { return HandshakeStatus.NEED_UNWRAP; } } if (closed || actionIndex > actions.length) { return HandshakeStatus.NOT_HANDSHAKING; } currentIndex = actionIndex; } if(currentIndex >= actions.length) { return HandshakeStatus.NOT_HANDSHAKING; } switch(actions[currentIndex]) { case NEED_TASK: case NEED_FAULTY_TASK: return HandshakeStatus.NEED_TASK; case NEED_WRAP: return HandshakeStatus.NEED_WRAP; case NEED_UNWRAP: return HandshakeStatus.NEED_UNWRAP; case PERFORM_REQUESTED_ACTION: return HandshakeStatus.NOT_HANDSHAKING; case FINISH: return HandshakeStatus.FINISHED; default: throw new IllegalStateException("Unexpected handshake action: " + actions[currentIndex]); } } @Override public SSLEngineResult unwrap(ByteBuffer src, ByteBuffer[] dsts, int offset, int length) throws SSLException { for (int i = offset; i < length; i++) { if (dsts[i].hasRemaining()) { break; } else if (i == length -1) { return new SSLEngineResult(SSLEngineResult.Status.BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0); } } if (closed && closeMessageUnwrapped) { return new SSLEngineResult(Status.CLOSED, HandshakeStatus.NOT_HANDSHAKING, 0, 0); } final HandshakeStatus status; final int currentActionIndex; synchronized (this) { status = getHandshakeStatus(); currentActionIndex = actionIndex; } switch(status) { case FINISHED: actionAccountedFor(HandshakeAction.FINISH, currentActionIndex); return new SSLEngineResult(Status.OK, HandshakeStatus.FINISHED, 30, 0); case NEED_TASK: return new SSLEngineResult(Status.OK, HandshakeStatus.NEED_TASK, 0, 0); case NEED_UNWRAP: return wrapper.unwrap(dsts, offset, length, src, true, currentActionIndex); case NEED_WRAP: if (closed) { return new SSLEngineResult(Status.CLOSED, SSLEngineResult.HandshakeStatus.NEED_WRAP, 0, 0); } return new SSLEngineResult(Status.OK, SSLEngineResult.HandshakeStatus.NEED_WRAP, 0, 0); case NOT_HANDSHAKING: return wrapper.unwrap(dsts, offset, length, src, false, currentActionIndex); default: throw new IllegalStateException("Unexpected handshake status: " + getHandshakeStatus()); } } @Override public SSLEngineResult wrap(ByteBuffer[] srcs, int offset, int length, ByteBuffer dst) throws SSLException { if (dst.position() > 0) { return new SSLEngineResult(SSLEngineResult.Status.BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0); } final HandshakeStatus status; final int currentActionIndex; synchronized (this) { status = getHandshakeStatus(); currentActionIndex = actionIndex; } switch(status) { case FINISHED: { actionAccountedFor(HandshakeAction.FINISH, currentActionIndex); return new SSLEngineResult(SSLEngineResult.Status.OK, SSLEngineResult.HandshakeStatus.FINISHED, 0, 0); } case NEED_TASK: return new SSLEngineResult(SSLEngineResult.Status.OK, SSLEngineResult.HandshakeStatus.NEED_TASK, 0, 0); case NEED_UNWRAP: return new SSLEngineResult(SSLEngineResult.Status.OK, SSLEngineResult.HandshakeStatus.NEED_UNWRAP, 0, 0); case NEED_WRAP: return wrapper.wrap(dst, srcs, offset, length, true, currentActionIndex); case NOT_HANDSHAKING: { return wrapper.wrap(dst, srcs, offset, length, false, currentActionIndex); } default: throw new IllegalStateException("Unexpected handshake status: " + getHandshakeStatus()); } } private final class MappedWrapper { private final Map wrapMap = new HashMap(); private final Map unwrapMap = new HashMap(); public void put(String unwrapped, String wrapped) { wrapMap.put(unwrapped, wrapped); // avoid use of wrapped text as it if it were wrapped if (!wrapMap.containsKey(wrapped)) { wrapMap.put(wrapped, ""); } unwrapMap.put(wrapped, unwrapped); // avoid use of unwrapped text as if it were wrapped on read if (!unwrapMap.containsKey(unwrapped)) { unwrapMap.put(unwrapped, ""); } } private boolean hasEnoughSpace(ByteBuffer[] dsts, int offset, int length, int dataLength) { for (int i = offset; i < length && dataLength > 0; i++) { dataLength -= dsts[i].remaining(); } return dataLength <= 0; } public SSLEngineResult unwrap(ByteBuffer[] dsts, int offset, int length, ByteBuffer src, boolean needUnwrap,int actionIndex) { if (!src.hasRemaining()) { return new SSLEngineResult(closed && closeMessageUnwrapped? Status.CLOSED: Status.BUFFER_UNDERFLOW, HandshakeStatus.NEED_UNWRAP, 0, 0); } Status okStatus = closed && closeMessageUnwrapped? Status.CLOSED: Status.OK; // amount of bytes available at src int initialSrcRemaining = src.remaining(); int bytesProduced = 0; while (src.hasRemaining()) { String unwrapped = unwrapBytes(dsts, offset, length, src, needUnwrap); int bytesConsumed = initialSrcRemaining - src.remaining(); if (unwrapped == null) { if (bytesProduced == 0) { return new SSLEngineResult(Status.BUFFER_OVERFLOW, HandshakeStatus.NEED_UNWRAP, 0, 0); } return new SSLEngineResult(okStatus, HandshakeStatus.NEED_UNWRAP, bytesConsumed, bytesProduced); } // it means handshake message was found when it is not expected, ignore it and return everything that // was read up until now if (unwrapped.length() == 0) { if (bytesConsumed > 0) { actionAccountedFor(HandshakeAction.PERFORM_REQUESTED_ACTION, actionIndex); } return new SSLEngineResult(okStatus, getHandshakeStatus(), bytesConsumed, bytesProduced); } // it means we are on a needUnwrap and we found the handshake message we are seeking if (unwrapped.equals(HANDSHAKE_MSG)) { actionAccountedFor(HandshakeAction.NEED_UNWRAP, actionIndex); // move to next action, NEED_UNWRAP action is finally accomplished return new SSLEngineResult(okStatus, getHandshakeStatus(), bytesConsumed, bytesProduced); } if (unwrapped.equals(CLOSE_MSG)) { closed = true; closeMessageUnwrapped = true; return new SSLEngineResult(Status.CLOSED, getHandshakeStatus(), bytesConsumed, bytesProduced); } bytesProduced += unwrapped.length(); } int bytesConsumed = initialSrcRemaining - src.remaining(); if (bytesConsumed > 0 && !needUnwrap) { actionAccountedFor(HandshakeAction.PERFORM_REQUESTED_ACTION, actionIndex); } return new SSLEngineResult(okStatus, getHandshakeStatus(), bytesConsumed, bytesProduced); } private String unwrapBytes(ByteBuffer[] dsts, int offset, int length, ByteBuffer src, boolean readHandshakeMsg) { // define unwrapped data to be written to dsts String wrapped = Buffers.getModifiedUtf8(src); int wrappedEndIndex = wrapped.length(); int wrappedLeftOver = -1; while (wrappedEndIndex > 0 && !unwrapMap.containsKey(wrapped.substring(0, wrappedEndIndex))) { wrappedLeftOver = wrappedEndIndex --; } // undo the reading of data that won't be used now if (wrappedLeftOver != -1 && wrappedEndIndex > 0) { src.position(src.position() - (wrapped.length() - wrappedEndIndex)); wrapped = wrapped.substring(0, wrappedEndIndex); } else { int msgIndex; if ((msgIndex = wrapped.indexOf(HANDSHAKE_MSG)) != -1) { if (msgIndex == 0) { src.position(src.position() - (wrapped.length() - HANDSHAKE_MSG.length())); wrapped = wrapped.substring(0, HANDSHAKE_MSG.length()); } else { src.position(src.position() - (wrapped.length() - msgIndex)); wrapped = wrapped.substring(0, msgIndex); } } if ((msgIndex = wrapped.indexOf(CLOSE_MSG)) != -1) { if (msgIndex == 0) { src.position(src.position() - (wrapped.length() - CLOSE_MSG.length())); wrapped = wrapped.substring(0, CLOSE_MSG.length()); } else { src.position(src.position() - (wrapped.length() - msgIndex)); wrapped = wrapped.substring(0, msgIndex); } } } String unwrapped = unwrapMap.containsKey(wrapped)? unwrapMap.get(wrapped): wrapped; if (unwrapped.equals(HANDSHAKE_MSG) && !readHandshakeMsg) { src.position(src.position() - wrapped.length()); return ""; } if (!unwrapped.equals(CLOSE_MSG) && !unwrapped.equals(HANDSHAKE_MSG)) { if (CLOSE_MSG.startsWith(unwrapped) || HANDSHAKE_MSG.startsWith(unwrapped)) { src.position(0); return null; } // check if there is enough space to write unwrapped data, if not, do not write if (!hasEnoughSpace(dsts, offset, length, unwrapped.length())) { src.position(src.position() - wrapped.length()); return null; } // copy data to dsts int unwrappedSliceIndex = 0; int dstsLength = offset + length; for (int i = offset; i < dstsLength; i++) { String unwrappedData = unwrapped; boolean done = true; if (dsts[i].remaining() < unwrapped.length()) { unwrappedData = unwrapped.substring(unwrappedSliceIndex, dsts[i].remaining()); unwrappedSliceIndex += dsts[i].remaining(); done = false; } Buffers.putModifiedUtf8(dsts[i], unwrappedData); if (done) { break; } } } return unwrapped; } public SSLEngineResult wrap(ByteBuffer dst, ByteBuffer[] srcs, int offset, int length, boolean needWrap, int actionIndex) { if (needWrap) { actionAccountedFor(HandshakeAction.NEED_WRAP, actionIndex); // a valid needWrapActionIndex indicates that we musts wrap a handshake message if (closed) { synchronized(SSLEngineMock.this) { closeMessageWrapped = true; } return wrapMessage(dst, CLOSE_MSG, Status.CLOSED); } return wrapMessage(dst, HANDSHAKE_MSG, Status.OK); } int dstInitialRemaining = dst.remaining(); int bytesConsumed = wrapBytes(dst, srcs, offset, length); int bytesProduced = dstInitialRemaining - dst.remaining(); if (bytesConsumed > 0) { actionAccountedFor(HandshakeAction.PERFORM_REQUESTED_ACTION, actionIndex); } if (closed) { return new SSLEngineResult(Status.CLOSED, HandshakeStatus.NOT_HANDSHAKING, bytesConsumed, bytesProduced); } if (bytesConsumed == 0) { for (int i = offset; i < length; i++) { if (srcs[i].hasRemaining()) { return new SSLEngineResult(Status.BUFFER_OVERFLOW, HandshakeStatus.NOT_HANDSHAKING, bytesConsumed, bytesProduced); } } } return new SSLEngineResult(Status.OK, HandshakeStatus.NOT_HANDSHAKING, bytesConsumed, bytesProduced); } private SSLEngineResult wrapMessage(ByteBuffer dst, String msg, Status okayStatus) { String wrappedMessage = wrapMap.containsKey(msg)? wrapMap.get(msg): msg; if (dst.remaining() < wrappedMessage.length()) { return new SSLEngineResult(Status.BUFFER_OVERFLOW, getHandshakeStatus(), 0, 0); } Buffers.putModifiedUtf8(dst, wrappedMessage); return new SSLEngineResult(okayStatus, getHandshakeStatus(), 0, wrappedMessage.length()); } public int wrapBytes(ByteBuffer dst, ByteBuffer[] srcs, int offset, int length) { int totalLength = 0; int srcsLength = offset + length; for (int i = offset; i < srcsLength && dst.hasRemaining(); i++) { StringBuilder unwrappedBuilder = new StringBuilder(); Buffers.readModifiedUtf8Line(srcs[i], unwrappedBuilder); int wrappedLength = wrapBytes(dst, unwrappedBuilder.toString()); if (wrappedLength == 0 && unwrappedBuilder.length() > 0) { srcs[i].position(srcs[i].position() - unwrappedBuilder.length()); break; } totalLength += wrappedLength; } return totalLength; } public int wrapBytes(ByteBuffer dst, String src) { String wrapped = wrapMap.containsKey(src)? wrapMap.get(src): src; if (dst.remaining() < wrapped.length()) { return 0; } Buffers.putModifiedUtf8(dst, wrapped); return src.length(); } } @Override public boolean getEnableSessionCreation() { return enableSessionCreation; } @Override public String[] getEnabledCipherSuites() { return enabledCipherSuites; } @Override public String[] getEnabledProtocols() { return enabledProtocols; } @Override public boolean getNeedClientAuth() { return needClientAuth; } @Override public String[] getSupportedCipherSuites() { return supportedCipherSuites; } public void setSupportedCipherSuites(String... supportedCipherSuites) { this.supportedCipherSuites = supportedCipherSuites; } @Override public String[] getSupportedProtocols() { return supportedProtocols; } public void setSupportedProtocols(String... supportedProtocols) { this.supportedProtocols = supportedProtocols; } @Override public boolean getUseClientMode() { return useClientMode; } @Override public boolean getWantClientAuth() { return wantClientAuth; } @Override public boolean isInboundDone() { return false; } @Override public boolean isOutboundDone() { return closeMessageWrapped; } @Override public void setEnableSessionCreation(boolean flag) { enableSessionCreation = flag; } @Override public void setEnabledCipherSuites(String[] suites) { enabledCipherSuites = suites; } @Override public void setEnabledProtocols(String[] protocols) { enabledProtocols = protocols; } @Override public void setNeedClientAuth(boolean need) { needClientAuth = need; } @Override public void setUseClientMode(boolean mode) { useClientMode = mode; } @Override public void setWantClientAuth(boolean want) { wantClientAuth = want; } } xnio-3.3.2.Final/api/src/test/java/org/xnio/streams/000077500000000000000000000000001257016060700222125ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/java/org/xnio/streams/AbstractChannelInputStreamTest.java000066400000000000000000000713041257016060700311520ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.streams; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.InputStream; import java.nio.channels.ClosedChannelException; import java.util.concurrent.TimeUnit; import org.junit.Test; import org.xnio.channels.ReadTimeoutException; import org.xnio.channels.StreamSourceChannel; import org.xnio.mock.ConnectedStreamChannelMock; /** * Abstract test for channel input streams. * * @author Flavia Rainone */ public abstract class AbstractChannelInputStreamTest extends AbstractChannelStreamTest { /** * Creates the channel input stream. * * @param sourceChannel the source channel * @param internalBufferSize the size of the stream's internal buffer size, if applicable * @return the created channel input stream */ protected abstract T createChannelInputStream(StreamSourceChannel sourceChannel, int internalBufferSize); /** * Creates the channel input stream with read timeout enabled. * * @param sourceChannel the source channel * @param timeout the read timeout * @param timeUnit the read timeout unit * @param internalBufferSize the size of the stream's internal buffer size, if applicable * @return the created channel input stream */ protected abstract T createChannelInputStream(StreamSourceChannel sourceChannel, long timeout, TimeUnit timeUnit, int internalBufferSize); /** * Returns the read timeout of {@code stream}. * * @param stream the channel input stream * @param timeUnit the timeout unit * @return the read timeout of {@code stream} */ protected abstract long getReadTimeout(T stream, TimeUnit timeUnit); /** * Sets the read timeout for {@code stream}. * * @param stream the channel input stream * @param timeout the timeout * @param timeUnit the timeout unit */ protected abstract void setReadTimeout(T stream, int timeout, TimeUnit timeUnit); /** * Asserts that the available bytes in {@code stream} are as expected. * * @param stream the channel input stream * @param availableInBuffer expected amount of bytes available in the stream's internal buffer, if applicable * @param availableTotal the total amount of bytes available for reading in {@code stream} * @throws IOException */ protected abstract void assertAvailableBytes( T stream, int availableInBuffer, int availableTotal) throws IOException; @Test public void illegalConstructorArguments() { final ConnectedStreamChannelMock sourceChannel = new ConnectedStreamChannelMock(); IllegalArgumentException expected = null; // null source channel try { createChannelInputStream(null, 10); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { createChannelInputStream(null, 5, TimeUnit.SECONDS, 10); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; // timeout < 0 try { createChannelInputStream(sourceChannel, -20, TimeUnit.DAYS, 20); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; // time unit is null try { createChannelInputStream(sourceChannel, 3000, null, 20); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void readBytesAfterAvailable() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final T stream = createChannelInputStream(channelMock, 10); channelMock.setReadData("load this message"); channelMock.setEof(); channelMock.enableRead(true); assertAvailableBytes(stream, 10, 17); assertEquals('l', stream.read()); assertAvailableBytes(stream, 9, 16); assertEquals('o', stream.read()); assertAvailableBytes(stream, 8, 15); assertEquals('a', stream.read()); assertAvailableBytes(stream, 7, 14); assertEquals('d', stream.read()); assertAvailableBytes(stream, 6, 13); assertEquals(' ', stream.read()); assertAvailableBytes(stream, 5, 12); assertEquals('t', stream.read()); assertAvailableBytes(stream, 4, 11); assertEquals('h', stream.read()); assertAvailableBytes(stream, 3, 10); assertEquals('i', stream.read()); assertAvailableBytes(stream, 2, 9); assertEquals('s', stream.read()); assertAvailableBytes(stream, 1, 8); assertEquals(' ', stream.read()); assertAvailableBytes(stream, 7, 7); assertEquals('m', stream.read()); assertAvailableBytes(stream, 6, 6); assertEquals('e', stream.read()); assertAvailableBytes(stream, 5, 5); assertEquals('s', stream.read()); assertAvailableBytes(stream, 4, 4); assertEquals('s', stream.read()); assertAvailableBytes(stream, 3, 3); assertEquals('a', stream.read()); assertAvailableBytes(stream, 2, 2); assertEquals('g', stream.read()); assertAvailableBytes(stream, 1, 1); assertEquals('e', stream.read()); assertAvailableBytes(stream, 0, 0); assertEquals(-1, stream.read()); assertAvailableBytes(stream, 0, 0); } @Test public void readByteArrayAfterAvailable() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final T stream = createChannelInputStream(channelMock, 10); channelMock.setReadData("load this message"); channelMock.setEof(); channelMock.enableRead(true); assertAvailableBytes(stream, 10, 17); byte[] bytes = new byte[20]; assertEquals(17, stream.read(bytes)); assertEquals('l', bytes[0]); assertEquals('o', bytes[1]); assertEquals('a', bytes[2]); assertEquals('d', bytes[3]); assertEquals(' ', bytes[4]); assertEquals('t', bytes[5]); assertEquals('h', bytes[6]); assertEquals('i', bytes[7]); assertEquals('s', bytes[8]); assertEquals(' ', bytes[9]); assertEquals('m', bytes[10]); assertEquals('e', bytes[11]); assertEquals('s', bytes[12]); assertEquals('s', bytes[13]); assertEquals('a', bytes[14]); assertEquals('g', bytes[15]); assertEquals('e', bytes[16]); assertEquals(-1, stream.read(bytes)); } @Test public void readBytesAndByteArrays() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final T stream = createChannelInputStream(channelMock, 10); assertAvailableBytes(stream, 0, 0); channelMock.setReadData("data"); channelMock.enableRead(true); assertEquals('d', stream.read()); assertAvailableBytes(stream, 3, 3); assertEquals('a', stream.read()); assertEquals('t', stream.read()); assertEquals('a', stream.read()); assertAvailableBytes(stream, 0, 0); channelMock.setReadData("more data"); assertAvailableBytes(stream, 9, 9); byte[] bytes = new byte[10]; assertEquals(9, stream.read(bytes, 1, 9)); assertEquals(0, bytes[0]); assertEquals('m', bytes[1]); assertEquals('o', bytes[2]); assertEquals('r', bytes[3]); assertEquals('e', bytes[4]); assertEquals(' ', bytes[5]); assertEquals('d', bytes[6]); assertEquals('a', bytes[7]); assertEquals('t', bytes[8]); assertEquals('a', bytes[9]); channelMock.setEof(); assertEquals(-1, stream.read()); assertEquals(-1, stream.read(bytes, 0, 10)); assertEquals(-1, stream.read()); assertEquals(-1, stream.read(bytes, 0, 10)); } @Test public void readByteArraysAndBytes() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final T stream = createChannelInputStream(channelMock, 10); assertAvailableBytes(stream, 0, 0); channelMock.setReadData("data"); channelMock.enableRead(true); byte[] bytes = new byte[5]; assertEquals(4, stream.read(bytes)); assertEquals('d', bytes[0]); assertEquals('a', bytes[1]); assertEquals('t', bytes[2]); assertEquals('a', bytes[3]); assertAvailableBytes(stream, 0, 0); channelMock.setReadData("more data"); assertAvailableBytes(stream, 9, 9); assertEquals('m', stream.read()); assertAvailableBytes(stream, 8, 8); assertEquals('o', stream.read()); assertAvailableBytes(stream, 7, 7); assertEquals('r', stream.read()); assertAvailableBytes(stream, 6, 6); assertEquals('e', stream.read()); assertAvailableBytes(stream, 5, 5); assertEquals(' ', stream.read()); assertAvailableBytes(stream, 4, 4); assertEquals('d', stream.read()); assertAvailableBytes(stream, 3, 3); assertEquals('a', stream.read()); assertAvailableBytes(stream, 2, 2); assertEquals('t', stream.read()); assertAvailableBytes(stream, 1, 1); assertEquals('a', stream.read()); assertAvailableBytes(stream, 0, 0); channelMock.setEof(); assertEquals(-1, stream.read()); assertEquals(-1, stream.read()); assertEquals(-1, stream.read()); assertEquals(-1, stream.read(bytes)); assertEquals(-1, stream.read(bytes)); assertEquals(-1, stream.read(bytes)); } @Test public void readBlocks() throws Exception { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final T stream = createChannelInputStream(channelMock, 20); channelMock.setReadData("stream read blocks until channel read is enabled"); // create and start read threa final ReadByteTask readByteTask = new ReadByteTask(stream); final Thread readByteThread = new Thread(readByteTask); readByteThread.start(); // thread cant complete readByteThread.join(200); assertTrue(readByteThread.isAlive()); // enable read, now thread can complete with a result channelMock.enableRead(true); readByteThread.join(); assertEquals('s', readByteTask.getReadResult()); assertAvailableBytes(stream, 19, 19); } @Test public void readByteArrayBlocks1() throws Exception { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final T stream = createChannelInputStream(channelMock, 20); channelMock.setReadData("stream read blocks until channel read is enabled"); // create and start read thread byte[] bytes = new byte[25]; final ReadBytesTask readBytesTask = new ReadBytesTask(stream, bytes); final Thread readBytesThread = new Thread(readBytesTask); readBytesThread.start(); // thread cant complete readBytesThread.join(200); assertTrue(readBytesThread.isAlive()); // enable read, now thread can complete with a result channelMock.enableRead(true); readBytesThread.join(); assertEquals(25, readBytesTask.getReadResult()); assertEquals('s', bytes[0]); assertEquals('t', bytes[1]); assertEquals('r', bytes[2]); assertEquals('e', bytes[3]); assertEquals('a', bytes[4]); assertEquals('m', bytes[5]); assertEquals(' ', bytes[6]); assertEquals('r', bytes[7]); assertEquals('e', bytes[8]); assertEquals('a', bytes[9]); assertEquals('d', bytes[10]); assertEquals(' ', bytes[11]); assertEquals('b', bytes[12]); assertEquals('l', bytes[13]); assertEquals('o', bytes[14]); assertEquals('c', bytes[15]); assertEquals('k', bytes[16]); assertEquals('s', bytes[17]); assertEquals(' ', bytes[18]); assertEquals('u', bytes[19]); assertEquals('n', bytes[20]); assertEquals('t', bytes[21]); assertEquals('i', bytes[22]); assertEquals('l', bytes[23]); assertEquals(' ', bytes[24]); assertAvailableBytes(stream, 20, 23); } @Test public void readByteArrayBlocks2() throws Exception { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final T stream = createChannelInputStream(channelMock, 20); channelMock.setReadData("read blocks"); // create and start read thread byte[] bytes = new byte[25]; final ReadBytesTask readBytesTask = new ReadBytesTask(stream, bytes); final Thread readBytesThread = new Thread(readBytesTask); readBytesThread.start(); // thread cant complete readBytesThread.join(200); assertTrue(readBytesThread.isAlive()); // enable read, now thread can complete with a result channelMock.enableRead(true); readBytesThread.join(); assertEquals(11, readBytesTask.getReadResult()); assertEquals('r', bytes[0]); assertEquals('e', bytes[1]); assertEquals('a', bytes[2]); assertEquals('d', bytes[3]); assertEquals(' ', bytes[4]); assertEquals('b', bytes[5]); assertEquals('l', bytes[6]); assertEquals('o', bytes[7]); assertEquals('c', bytes[8]); assertEquals('k', bytes[9]); assertEquals('s', bytes[10]); assertAvailableBytes(stream, 0, 0); } @Test public void readBytesAfterAvailableWithTimeout() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final T stream = createChannelInputStream(channelMock, 100, TimeUnit.MILLISECONDS, 10); assertEquals(100, getReadTimeout(stream, TimeUnit.MILLISECONDS)); channelMock.setReadData("load this message"); channelMock.setEof(); channelMock.enableRead(true); assertAvailableBytes(stream, 10, 17); assertEquals('l', stream.read()); assertAvailableBytes(stream, 9, 16); assertEquals('o', stream.read()); assertAvailableBytes(stream, 8, 15); assertEquals('a', stream.read()); assertAvailableBytes(stream, 7, 14); assertEquals('d', stream.read()); assertAvailableBytes(stream, 6, 13); assertEquals(' ', stream.read()); assertAvailableBytes(stream, 5, 12); assertEquals('t', stream.read()); assertAvailableBytes(stream, 4, 11); assertEquals('h', stream.read()); assertAvailableBytes(stream, 3, 10); assertEquals('i', stream.read()); assertAvailableBytes(stream, 2, 9); assertEquals('s', stream.read()); assertAvailableBytes(stream, 1, 8); assertEquals(' ', stream.read()); assertAvailableBytes(stream, 7, 7); assertEquals('m', stream.read()); assertAvailableBytes(stream, 6, 6); assertEquals('e', stream.read()); assertAvailableBytes(stream, 5, 5); assertEquals('s', stream.read()); assertAvailableBytes(stream, 4, 4); assertEquals('s', stream.read()); assertAvailableBytes(stream, 3, 3); assertEquals('a', stream.read()); assertAvailableBytes(stream, 2, 2); assertEquals('g', stream.read()); assertAvailableBytes(stream, 1, 1); assertEquals('e', stream.read()); assertAvailableBytes(stream, 0, 0); assertEquals(-1, stream.read()); assertAvailableBytes(stream, 0, 0); } @Test public void readByteArrayAfterAvailableWithTimeout() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final T stream = createChannelInputStream(channelMock, 200, TimeUnit.MILLISECONDS, 10); assertEquals(200, getReadTimeout(stream, TimeUnit.MILLISECONDS)); channelMock.setReadData("load this message"); channelMock.setEof(); channelMock.enableRead(true); assertAvailableBytes(stream, 10, 17); byte[] bytes = new byte[20]; assertEquals(17, stream.read(bytes)); assertEquals('l', bytes[0]); assertEquals('o', bytes[1]); assertEquals('a', bytes[2]); assertEquals('d', bytes[3]); assertEquals(' ', bytes[4]); assertEquals('t', bytes[5]); assertEquals('h', bytes[6]); assertEquals('i', bytes[7]); assertEquals('s', bytes[8]); assertEquals(' ', bytes[9]); assertEquals('m', bytes[10]); assertEquals('e', bytes[11]); assertEquals('s', bytes[12]); assertEquals('s', bytes[13]); assertEquals('a', bytes[14]); assertEquals('g', bytes[15]); assertEquals('e', bytes[16]); assertEquals(-1, stream.read(bytes)); } @Test public void readBytesAndByteArraysWithTimeout() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final T stream = createChannelInputStream(channelMock, 0, TimeUnit.MICROSECONDS, 10); assertEquals(0, getReadTimeout(stream, TimeUnit.MICROSECONDS)); assertEquals(0, getReadTimeout(stream, TimeUnit.MILLISECONDS)); setReadTimeout(stream, 100, TimeUnit.MILLISECONDS); assertEquals(100, getReadTimeout(stream, TimeUnit.MILLISECONDS)); // start read test assertAvailableBytes(stream, 0, 0); ReadTimeoutException expectedException = null; try { stream.read(); } catch (ReadTimeoutException e) { expectedException = e; } assertNotNull(expectedException); channelMock.setReadData("data"); channelMock.enableRead(true); assertEquals('d', stream.read()); assertAvailableBytes(stream, 3, 3); assertEquals('a', stream.read()); assertEquals('t', stream.read()); assertEquals('a', stream.read()); assertAvailableBytes(stream, 0, 0); expectedException = null; try { stream.read(); } catch (ReadTimeoutException e) { expectedException = e; } assertNotNull(expectedException); final byte[] bytes = new byte[10]; expectedException = null; try { stream.read(bytes); } catch (ReadTimeoutException e) { expectedException = e; } assertNotNull(expectedException); channelMock.setReadData("more data"); assertAvailableBytes(stream, 9, 9); assertEquals(9, stream.read(bytes, 1, 9)); assertEquals(0, bytes[0]); assertEquals('m', bytes[1]); assertEquals('o', bytes[2]); assertEquals('r', bytes[3]); assertEquals('e', bytes[4]); assertEquals(' ', bytes[5]); assertEquals('d', bytes[6]); assertEquals('a', bytes[7]); assertEquals('t', bytes[8]); assertEquals('a', bytes[9]); assertAvailableBytes(stream, 0, 0); expectedException = null; try { stream.read(bytes); } catch (ReadTimeoutException e) { expectedException = e; } assertNotNull(expectedException); channelMock.setEof(); assertEquals(-1, stream.read()); assertEquals(-1, stream.read(bytes, 0, 10)); assertEquals(-1, stream.read()); assertEquals(-1, stream.read(bytes, 0, 10)); } @Test public void readByteArraysAndBytesWithTimeout() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); // try using 10 microseconds, timeout value is NOT rounded up final T stream = createChannelInputStream(channelMock, 10, TimeUnit.MICROSECONDS, 10); assertEquals(10, getReadTimeout(stream, TimeUnit.MICROSECONDS)); assertEquals(10000, getReadTimeout(stream, TimeUnit.NANOSECONDS)); // start read test final byte[] bytes = new byte[5]; assertAvailableBytes(stream, 0, 0); ReadTimeoutException expectedException = null; try { stream.read(bytes); } catch (ReadTimeoutException e) { expectedException = e; } assertNotNull(expectedException); channelMock.setReadData("data"); channelMock.enableRead(true); assertEquals(0, stream.read(bytes, 0, -3)); assertEquals(4, stream.read(bytes)); assertEquals('d', bytes[0]); assertEquals('a', bytes[1]); assertEquals('t', bytes[2]); assertEquals('a', bytes[3]); assertAvailableBytes(stream, 0, 0); expectedException = null; try { stream.read(); } catch (ReadTimeoutException e) { expectedException = e; } assertNotNull(expectedException); expectedException = null; try { stream.read(bytes); } catch (ReadTimeoutException e) { expectedException = e; } assertNotNull(expectedException); channelMock.setReadData("more data"); assertAvailableBytes(stream, 9, 9); assertEquals('m', stream.read()); assertAvailableBytes(stream, 8, 8); assertEquals('o', stream.read()); assertAvailableBytes(stream, 7, 7); assertEquals('r', stream.read()); assertAvailableBytes(stream, 6, 6); assertEquals('e', stream.read()); assertAvailableBytes(stream, 5, 5); assertEquals(' ', stream.read()); assertAvailableBytes(stream, 4, 4); assertEquals('d', stream.read()); assertAvailableBytes(stream, 3, 3); assertEquals('a', stream.read()); assertAvailableBytes(stream, 2, 2); assertEquals('t', stream.read()); assertAvailableBytes(stream, 1, 1); assertEquals('a', stream.read()); assertAvailableBytes(stream, 0, 0); expectedException = null; try { stream.read(); } catch (ReadTimeoutException e) { expectedException = e; } assertNotNull(expectedException); channelMock.setEof(); assertEquals(-1, stream.read()); assertEquals(-1, stream.read()); assertEquals(-1, stream.read()); assertEquals(-1, stream.read(bytes)); assertEquals(-1, stream.read(bytes)); assertEquals(-1, stream.read(bytes)); } @Test public void skip() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final T stream = createChannelInputStream(channelMock, 10); assertEquals(0, stream.skip(-1)); assertEquals(0, stream.skip(0)); channelMock.setReadData("skip all this - data"); channelMock.enableRead(true); assertEquals(16, stream.skip(16)); assertAvailableBytes(stream, 4, 4); assertEquals('d', stream.read()); assertEquals('a', stream.read()); assertEquals('t', stream.read()); assertEquals('a', stream.read()); channelMock.setReadData("skip again"); assertAvailableBytes(stream, 10, 10); assertEquals(4, stream.skip(4)); assertAvailableBytes(stream, 6, 6); assertEquals(' ', stream.read()); assertEquals('a', stream.read()); assertEquals('g', stream.read()); assertEquals('a', stream.read()); assertEquals('i', stream.read()); assertEquals('n', stream.read()); channelMock.setReadData("skip"); assertAvailableBytes(stream, 4, 4); assertEquals(4, stream.skip(4)); channelMock.setReadData("skip once more"); assertEquals(14, stream.skip(14)); channelMock.setReadData("more"); channelMock.setEof(); assertEquals(4, stream.skip(Integer.MAX_VALUE)); assertAvailableBytes(stream, 0, 0); } @Test public void readThrowsException() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); channelMock.close(); // channel mock will always throw ClosedChannelException final T stream = createChannelInputStream(channelMock, 10); // try to skip, test twice to make sure that buffer is kept consistent ClosedChannelException expected = null; try { stream.skip(10); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.skip(10); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); // try to read, test twice to make sure that buffer is kept consistent expected = null; try { stream.read(); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.read(); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); // try to read bytes, test twice to make sure that buffer is kept consistent expected = null; try { stream.read(new byte[10]); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.read(new byte[10]); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); } private class ReadByteTask implements Runnable { private final T stream; private int readResult; public ReadByteTask(T s) { stream = s; } @Override public void run() { try { readResult = stream.read(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } public int getReadResult() { return readResult; } } private class ReadBytesTask implements Runnable { private final T stream; private final byte[] bytes; private int readResult; public ReadBytesTask(T s, byte[] b) { stream = s; bytes = b; } @Override public void run() { try { readResult = stream.read(bytes); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } public int getReadResult() { return readResult; } } protected class SkipBytesTask implements Runnable { private final T stream; private final int skip; private long skipResult; public SkipBytesTask(T s, int l) { stream = s; skip = l; } @Override public void run() { try { skipResult = stream.skip(skip); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } public long getSkipResult() { return skipResult; } } @Override protected long getOperationTimeout(T stream, TimeUnit timeUnit) { return getReadTimeout(stream, timeUnit); } @Override protected void setOperationTimeout(T stream, int timeout, TimeUnit timeUnit) { setReadTimeout(stream, timeout, timeUnit); } @Override protected T createChannelStream(long timeout, TimeUnit timeUnit) { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); return createChannelInputStream(channelMock, timeout, timeUnit, 10); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/streams/AbstractChannelStreamTest.java000066400000000000000000000104231257016060700301250ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.streams; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.io.Closeable; import java.util.concurrent.TimeUnit; import org.junit.Test; /** * Abstract test for channel streams. * * @author Flavia Rainone */ public abstract class AbstractChannelStreamTest { /** * Returns the operation (it could be read or write) timeout of {@code stream}. * * @param stream the channel input or output stream * @param timeUnit the timeout unit * @return the read or write timeout of {@code stream} */ protected abstract long getOperationTimeout(T stream, TimeUnit timeUnit); /** * Sets the read or write timeout for {@code stream}. * * @param stream the channel input or output stream * @param timeout the timeout * @param timeUnit the timeout unit */ protected abstract void setOperationTimeout(T stream, int timeout, TimeUnit timeUnit); /** * Creates the channel input or output stream with operation timeout enabled. * * @param timeout the operation timeout * @param timeUnit the operation timeout unit * @return the created channel stream */ protected abstract T createChannelStream(long timeout, TimeUnit timeUnit); @Test public void setOperationTimeout() { // create stream final T stream = createChannelStream(0, TimeUnit.SECONDS); assertEquals(0, getOperationTimeout(stream, TimeUnit.MICROSECONDS)); // try to set read timeout -1 Exception setOperationTimeoutException = null; try { setOperationTimeout(stream, -1, TimeUnit.HOURS); } catch (IllegalArgumentException e) { setOperationTimeoutException = e; } assertNotNull(setOperationTimeoutException); // try to set read timeout with null timeunit setOperationTimeoutException = null; try { setOperationTimeout(stream, 5, null); } catch (IllegalArgumentException e) { setOperationTimeoutException = e; } assertNotNull(setOperationTimeoutException); // try to get read timeout with null timeunit Exception getOperationTimeoutException = null; try { getOperationTimeout(stream, null); } catch (IllegalArgumentException e) { getOperationTimeoutException = e; } assertNotNull(getOperationTimeoutException); // set timeout to 1 microsecond setOperationTimeout(stream, 1, TimeUnit.MICROSECONDS); assertEquals(0, getOperationTimeout(stream, TimeUnit.MILLISECONDS)); assertEquals(1000, getOperationTimeout(stream, TimeUnit.NANOSECONDS)); // timeout is not rounded up assertEquals(0, getOperationTimeout(stream, TimeUnit.SECONDS)); // set timeout to 0 milliseconds setOperationTimeout(stream, 0, TimeUnit.MILLISECONDS); assertEquals(0, getOperationTimeout(stream, TimeUnit.MILLISECONDS)); assertEquals(0, getOperationTimeout(stream, TimeUnit.MICROSECONDS)); // set timeout to 10 minutes setOperationTimeout(stream, 10, TimeUnit.MINUTES); assertEquals(10, getOperationTimeout(stream, TimeUnit.MINUTES)); assertEquals(600, getOperationTimeout(stream, TimeUnit.SECONDS)); assertEquals(600000, getOperationTimeout(stream, TimeUnit.MILLISECONDS)); assertEquals(0, getOperationTimeout(stream, TimeUnit.HOURS)); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/streams/BufferPipeInputStreamTestCase.java000066400000000000000000001270131257016060700307400ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.streams; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.xnio.AssertReadWrite.assertReadMessage; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; import java.util.NoSuchElementException; import org.junit.Before; import org.junit.Test; import org.xnio.Buffers; import org.xnio.ByteBufferSlicePool; import org.xnio.Pooled; /** * Test for {@link BufferPipeInputStream}. * * @author Flavia Rainone */ public class BufferPipeInputStreamTestCase { private TestInputHandler handler; private BufferPipeInputStream stream; @Before public void before() { handler = new TestInputHandler(); stream = new BufferPipeInputStream(handler); } @Test public void pushEmptyBuffer() throws IOException { assertEquals(0, stream.available()); stream.push(ByteBuffer.allocate(0)); assertEquals(0, stream.available()); final Pooled pooledBuffer = new ByteBufferSlicePool(1, 1).allocate(); pooledBuffer.getResource().flip(); stream.push(pooledBuffer); assertEquals(0, stream.available()); } @Test public void pushAfterFailure() throws IOException { stream.pushException(new IOException("test")); assertCantPush(); } @Test public void readSimpleBuffer() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(20); buffer.put("abc, def, ghi, jkl".getBytes("UTF-8")).flip(); stream.push(buffer); assertEquals(18, stream.available()); // can't read to empty buffer assertEquals(0, stream.read(new byte[0])); byte[] readBuffer = new byte[20]; assertEquals(18, stream.read(readBuffer)); assertReadMessage(readBuffer, "abc, ", "def, ", "ghi, ", "jkl"); assertEquals(0, stream.available()); assertHandledMessages(false, "abc, def, ghi, jkl"); } @Test public void readPooledByteBuffer() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(30, 30); final Pooled pooledBuffer = pool.allocate(); pooledBuffer.getResource().put("abc, def, ghi, jkl".getBytes("UTF-8")).flip(); stream.push(pooledBuffer); assertEquals(18, stream.available()); byte[] readBuffer = new byte[20]; assertEquals(18, stream.read(readBuffer)); assertReadMessage(readBuffer, "abc, ", "def, ", "ghi, ", "jkl"); assertEquals(0, stream.available()); assertHandledMessages(false, "abc, def, ghi, jkl"); } @Test public void readMultipleBuffers() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(5, 5); final Pooled pooledBuffer1 = pool.allocate(); final Pooled pooledBuffer2 = pool.allocate(); final ByteBuffer byteBuffer1 = ByteBuffer.allocate(1); final ByteBuffer byteBuffer2 = ByteBuffer.allocate(2); final ByteBuffer byteBuffer3 = ByteBuffer.allocate(3); pooledBuffer1.getResource().put("multi".getBytes("UTF-8")).flip(); byteBuffer1.put("p".getBytes("UTF-8")).flip(); pooledBuffer2.getResource().put("le bu".getBytes("UTF-8")).flip(); byteBuffer2.put("ff".getBytes("UTF-8")).flip(); byteBuffer3.put("ers".getBytes("UTF-8")).flip(); assertEquals(0, stream.available()); stream.push(pooledBuffer1); assertEquals(5, stream.available()); stream.push(byteBuffer1); assertEquals(6, stream.available()); stream.push(pooledBuffer2); assertEquals(11, stream.available()); stream.push(byteBuffer2); assertEquals(13, stream.available()); stream.push(byteBuffer3); assertEquals(16, stream.available()); byte[] readBuffer = new byte[20]; assertEquals(16, stream.read(readBuffer)); assertReadMessage(readBuffer, "multiple buffers"); assertEquals(0, stream.available()); assertHandledMessages(false, "multi", "p", "le bu", "ff", "ers"); } @Test public void readMultipleBuffersMultipleTimes() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(5, 5); final Pooled pooledBuffer1 = pool.allocate(); final Pooled pooledBuffer2 = pool.allocate(); final ByteBuffer byteBuffer1 = ByteBuffer.allocate(1); final ByteBuffer byteBuffer2 = ByteBuffer.allocate(2); final ByteBuffer byteBuffer3 = ByteBuffer.allocate(3); byteBuffer1.put("m".getBytes("UTF-8")).flip(); pooledBuffer1.getResource().put("ultip".getBytes("UTF-8")).flip(); pooledBuffer2.getResource().put("le bu".getBytes("UTF-8")).flip(); byteBuffer2.put("ff".getBytes("UTF-8")).flip(); byteBuffer3.put("ers".getBytes("UTF-8")).flip(); assertEquals(0, stream.available()); stream.push(byteBuffer1); assertEquals(1, stream.available()); stream.push(pooledBuffer1); assertEquals(6, stream.available()); stream.push(pooledBuffer2); assertEquals(11, stream.available()); stream.push(byteBuffer2); assertEquals(13, stream.available()); stream.push(byteBuffer3); assertEquals(16, stream.available()); byte[] readBuffer = new byte[3]; assertEquals(3, stream.read(readBuffer)); assertReadMessage(readBuffer, "mul"); assertEquals(13, stream.available()); assertEquals(3, stream.read(readBuffer)); assertReadMessage(readBuffer, "tip"); assertEquals(10, stream.available()); assertEquals(3, stream.read(readBuffer)); assertReadMessage(readBuffer, "le "); assertEquals(7, stream.available()); assertEquals(3, stream.read(readBuffer)); assertReadMessage(readBuffer, "buf"); assertEquals(4, stream.available()); assertEquals(3, stream.read(readBuffer)); assertReadMessage(readBuffer, "fer"); assertEquals(1, stream.available()); assertEquals(1, stream.read(readBuffer)); assertReadMessage(readBuffer, "s"); assertEquals(0, stream.available()); assertHandledMessages(false, "m", "ultip", "le bu", "ff", "ers"); } @Test public void readFailure() throws IOException { final IOException exception = new IOException("test"); stream.pushException(exception); IOException failure = null; try { stream.read(new byte[5]); } catch (IOException e) { failure = e; } assertSame(exception, failure); assertCantPush(); assertHandledMessages(false); } @Test public void messageIsNotTruncatedByFailure() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(20); buffer.put("truncated message".getBytes("UTF-8")).flip(); stream.push(buffer); assertEquals(17, stream.available()); byte[] readBuffer = new byte[10]; assertEquals(10, stream.read(readBuffer)); assertReadMessage(readBuffer, "truncated "); assertEquals(7, stream.available()); final IOException exception = new IOException("test"); stream.pushException(exception); assertEquals(7, stream.read(readBuffer)); assertReadMessage(readBuffer, "message"); assertEquals(0, stream.available()); IOException failure = null; try { stream.read(readBuffer); } catch (IOException e) { failure = e; } assertSame(exception, failure); assertEquals(0, stream.available()); assertCantPush(); assertHandledMessages(false, "truncated message"); } @Test public void readWaitsForPush() throws Exception { final ByteBuffer buffer = ByteBuffer.allocate(5); buffer.put("read".getBytes("UTF-8")).flip(); assertEquals(0, stream.available()); final ReadTask read = new ReadTask(stream); final Thread readThread = new Thread(read); readThread.start(); readThread.join(100); assertTrue(readThread.isAlive()); stream.push(buffer); readThread.join(); assertEquals(0, stream.available()); assertEquals(4, read.getReadResult()); assertReadMessage(read.getReadBuffer(), "read"); assertHandledMessages(false, "read"); } @Test public void readWaitsForFailure() throws Exception { assertEquals(0, stream.available()); final ReadTask read = new ReadTask(stream); final Thread readThread = new Thread(read); readThread.start(); readThread.join(100); assertTrue(readThread.isAlive()); final IOException failure = new IOException("test"); stream.pushException(failure); readThread.join(); assertEquals(0, stream.available()); assertEquals(0, read.getReadResult()); assertReadMessage(read.getReadBuffer()); assertSame(failure, read.getFailure()); assertCantPush(); assertHandledMessages(false); } @Test public void readWaitsForEof() throws Exception { assertEquals(0, stream.available()); final ReadTask read = new ReadTask(stream); final Thread readThread = new Thread(read); readThread.start(); readThread.join(100); assertTrue(readThread.isAlive()); stream.pushEof(); readThread.join(); assertEquals(0, stream.available()); assertEquals(-1, read.getReadResult()); assertReadMessage(read.getReadBuffer()); assertNull(read.getFailure()); assertCantPush(); assertHandledMessages(false); } @Test public void readWaitsForClose() throws Exception { assertEquals(0, stream.available()); final ReadTask read = new ReadTask(stream); final Thread readThread = new Thread(read); readThread.start(); readThread.join(100); assertTrue(readThread.isAlive()); stream.close(); readThread.join(); assertEquals(0, stream.available()); assertEquals(-1, read.getReadResult()); assertReadMessage(read.getReadBuffer()); assertNull(read.getFailure()); assertCantPush(); assertHandledMessages(true); } @Test public void concurrentReadBuffers() throws Exception { final ByteBuffer buffer = ByteBuffer.allocate(20); buffer.put("abcdefghijklmnopqrst".getBytes("UTF-8")).flip(); stream.push(buffer); assertEquals(20, stream.available()); final ReadTask read1 = new ReadTask(stream, 10); final ReadTask read2 = new ReadTask(stream, 10); final ReadTask read3 = new ReadTask(stream, 10); final PushTask push = new PushTask(stream, "uvwxyz"); final Thread readThread1 = new Thread(read1, "READ1"); final Thread readThread2 = new Thread(read2, "READ2"); final Thread readThread3 = new Thread(read3, "READ3"); final Thread pushThread = new Thread(push, "PUSH"); readThread1.start(); readThread2.start(); readThread3.start(); Thread.sleep(100); pushThread.start(); readThread1.join(); readThread2.join(); readThread3.join(); pushThread.join(); byte[] readBuffer1 = read1.getReadBuffer(); byte[] readBuffer2 = read2.getReadBuffer(); byte[] readBuffer3 = read3.getReadBuffer(); if (readBuffer1[0] == 'a') { if (readBuffer2[0] == 'k') { assertEquals(10, read1.getReadResult()); assertReadMessage(readBuffer1, "abcdefghij"); assertEquals(10, read2.getReadResult()); assertReadMessage(readBuffer2, "klmnopqrst"); assertEquals(6, read3.getReadResult()); assertReadMessage(readBuffer3, "uvwxyz"); } else if (readBuffer2[0] == 'u') { assertEquals(10, read1.getReadResult()); assertReadMessage(readBuffer1, "abcdefghij"); assertEquals(10, read3.getReadResult()); assertReadMessage(readBuffer3, "klmnopqrst"); assertEquals(6, read2.getReadResult()); assertReadMessage(readBuffer2, "uvwxyz"); } else { fail("Unexpected content for readBuffer2: " + Arrays.toString(readBuffer2)); } } else if (readBuffer1[0] == 'k') { if (readBuffer2[0] == 'a') { assertEquals(10, read2.getReadResult()); assertReadMessage(readBuffer2, "abcdefghij"); assertEquals(10, read1.getReadResult()); assertReadMessage(readBuffer1, "klmnopqrst"); assertEquals(6, read3.getReadResult()); assertReadMessage(readBuffer3, "uvwxyz"); } else if (readBuffer2[0] == 'u') { assertEquals(10, read3.getReadResult()); assertReadMessage(readBuffer3, "abcdefghij"); assertEquals(10, read1.getReadResult()); assertReadMessage(readBuffer1, "klmnopqrst"); assertEquals(6, read2.getReadResult()); assertReadMessage(readBuffer2, "uvwxyz"); } else { fail("Unexpected content for readBuffer2: " + Arrays.toString(readBuffer2)); } } else if (readBuffer1[0] == 'u') { if (readBuffer2[0] == 'a') { assertEquals(10, read2.getReadResult()); assertReadMessage(readBuffer2, "abcdefghij"); assertEquals(10, read3.getReadResult()); assertReadMessage(readBuffer3, "klmnopqrst"); assertEquals(6, read1.getReadResult()); assertReadMessage(readBuffer1, "uvwxyz"); } else if (readBuffer2[0] == 'ḱ') { assertEquals(10, read3.getReadResult()); assertReadMessage(readBuffer3, "abcdefghij"); assertEquals(10, read2.getReadResult()); assertReadMessage(readBuffer2, "klmnopqrst"); assertEquals(6, read1.getReadResult()); assertReadMessage(readBuffer1, "uvwxyz"); } else { fail("Unexpected content for readBuffer2: " + Arrays.toString(readBuffer2)); } } else { fail("Unexpected content for readBuffer1: " + Arrays.toString(readBuffer1)); } assertHandledMessages(false, "abcdefghijklmnopqrst", "uvwxyz"); } @Test public void readBytesFromSimpleBuffer() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("abcdef".getBytes("UTF-8")).flip(); stream.push(buffer); assertEquals(6, stream.available()); assertEquals('a', stream.read()); assertEquals(5, stream.available()); assertEquals('b', stream.read()); assertEquals(4, stream.available()); assertEquals('c', stream.read()); assertEquals(3, stream.available()); assertEquals('d', stream.read()); assertEquals(2, stream.available()); assertEquals('e', stream.read()); assertEquals(1, stream.available()); assertEquals('f', stream.read()); assertEquals(0, stream.available()); assertHandledMessages(false, "abcdef"); } @Test public void readBytesFromPooledByteBuffer() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(5, 5); final Pooled pooledBuffer = pool.allocate(); pooledBuffer.getResource().put("ghijk".getBytes("UTF-8")).flip(); stream.push(pooledBuffer); assertEquals(5, stream.available()); assertEquals('g', stream.read()); assertEquals(4, stream.available()); assertEquals('h', stream.read()); assertEquals(3, stream.available()); assertEquals('i', stream.read()); assertEquals(2, stream.available()); assertEquals('j', stream.read()); assertEquals(1, stream.available()); assertEquals('k', stream.read()); assertEquals(0, stream.available()); assertHandledMessages(false, "ghijk"); } @Test public void readBytesFromMultipleBuffers() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(5, 5); final Pooled pooledBuffer1 = pool.allocate(); final Pooled pooledBuffer2 = pool.allocate(); final ByteBuffer byteBuffer1 = ByteBuffer.allocate(1); final ByteBuffer byteBuffer2 = ByteBuffer.allocate(2); final ByteBuffer byteBuffer3 = ByteBuffer.allocate(3); pooledBuffer1.getResource().put("multi".getBytes("UTF-8")).flip(); byteBuffer1.put("p".getBytes("UTF-8")).flip(); pooledBuffer2.getResource().put("le bu".getBytes("UTF-8")).flip(); byteBuffer2.put("ff".getBytes("UTF-8")).flip(); byteBuffer3.put("ers".getBytes("UTF-8")).flip(); assertEquals(0, stream.available()); stream.push(pooledBuffer1); assertEquals(5, stream.available()); stream.push(byteBuffer1); assertEquals(6, stream.available()); stream.push(pooledBuffer2); assertEquals(11, stream.available()); stream.push(byteBuffer2); assertEquals(13, stream.available()); stream.push(byteBuffer3); assertEquals(16, stream.available()); assertEquals('m', stream.read()); assertEquals(15, stream.available()); assertEquals('u', stream.read()); assertEquals(14, stream.available()); assertEquals('l', stream.read()); assertEquals(13, stream.available()); assertEquals('t', stream.read()); assertEquals(12, stream.available()); assertEquals('i', stream.read()); assertEquals(11, stream.available()); assertEquals('p', stream.read()); assertEquals(10, stream.available()); assertEquals('l', stream.read()); assertEquals(9, stream.available()); assertEquals('e', stream.read()); assertEquals(8, stream.available()); assertEquals(' ', stream.read()); assertEquals(7, stream.available()); assertEquals('b', stream.read()); assertEquals(6, stream.available()); assertEquals('u', stream.read()); assertEquals(5, stream.available()); assertEquals('f', stream.read()); assertEquals(4, stream.available()); assertEquals('f', stream.read()); assertEquals(3, stream.available()); assertEquals('e', stream.read()); assertEquals(2, stream.available()); assertEquals('r', stream.read()); assertEquals(1, stream.available()); assertEquals('s', stream.read()); assertEquals(0, stream.available()); assertHandledMessages(false, "multi", "p", "le bu", "ff", "ers"); } @Test public void readBytesFromMultipleBuffersMultipleTimes() throws IOException { final ByteBufferSlicePool pool = new ByteBufferSlicePool(5, 5); final Pooled pooledBuffer1 = pool.allocate(); final Pooled pooledBuffer2 = pool.allocate(); final ByteBuffer byteBuffer1 = ByteBuffer.allocate(1); final ByteBuffer byteBuffer2 = ByteBuffer.allocate(2); final ByteBuffer byteBuffer3 = ByteBuffer.allocate(3); byteBuffer1.put("m".getBytes("UTF-8")).flip(); pooledBuffer1.getResource().put("ultip".getBytes("UTF-8")).flip(); pooledBuffer2.getResource().put("le bu".getBytes("UTF-8")).flip(); byteBuffer2.put("ff".getBytes("UTF-8")).flip(); byteBuffer3.put("ers".getBytes("UTF-8")).flip(); assertEquals(0, stream.available()); stream.push(byteBuffer1); assertEquals(1, stream.available()); stream.push(pooledBuffer1); assertEquals(6, stream.available()); stream.push(pooledBuffer2); assertEquals(11, stream.available()); stream.push(byteBuffer2); assertEquals(13, stream.available()); stream.push(byteBuffer3); assertEquals(16, stream.available()); assertEquals('m', stream.read()); assertEquals(15, stream.available()); assertEquals('u', stream.read()); assertEquals(14, stream.available()); assertEquals('l', stream.read()); assertEquals(13, stream.available()); assertEquals('t', stream.read()); assertEquals(12, stream.available()); assertEquals('i', stream.read()); assertEquals(11, stream.available()); assertEquals('p', stream.read()); assertEquals(10, stream.available()); assertEquals('l', stream.read()); assertEquals(9, stream.available()); assertEquals('e', stream.read()); assertEquals(8, stream.available()); assertEquals(' ', stream.read()); assertEquals(7, stream.available()); assertEquals('b', stream.read()); assertEquals(6, stream.available()); assertEquals('u', stream.read()); assertEquals(5, stream.available()); assertEquals('f', stream.read()); assertEquals(4, stream.available()); assertEquals('f', stream.read()); assertEquals(3, stream.available()); assertEquals('e', stream.read()); assertEquals(2, stream.available()); assertEquals('r', stream.read()); assertEquals(1, stream.available()); assertEquals('s', stream.read()); assertEquals(0, stream.available()); assertHandledMessages(false, "m", "ultip", "le bu", "ff", "ers"); } @Test public void readByteReceivesFailure() throws IOException { final IOException exception = new IOException("test"); stream.pushException(exception); IOException failure = null; try { stream.read(); } catch (IOException e) { failure = e; } assertSame(exception, failure); assertCantPush(); assertHandledMessages(false); } @Test public void messageBytesAreNotTruncatedByFailure() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(20); buffer.put("truncated message".getBytes("UTF-8")).flip(); stream.push(buffer); assertEquals(17, stream.available()); assertEquals('t', stream.read()); assertEquals(16, stream.available()); assertEquals('r', stream.read()); assertEquals(15, stream.available()); assertEquals('u', stream.read()); assertEquals(14, stream.available()); assertEquals('n', stream.read()); assertEquals(13, stream.available()); assertEquals('c', stream.read()); assertEquals(12, stream.available()); assertEquals('a', stream.read()); assertEquals(11, stream.available()); assertEquals('t', stream.read()); assertEquals(10, stream.available()); assertEquals('e', stream.read()); assertEquals(9, stream.available()); assertEquals('d', stream.read()); assertEquals(8, stream.available()); assertEquals(' ', stream.read()); assertEquals(7, stream.available()); final IOException exception = new IOException("test"); stream.pushException(exception); assertEquals('m', stream.read()); assertEquals(6, stream.available()); assertEquals('e', stream.read()); assertEquals(5, stream.available()); assertEquals('s', stream.read()); assertEquals(4, stream.available()); assertEquals('s', stream.read()); assertEquals(3, stream.available()); assertEquals('a', stream.read()); assertEquals(2, stream.available()); assertEquals('g', stream.read()); assertEquals(1, stream.available()); assertEquals('e', stream.read()); assertEquals(0, stream.available()); IOException failure = null; try { stream.read(); } catch (IOException e) { failure = e; } assertSame(exception, failure); assertEquals(0, stream.available()); assertCantPush(); assertHandledMessages(false, "truncated message"); } @Test public void readByteWaitsForPush() throws Exception { final ByteBuffer buffer = ByteBuffer.allocate(5); buffer.put("read".getBytes("UTF-8")).flip(); assertEquals(0, stream.available()); final ReadByteTask read1 = new ReadByteTask(stream); final Thread readThread1 = new Thread(read1); final ReadByteTask read2 = new ReadByteTask(stream); final Thread readThread2 = new Thread(read2); final ReadByteTask read3 = new ReadByteTask(stream); final Thread readThread3 = new Thread(read3); final ReadByteTask read4 = new ReadByteTask(stream); final Thread readThread4 = new Thread(read4); readThread1.start(); readThread1.join(100); assertTrue(readThread1.isAlive()); stream.push(buffer); readThread1.join(); assertEquals(3, stream.available()); readThread2.start(); readThread2.join(); assertEquals(2, stream.available()); readThread3.start(); readThread3.join(); assertEquals(1, stream.available()); readThread4.start(); readThread4.join(); assertEquals(0, stream.available()); assertEquals(0, stream.available()); assertEquals('r', read1.getReadResult()); assertEquals('e', read2.getReadResult()); assertEquals('a', read3.getReadResult()); assertEquals('d', read4.getReadResult()); assertHandledMessages(false, "read"); } @Test public void readByteWaitsForFailure() throws Exception { assertEquals(0, stream.available()); final ReadByteTask read = new ReadByteTask(stream); final Thread readThread = new Thread(read); readThread.start(); readThread.join(100); assertTrue(readThread.isAlive()); final IOException failure = new IOException("test"); stream.pushException(failure); readThread.join(); assertEquals(0, stream.available()); assertEquals(0, read.getReadResult()); assertSame(failure, read.getFailure()); assertCantPush(); assertHandledMessages(false); } @Test public void readByteWaitsForEof() throws Exception { assertEquals(0, stream.available()); final ReadByteTask read = new ReadByteTask(stream); final Thread readThread = new Thread(read); readThread.start(); readThread.join(100); assertTrue(readThread.isAlive()); stream.pushEof(); readThread.join(); assertEquals(0, stream.available()); assertEquals(-1, read.getReadResult()); assertNull(read.getFailure()); assertCantPush(); assertHandledMessages(false); } @Test public void readByteWaitsForClose() throws Exception { assertEquals(0, stream.available()); final ReadByteTask read = new ReadByteTask(stream); final Thread readThread = new Thread(read); readThread.start(); readThread.join(100); assertTrue(readThread.isAlive()); stream.close(); readThread.join(); assertEquals(0, stream.available()); assertEquals(-1, read.getReadResult()); assertNull(read.getFailure()); assertCantPush(); assertHandledMessages(true); } @Test public void readBuffersAndBytes() throws IOException { final ByteBuffer buffer1 = ByteBuffer.allocate(10); buffer1.put("abcdefghij".getBytes("UTF-8")).flip(); final ByteBuffer buffer2 = ByteBuffer.allocate(10); buffer2.put("klmnopqrst".getBytes("UTF-8")).flip(); final byte[] readBuffer1 = new byte[3]; final byte[] readBuffer2 = new byte[5]; final byte[] readBuffer3 = new byte[2]; stream.push(buffer1); stream.push(buffer2); assertEquals(20, stream.available()); assertEquals(3, stream.read(readBuffer1)); assertReadMessage(readBuffer1, "abc"); assertEquals(17, stream.available()); assertEquals('d', stream.read()); assertEquals(16, stream.available()); assertEquals('e', stream.read()); assertEquals(15, stream.available()); assertEquals('f', stream.read()); assertEquals(14, stream.available()); assertEquals('g', stream.read()); assertEquals(13, stream.available()); assertEquals(5, stream.read(readBuffer2)); assertReadMessage(readBuffer2, "hijkl"); assertEquals(8, stream.available()); assertEquals('m', stream.read()); assertEquals(7, stream.available()); assertEquals(2, stream.read(readBuffer3)); assertReadMessage(readBuffer3, "no"); assertEquals(5, stream.available()); assertEquals('p', stream.read()); assertEquals(4, stream.available()); assertEquals('q', stream.read()); assertEquals(3, stream.available()); assertEquals('r', stream.read()); assertEquals(2, stream.available()); assertEquals('s', stream.read()); assertEquals(1, stream.available()); assertEquals('t', stream.read()); assertEquals(0, stream.available()); assertHandledMessages(false, "abcdefghij", "klmnopqrst"); } @Test public void concurrentReadBytes() throws Exception { final ByteBuffer buffer = ByteBuffer.allocate(20); buffer.put("ab".getBytes("UTF-8")).flip(); stream.push(buffer); assertEquals(2, stream.available()); final ReadByteTask read1 = new ReadByteTask(stream); final ReadByteTask read2 = new ReadByteTask(stream); final ReadByteTask read3 = new ReadByteTask(stream); final PushTask push = new PushTask(stream, "cde"); final Thread readThread1 = new Thread(read1, "READ1"); final Thread readThread2 = new Thread(read2, "READ2"); final Thread readThread3 = new Thread(read3, "READ3"); final Thread pushThread = new Thread(push, "PUSH"); readThread1.start(); readThread2.start(); readThread3.start(); Thread.sleep(100); pushThread.start(); readThread1.join(); readThread2.join(); readThread3.join(); pushThread.join(); int readByte1 = read1.getReadResult(); int readByte2= read2.getReadResult(); int readByte3 = read3.getReadResult(); assertTrue("Unexpected values for read results: '" + (char) readByte1 + "', '" + (char) readByte2 + "', and '" + (char) readByte3 + "'", (readByte1 == 'a' && readByte2 == 'b' && readByte3 == 'c') || (readByte1 == 'a' && readByte2 == 'c' && readByte3 == 'b') || (readByte1 == 'b' && readByte2 == 'a' && readByte3 == 'c') || (readByte1 == 'b' && readByte2 == 'c' && readByte3 == 'a') || (readByte1 == 'c' && readByte2 == 'a' && readByte3 == 'b') || (readByte1 == 'c' && readByte2 == 'b' && readByte3 == 'a')); // "cde" is not handled because it was not fully read, only the 'c' char was read from "cde" message assertHandledMessages(false, "ab"); } @Test public void skipMessage() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(3); buffer.put("abc".getBytes("UTF-8")).flip(); stream.push(buffer); assertEquals(3, stream.available()); assertEquals(3, stream.skip(3)); assertEquals(0, stream.available()); assertHandledMessages(false, "abc"); } @Test public void skipPartOfMessage() throws IOException { final ByteBufferSlicePool bufferPool = new ByteBufferSlicePool(6, 6); final Pooled pooledBuffer1 = bufferPool.allocate(); final Pooled pooledBuffer2 = bufferPool.allocate(); pooledBuffer1.getResource().put("skip ".getBytes("UTF-8")).flip(); pooledBuffer2.getResource().put("msg".getBytes("UTF-8")).flip(); assertEquals(0, stream.available()); stream.push(pooledBuffer1); assertEquals(5, stream.available()); stream.push(pooledBuffer2); assertEquals(8, stream.available()); assertEquals(5, stream.skip(4)); assertEquals(3, stream.available()); final byte[] readBuffer = new byte[6]; assertEquals(3, stream.read(readBuffer)); assertReadMessage(readBuffer, "msg"); assertEquals(0, stream.available()); assertHandledMessages(false, "skip ", "msg"); } @Test public void skipWaitsForFailure() throws Exception { assertEquals(0, stream.available()); final SkipTask skip = new SkipTask(stream, 3); final Thread skipThread = new Thread(skip); skipThread.start(); skipThread.join(100); assertTrue(skipThread.isAlive()); final IOException failure = new IOException("test"); stream.pushException(failure); skipThread.join(); assertEquals(0, stream.available()); assertEquals(0, skip.getSkipResult()); assertSame(failure, skip.getFailure()); assertHandledMessages(false); } @Test public void skipWaitsForPush() throws Exception { final ByteBuffer buffer = ByteBuffer.allocate(5); buffer.put("skip".getBytes("UTF-8")).flip(); assertEquals(0, stream.available()); final SkipTask skip = new SkipTask(stream, 10); final Thread skipThread = new Thread(skip); skipThread.start(); skipThread.join(100); assertTrue(skipThread.isAlive()); stream.push(buffer); skipThread.join(); assertEquals(0, stream.available()); assertEquals(4, skip.getSkipResult()); assertHandledMessages(false, "skip"); } @Test public void skipWaitsForEof() throws Exception { assertEquals(0, stream.available()); final SkipTask skip = new SkipTask(stream, 0); final Thread skipThread = new Thread(skip); skipThread.start(); skipThread.join(100); assertTrue(skipThread.isAlive()); stream.pushEof(); skipThread.join(); assertEquals(0, stream.available()); assertEquals(0, skip.getSkipResult()); assertNull(skip.getFailure()); assertCantPush(); assertHandledMessages(false); } @Test public void skipWaitsForClose() throws Exception { assertEquals(0, stream.available()); final SkipTask skip = new SkipTask(stream, 1); final Thread skipThread = new Thread(skip); skipThread.start(); skipThread.join(100); assertTrue(skipThread.isAlive()); stream.close(); skipThread.join(); assertEquals(0, stream.available()); assertEquals(0, skip.getSkipResult()); assertNull(skip.getFailure()); assertCantPush(); assertHandledMessages(true); } @Test public void messageIsTruncatedByClose() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(20); buffer.put("truncated message".getBytes("UTF-8")).flip(); stream.push(buffer); byte[] readBuffer = new byte[10]; assertEquals(10, stream.read(readBuffer)); assertReadMessage(readBuffer, "truncated "); stream.close(); assertEquals(-1, stream.read(readBuffer)); assertEquals(-1, stream.read()); assertEquals(0, stream.skip(7)); assertCantPush(); assertHandledMessages(true); } @Test public void messageIsNotTruncatedByEof() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(20); buffer.put("truncated message".getBytes("UTF-8")).flip(); stream.push(buffer); byte[] readBuffer = new byte[10]; assertEquals(10, stream.read(readBuffer)); assertReadMessage(readBuffer, "truncated "); stream.pushEof(); assertEquals(7, stream.read(readBuffer)); assertReadMessage(readBuffer, "message"); assertEquals(-1, stream.read(readBuffer)); // now we can't push anymore buffer.flip(); stream.push(buffer); assertEquals(0, stream.available()); assertEquals(-1, stream.read()); assertEquals(-1, stream.read(readBuffer)); assertEquals(0, stream.skip(5)); assertCantPush(); // push eof is idempotent buffer.flip(); stream.push(buffer); assertEquals(0, stream.available()); assertEquals(-1, stream.read()); assertEquals(-1, stream.read(readBuffer)); assertEquals(0, stream.skip(10)); assertCantPush(); assertHandledMessages(false, "truncated message"); } @Test public void closeEmptyStream() throws IOException { stream.close(); byte[] readBuffer = new byte[10]; assertEquals(-1, stream.read(readBuffer)); final ByteBuffer buffer = ByteBuffer.allocate(20); buffer.put("can't push".getBytes("UTF-8")).flip(); stream.push(buffer); assertEquals(0, stream.available()); assertEquals(-1, stream.read()); assertEquals(-1, stream.read(readBuffer)); assertEquals(0, stream.skip(11)); assertCantPush(); // close is idempotent stream.close(); assertEquals(-1, stream.read()); assertEquals(-1, stream.read(readBuffer)); assertEquals(0, stream.skip(1000)); assertCantPush(); stream.pushException(new IOException("test")); assertHandledMessages(true); } public static class TestInputHandler implements BufferPipeInputStream.InputHandler { private Collection messages = new ArrayList(); private boolean closed = false; @Override public void acknowledge(Pooled pooled) throws IOException { if (closed) { fail("Stream is closed already"); } pooled.getResource().flip(); messages.add(Buffers.getModifiedUtf8(pooled.getResource())); } @Override public void close() throws IOException { closed = true; } public Iterator getHandledMessages() { return messages.iterator(); } public boolean isClosed() { return closed; } } private void assertHandledMessages(boolean closed, String... messages) { final Iterator handledMessages = handler.getHandledMessages(); for (String message: messages) { try { assertEquals(message, handledMessages.next()); } catch (NoSuchElementException e) { fail("Message " + message + " is not handled"); } } assertFalse("There is one or more unexpected handled messages", handledMessages.hasNext()); assertEquals(closed, handler.isClosed()); } private void assertCantPush() throws IOException, UnsupportedEncodingException { // once a failure has been pushed, we can't push anything else assertEquals(0, stream.available()); final ByteBufferSlicePool bufferPool = new ByteBufferSlicePool(5, 5); final Pooled pooledBuffer = bufferPool.allocate(); pooledBuffer.getResource().put("test".getBytes("UTF-8")).flip(); stream.push(pooledBuffer.getResource()); assertEquals(0, stream.available()); stream.push(pooledBuffer); assertEquals(0, stream.available()); // check pooledBuffer resource is freed IllegalStateException expected = null; try { pooledBuffer.getResource(); } catch (IllegalStateException e) { expected = e; } assertNotNull(expected); } private static class PushTask implements Runnable { private final BufferPipeInputStream stream; private final String message; public PushTask(BufferPipeInputStream s, String m) { stream = s; message = m; } public void run() { final ByteBuffer buffer = ByteBuffer.allocate(message.length()); try { buffer.put(message.getBytes("UTF-8")).flip(); } catch (UnsupportedEncodingException e) { e.printStackTrace(); throw new RuntimeException(e); } stream.push(buffer); } } private static class ReadTask implements Runnable { private final BufferPipeInputStream stream; private final int length; private int readResult; private byte[] readBuffer; private IOException failure; public ReadTask(BufferPipeInputStream s) { this(s, -1); } public ReadTask(BufferPipeInputStream s, int l) { stream = s; length = l; } @Override public void run() { readBuffer = length == -1? new byte[50]: new byte[length]; try { readResult = stream.read(readBuffer); } catch (IOException e) { failure = e; } } public int getReadResult() { return readResult; } public byte[] getReadBuffer() { return readBuffer; } public IOException getFailure() { return failure; } } private static class ReadByteTask implements Runnable { private final BufferPipeInputStream stream; private int readResult; private IOException failure; public ReadByteTask(BufferPipeInputStream s) { stream = s; } @Override public void run() { try { readResult = stream.read(); } catch (IOException e) { failure = e; } } public int getReadResult() { return readResult; } public IOException getFailure() { return failure; } } private static class SkipTask implements Runnable { private final BufferPipeInputStream stream; private final int howManyBytes; private long skipResult; private IOException failure; public SkipTask(BufferPipeInputStream s, int l) { stream = s; howManyBytes = l; } @Override public void run() { try { skipResult = stream.skip(howManyBytes); } catch (IOException e) { failure = e; } } public long getSkipResult() { return skipResult; } public IOException getFailure() { return failure; } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/streams/BufferPipeOutputStreamTestCase.java000066400000000000000000000303101257016060700311320ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.streams; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.List; import org.junit.Before; import org.junit.Test; import org.xnio.Buffers; import org.xnio.ByteBufferSlicePool; import org.xnio.Pooled; /** * Test for {@link BufferPipeOutputStream}. * * @author Flavia Rainone * */ public class BufferPipeOutputStreamTestCase { private BufferPipeOutputStream stream; private TestBufferWriter bufferWriter; @Before public void init() throws IOException { bufferWriter = new TestBufferWriter(); stream = new BufferPipeOutputStream(bufferWriter); } @Test public void writeAndFlush() throws IOException { stream.write("test".getBytes("UTF-8")); assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); stream.flush(); List> acceptedBuffers = bufferWriter.getAcceptedBuffers(); assertEquals(1, acceptedBuffers.size()); assertAcceptedMessage(acceptedBuffers.get(0).getResource(), "test"); } @Test public void writeBytesAndFlush() throws IOException { stream.write('b'); stream.write('y'); stream.write('t'); stream.write('e'); stream.write('s'); assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); stream.flush(); List> acceptedBuffers = bufferWriter.getAcceptedBuffers(); assertEquals(1, acceptedBuffers.size()); assertAcceptedMessage(acceptedBuffers.get(0).getResource(), "bytes"); } @Test public void writeAndFlushRepeatedly() throws IOException { // flush empty stream stream.flush(); // nothing happens assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); stream.write("test".getBytes("UTF-8")); assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); stream.flush(); stream.write("repeatedly".getBytes("UTF-8")); assertEquals(2, bufferWriter.getAcceptedBuffers().size()); // flush more than once, flush should be idempotent stream.flush(); stream.flush(); stream.write("again".getBytes("UTF-8")); assertEquals(3, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("and again".getBytes("UTF-8")); assertEquals(5, bufferWriter.getAcceptedBuffers().size()); stream.flush(); List> acceptedBuffers = bufferWriter.getAcceptedBuffers(); assertEquals(6, acceptedBuffers.size()); assertAcceptedMessage(acceptedBuffers.get(0).getResource(), "test"); assertAcceptedMessage(acceptedBuffers.get(1).getResource(), "repea"); assertAcceptedMessage(acceptedBuffers.get(2).getResource(), "tedly"); assertAcceptedMessage(acceptedBuffers.get(3).getResource(), "again"); assertAcceptedMessage(acceptedBuffers.get(4).getResource(), "and a"); assertAcceptedMessage(acceptedBuffers.get(5).getResource(), "gain"); } @Test public void writeBytesAndFlushRepeatedly() throws IOException { stream.write("r".getBytes("UTF-8")); assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); stream.flush(); stream.write("e".getBytes("UTF-8")); assertEquals(1, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("p".getBytes("UTF-8")); assertEquals(2, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("e".getBytes("UTF-8")); assertEquals(3, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("a".getBytes("UTF-8")); assertEquals(4, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("t".getBytes("UTF-8")); assertEquals(5, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("e".getBytes("UTF-8")); assertEquals(6, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("d".getBytes("UTF-8")); assertEquals(7, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("l".getBytes("UTF-8")); assertEquals(8, bufferWriter.getAcceptedBuffers().size()); stream.flush(); stream.write("y".getBytes("UTF-8")); assertEquals(9, bufferWriter.getAcceptedBuffers().size()); // flush more than once, flush should be idempotent stream.flush(); stream.flush(); List> acceptedBuffers = bufferWriter.getAcceptedBuffers(); assertEquals(10, acceptedBuffers.size()); assertAcceptedMessage(acceptedBuffers.get(0).getResource(), "r"); assertAcceptedMessage(acceptedBuffers.get(1).getResource(), "e"); assertAcceptedMessage(acceptedBuffers.get(2).getResource(), "p"); assertAcceptedMessage(acceptedBuffers.get(3).getResource(), "e"); assertAcceptedMessage(acceptedBuffers.get(4).getResource(), "a"); assertAcceptedMessage(acceptedBuffers.get(5).getResource(), "t"); assertAcceptedMessage(acceptedBuffers.get(6).getResource(), "e"); assertAcceptedMessage(acceptedBuffers.get(7).getResource(), "d"); assertAcceptedMessage(acceptedBuffers.get(8).getResource(), "l"); assertAcceptedMessage(acceptedBuffers.get(9).getResource(), "y"); } @Test public void closeEmptyStream() throws IOException { assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); assertTrue(bufferWriter.isFlushed()); assertFalse(bufferWriter.isEof()); stream.close(); assertClosedChannel(true, true, 1, ""); } @Test public void close() throws IOException { assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); assertTrue(bufferWriter.isFlushed()); assertFalse(bufferWriter.isEof()); stream.write("test".getBytes()); assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); assertTrue(bufferWriter.isFlushed()); assertFalse(bufferWriter.isEof()); stream.close(); assertClosedChannel(true, true, 1, "test"); } @Test public void bufferWriterAcceptThrowsIOException() throws IOException { stream.write("12345".getBytes("UTF-8")); assertTrue(bufferWriter.getAcceptedBuffers().isEmpty()); assertTrue(bufferWriter.isFlushed()); assertFalse(bufferWriter.isEof()); bufferWriter.throwIOExceptionOnAccept(); IOException exceptionThrownByAccept = null; try { stream.write("won't accept".getBytes("UTF-8")); } catch (IOException e) { exceptionThrownByAccept = e; } assertNotNull(exceptionThrownByAccept); assertClosedChannel(true, false, 0); } @Test public void bufferWriterFlushThrowsIOException() throws IOException { stream.write('1'); stream.write("23456".getBytes("UTF-8")); List> acceptedBuffers = bufferWriter.getAcceptedBuffers(); assertEquals(1, acceptedBuffers.size()); assertAcceptedMessage(acceptedBuffers.get(0).getResource(), "12345"); assertFalse(bufferWriter.isFlushed()); assertFalse(bufferWriter.isEof()); bufferWriter.throwIOExceptionOnFlush(); IOException exceptionThrownByFlush = null; try { stream.flush(); } catch (IOException e) { exceptionThrownByFlush= e; } assertNotNull(exceptionThrownByFlush); acceptedBuffers.get(0).getResource().flip(); assertClosedChannel(false, false, 2, "12345", "6"); } private void assertClosedChannel(boolean flushed, boolean flushedEof, int numberOfAcceptedBuffers, String... bufferContents) throws IOException { List> acceptedBuffers = bufferWriter.getAcceptedBuffers(); assertEquals(numberOfAcceptedBuffers, acceptedBuffers.size()); for (int i = 0; i < bufferContents.length; i++) { assertAcceptedMessage(acceptedBuffers.get(i).getResource(), bufferContents[i]); } assertEquals(flushed, bufferWriter.isFlushed()); assertEquals(flushedEof, bufferWriter.isEof()); // close is idempotent stream.close(); assertEquals(numberOfAcceptedBuffers, bufferWriter.getAcceptedBuffers().size()); assertEquals(flushed, bufferWriter.isFlushed()); assertEquals(flushedEof, bufferWriter.isEof()); // can't write IOException cantWriteException = null; try { stream.write("can't write this".getBytes()); } catch (IOException e) { cantWriteException = e; } assertNotNull(cantWriteException); cantWriteException = null; try { stream.write('a'); } catch (IOException e) { cantWriteException = e; } assertNotNull(cantWriteException); // flushing is useless after closed stream.flush(); assertEquals(numberOfAcceptedBuffers, bufferWriter.getAcceptedBuffers().size()); assertEquals(flushed, bufferWriter.isFlushed()); assertEquals(flushedEof, bufferWriter.isEof()); } private static final void assertAcceptedMessage(ByteBuffer dst, String... message) { final StringBuffer stringBuffer = new StringBuffer(); for (String messageString: message) { stringBuffer.append(messageString); } assertEquals(stringBuffer.toString(), Buffers.getModifiedUtf8(dst)); } private static class TestBufferWriter implements BufferPipeOutputStream.BufferWriter { private ByteBufferSlicePool bufferPool = new ByteBufferSlicePool(5, 10); private List> acceptedBuffers = new ArrayList>(); private boolean eof = false;; private boolean flushed = true; private boolean throwIOExceptionOnAccept = false; private boolean throwIOExceptionOnFlush = false; @Override public Pooled getBuffer(boolean firstBuffer) throws IOException { return bufferPool.allocate(); } @Override public void accept(Pooled pooledBuffer, boolean eof) throws IOException { if (throwIOExceptionOnAccept) { throwIOExceptionOnAccept = false; throw new IOException("test requested bufferWriter to throw IOException on accept"); } acceptedBuffers.add(pooledBuffer); this.eof = this.eof || eof; flushed = false; } @Override public void flush() throws IOException { if (throwIOExceptionOnFlush) { throwIOExceptionOnFlush = false; throw new IOException("test requested bufferWriter to throw IOException on flush"); } flushed = true; } public boolean isFlushed() { return flushed; } public List> getAcceptedBuffers() { return acceptedBuffers; } public boolean isEof() { return eof; } public void throwIOExceptionOnAccept() { throwIOExceptionOnAccept = true; } public void throwIOExceptionOnFlush() { throwIOExceptionOnFlush = true; } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/streams/BufferedChannelInputStreamTestCase.java000066400000000000000000000160471257016060700317300ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.streams; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.nio.channels.ClosedChannelException; import java.util.concurrent.TimeUnit; import org.junit.Test; import org.xnio.channels.StreamSourceChannel; import org.xnio.mock.ConnectedStreamChannelMock; /** * Test for {@link BufferedChannelInputStream}. * * @author Flavia Rainone */ public class BufferedChannelInputStreamTestCase extends AbstractChannelInputStreamTest{ @Test public void illegalBufferSizeArgument() { final ConnectedStreamChannelMock sourceChannel = new ConnectedStreamChannelMock(); IllegalArgumentException constructorException = null; // buffer sized 0 try { new BufferedChannelInputStream(sourceChannel, 0); } catch (IllegalArgumentException e) { constructorException = e; } assertNotNull(constructorException); constructorException = null; try { new BufferedChannelInputStream(sourceChannel, 0, 100, TimeUnit.MILLISECONDS); } catch (IllegalArgumentException e) { constructorException = e; } assertNotNull(constructorException); constructorException = null; // buffer size < 0 try { new BufferedChannelInputStream(sourceChannel, -2); } catch (IllegalArgumentException e) { constructorException = e; } assertNotNull(constructorException); constructorException = null; try { new BufferedChannelInputStream(sourceChannel, -5, 5000, TimeUnit.MICROSECONDS); } catch (IllegalArgumentException e) { constructorException = e; } assertNotNull(constructorException); constructorException = null; } @Test public void skipBlocks() throws Exception { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final BufferedChannelInputStream stream = createChannelInputStream(channelMock, 10); channelMock.setReadData("skip all"); channelMock.enableRead(true); SkipBytesTask skipTask = new SkipBytesTask(stream, 16); Thread skipBytesThread = new Thread(skipTask); skipBytesThread.start(); skipBytesThread.join(200); assertTrue(skipBytesThread.isAlive()); channelMock.setReadData("moredataskip"); skipBytesThread.join(); assertEquals(16, skipTask.getSkipResult()); // try again skipBytesThread = new Thread(skipTask); skipBytesThread.start(); skipBytesThread.join(200); assertTrue(skipBytesThread.isAlive()); channelMock.setReadData(" all this - data - and a little bit more"); skipBytesThread.join(); assertEquals(16, skipTask.getSkipResult()); assertAvailableBytes(stream, 10, 28); assertEquals('d', stream.read()); assertEquals('a', stream.read()); assertEquals('t', stream.read()); assertEquals('a', stream.read()); // one more time skipTask = new SkipBytesTask(stream, 50); skipBytesThread = new Thread(skipTask); skipBytesThread.start(); skipBytesThread.join(200); assertTrue(skipBytesThread.isAlive()); channelMock.setEof(); skipBytesThread.join(); assertEquals(24, skipTask.getSkipResult()); } @Test public void availableThrowsIOException() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); channelMock.close(); // channel mock will always throw ClosedChannelException final BufferedChannelInputStream stream = createChannelInputStream(channelMock, 10); // try to check availability, test twice to make sure that buffer is kept consistent ClosedChannelException expected = null; try { stream.available(); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.available(); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); } @Test public void close() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final BufferedChannelInputStream stream = createChannelInputStream(channelMock, 5); channelMock.setReadData("12345"); channelMock.enableRead(true); assertAvailableBytes(stream, 5, 5); // close! stream.close(); channelMock.setReadData("67890"); assertAvailableBytes(stream, 0, 0); assertEquals(-1, stream.read()); assertEquals(0, stream.skip(2)); assertEquals(-1, stream.read()); assertEquals(-1, stream.read(new byte[10])); assertEquals(0, stream.skip(3)); // close is idempotent stream.close(); assertAvailableBytes(stream, 0, 0); assertEquals(-1, stream.read()); assertEquals(-1, stream.read(new byte[10])); assertEquals(0, stream.skip(3)); } @Override protected BufferedChannelInputStream createChannelInputStream(StreamSourceChannel sourceChannel, int internalBufferSize) { return new BufferedChannelInputStream(sourceChannel, internalBufferSize); } @Override protected BufferedChannelInputStream createChannelInputStream(StreamSourceChannel sourceChannel, long timeout, TimeUnit timeUnit, int internalBufferSize) { return new BufferedChannelInputStream(sourceChannel, internalBufferSize, timeout, timeUnit); } @Override protected long getReadTimeout(BufferedChannelInputStream stream, TimeUnit timeUnit) { return stream.getReadTimeout(timeUnit); } @Override protected void setReadTimeout(BufferedChannelInputStream stream, int timeout, TimeUnit timeUnit) { stream.setReadTimeout(timeout, timeUnit); } @Override protected void assertAvailableBytes(BufferedChannelInputStream stream, int availableInBuffer, int availableTotal) throws IOException { assertEquals(availableInBuffer, stream.available()); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/streams/ChannelInputStreamTestCase.java000066400000000000000000000112701257016060700302560ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.streams; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.util.concurrent.TimeUnit; import org.junit.Test; import org.xnio.channels.StreamSourceChannel; import org.xnio.mock.ConnectedStreamChannelMock; /** * Test for {@link ChannelInputStream}. * * @author Flavia Rainone */ public class ChannelInputStreamTestCase extends AbstractChannelInputStreamTest { @Test public void close() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final ChannelInputStream stream = new ChannelInputStream(channelMock); channelMock.setReadData("12345"); channelMock.enableRead(true); assertEquals(0, stream.available()); // close! stream.close(); channelMock.setReadData("67890"); assertEquals(0, stream.available()); assertEquals(-1, stream.read()); assertEquals(-1, stream.read(new byte[10])); assertEquals(0, stream.skip(3)); // close is idempotent stream.close(); assertEquals(0, stream.available()); assertEquals(-1, stream.read()); assertEquals(-1, stream.read(new byte[10])); assertEquals(0, stream.skip(3)); } @Test public void skipBlocks() throws Exception { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final ChannelInputStream stream = new ChannelInputStream(channelMock); channelMock.setReadData("skip all"); channelMock.enableRead(false); SkipBytesTask skipTask = new SkipBytesTask(stream, 16); Thread skipBytesThread = new Thread(skipTask); skipBytesThread.start(); skipBytesThread.join(200); assertTrue(skipBytesThread.isAlive()); channelMock.enableRead(true); skipBytesThread.join(200); assertTrue(skipBytesThread.isAlive()); channelMock.setReadData("moredataskip"); skipBytesThread.join(); assertEquals(16, skipTask.getSkipResult()); // try again skipBytesThread = new Thread(skipTask); skipBytesThread.start(); skipBytesThread.join(200); assertTrue(skipBytesThread.isAlive()); channelMock.setReadData(" all this - data - and a little bit more"); skipBytesThread.join(); assertEquals(16, skipTask.getSkipResult()); assertAvailableBytes(stream, 10, 28); assertEquals('d', stream.read()); assertEquals('a', stream.read()); assertEquals('t', stream.read()); assertEquals('a', stream.read()); // one more time skipTask = new SkipBytesTask(stream, 50); skipBytesThread = new Thread(skipTask); skipBytesThread.start(); skipBytesThread.join(200); assertTrue(skipBytesThread.isAlive()); channelMock.setEof(); skipBytesThread.join(); assertEquals(24, skipTask.getSkipResult()); } @Override protected ChannelInputStream createChannelInputStream(StreamSourceChannel sourceChannel, int internalBufferSize) { return new ChannelInputStream(sourceChannel); } @Override protected ChannelInputStream createChannelInputStream(StreamSourceChannel sourceChannel, long timeout, TimeUnit timeUnit, int internalBufferSize) { return new ChannelInputStream(sourceChannel, timeout, timeUnit); } @Override protected long getReadTimeout(ChannelInputStream stream, TimeUnit timeUnit) { return stream.getReadTimeout(timeUnit); } @Override protected void setReadTimeout(ChannelInputStream stream, int timeout, TimeUnit timeUnit) { stream.setReadTimeout(timeout, timeUnit); } @Override protected void assertAvailableBytes(ChannelInputStream stream, int availableInBuffer, int availableTotal) throws IOException { assertEquals(0, stream.available()); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/streams/ChannelOutputStreamTestCase.java000066400000000000000000000427241257016060700304670ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.streams; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.xnio.AssertReadWrite.assertWrittenMessage; import java.io.IOException; import java.nio.channels.ClosedChannelException; import java.util.concurrent.TimeUnit; import org.junit.Test; import org.xnio.channels.WriteTimeoutException; import org.xnio.mock.ConnectedStreamChannelMock; /** * Test for {@link ChannelOutputStream}. * * @author Flavia Rainone */ public class ChannelOutputStreamTestCase extends AbstractChannelStreamTest { @Test public void illegalConstructorArguments() { // try with null sinkChannel IllegalArgumentException expected = null; try { new ChannelOutputStream(null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { new ChannelOutputStream(null, 10, TimeUnit.SECONDS); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); // try with null timeout unit final ConnectedStreamChannelMock sinkChannel = new ConnectedStreamChannelMock(); expected = null; try { new ChannelOutputStream(sinkChannel, 5, null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); // try with negative timeout expected = null; try { new ChannelOutputStream(sinkChannel, -1, TimeUnit.MICROSECONDS); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { new ChannelOutputStream(sinkChannel, -60, TimeUnit.SECONDS); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void writeBytesAndByteArrays() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final ChannelOutputStream stream = new ChannelOutputStream(channelMock); channelMock.setReadData("data"); channelMock.enableWrite(true); assertWrittenMessage(channelMock); stream.write('d'); assertWrittenMessage(channelMock, "d"); stream.write('a'); assertWrittenMessage(channelMock, "da"); stream.write('t'); assertWrittenMessage(channelMock, "dat"); stream.write('a'); assertWrittenMessage(channelMock, "data"); stream.write(" more data".getBytes("UTF-8"), 1, 9); assertWrittenMessage(channelMock, "data", "more data"); } @Test public void writeByteArraysAndBytes() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final ChannelOutputStream stream = new ChannelOutputStream(channelMock); channelMock.enableWrite(true); stream.write("data".getBytes("UTF-8")); assertWrittenMessage(channelMock, "data"); stream.write('m'); assertWrittenMessage(channelMock, "data", "m"); stream.write('o'); assertWrittenMessage(channelMock, "data", "mo"); stream.write('r'); assertWrittenMessage(channelMock, "data", "mor"); stream.write('e'); assertWrittenMessage(channelMock, "data", "more"); stream.write(' '); assertWrittenMessage(channelMock, "data", "more "); stream.write('d'); assertWrittenMessage(channelMock, "data", "more d"); stream.write('a'); assertWrittenMessage(channelMock, "data", "more da"); stream.write('t'); assertWrittenMessage(channelMock, "data", "more dat"); stream.write('a'); assertWrittenMessage(channelMock, "data", "more data"); } @Test public void writeBlocks() throws Exception { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); channelMock.enableWrite(false); final ChannelOutputStream stream = new ChannelOutputStream(channelMock); // create and start write thread final WriteByteTask writeByteTask = new WriteByteTask(stream, (byte) 'w'); final Thread writeByteThread = new Thread(writeByteTask); writeByteThread.start(); // thread cant complete writeByteThread.join(200); assertTrue(writeByteThread.isAlive()); // enable write, now thread can complete with a result channelMock.enableWrite(true); writeByteThread.join(); assertWrittenMessage(channelMock, "w"); } @Test public void writeByteArrayBlocks1() throws Exception { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); channelMock.enableWrite(false); final ChannelOutputStream stream = new ChannelOutputStream(channelMock); // create and start write thread final WriteBytesTask writeBytesTask = new WriteBytesTask(stream, "stream write blocks until channel write is enabled".getBytes("UTF-8")); final Thread writeBytesThread = new Thread(writeBytesTask); writeBytesThread.start(); // thread cant complete writeBytesThread.join(200); assertTrue(writeBytesThread.isAlive()); // enable write, now thread can complete with a result channelMock.enableWrite(true); writeBytesThread.join(); assertWrittenMessage(channelMock, "stream write blocks until channel write is enabled"); } @Test public void writeByteArrayBlocks2() throws Exception { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); channelMock.enableWrite(false); final ChannelOutputStream stream = new ChannelOutputStream(channelMock); // create and start write thread final WriteBytesTask writeBytesTask = new WriteBytesTask(stream, "write blocks".getBytes("UTF-8")); final Thread writeBytesThread = new Thread(writeBytesTask); writeBytesThread.start(); // thread cant complete writeBytesThread.join(200); assertTrue(writeBytesThread.isAlive()); // enable write, now thread can complete with a result channelMock.enableWrite(true); writeBytesThread.join(); assertWrittenMessage(channelMock, "write blocks"); } @Test public void flushBlocks() throws Exception { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); channelMock.enableWrite(true); channelMock.enableFlush(false); final ChannelOutputStream stream = new ChannelOutputStream(channelMock); stream.write("flush".getBytes("UTF-8")); assertWrittenMessage(channelMock, "flush"); assertFalse(channelMock.isFlushed()); // try to flush final FlushTask flushTask = new FlushTask(stream); final Thread flushThread = new Thread(flushTask); flushThread.start(); flushThread.join(200); assertTrue(flushThread.isAlive()); assertFalse(channelMock.isFlushed()); channelMock.enableFlush(true); flushThread.join(); assertTrue(channelMock.isFlushed()); assertWrittenMessage(channelMock, "flush"); } @Test public void writeBytesAndByteArraysWithTimeout() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); channelMock.enableWrite(false); final ChannelOutputStream stream = new ChannelOutputStream(channelMock, 0, TimeUnit.MICROSECONDS); assertEquals(0, stream.getWriteTimeout(TimeUnit.MICROSECONDS)); assertEquals(0, stream.getWriteTimeout(TimeUnit.MILLISECONDS)); stream.setWriteTimeout(100, TimeUnit.MILLISECONDS); assertEquals(100, stream.getWriteTimeout(TimeUnit.MILLISECONDS)); // start write test WriteTimeoutException expectedException = null; try { stream.write('a'); } catch (WriteTimeoutException e) { expectedException = e; } assertNotNull(expectedException); channelMock.setReadData("data"); channelMock.enableWrite(true); assertWrittenMessage(channelMock); stream.write('d'); stream.write('a'); stream.write('t'); stream.write('a'); assertWrittenMessage(channelMock, "data"); channelMock.enableWrite(false); expectedException = null; try { stream.write('a'); } catch (WriteTimeoutException e) { expectedException = e; } assertNotNull(expectedException); expectedException = null; try { stream.write("abc".getBytes("UTF-8")); } catch (WriteTimeoutException e) { expectedException = e; } assertNotNull(expectedException); channelMock.enableWrite(true); stream.write("#more data".getBytes("UTF-8"), 1, 9); assertWrittenMessage(channelMock, "data", "more data"); } @Test public void writeByteArraysAndBytesWithTimeout() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); channelMock.enableWrite(false); // try using 10 microseconds, timeout value is not rounded up to 1 millisecond final ChannelOutputStream stream = new ChannelOutputStream(channelMock, 10, TimeUnit.MICROSECONDS); assertEquals(10, stream.getWriteTimeout(TimeUnit.MICROSECONDS)); assertEquals(0, stream.getWriteTimeout(TimeUnit.MILLISECONDS)); stream.setWriteTimeout(200, TimeUnit.MILLISECONDS); assertEquals(200, stream.getWriteTimeout(TimeUnit.MILLISECONDS)); // start write test WriteTimeoutException expectedException = null; try { stream.write("abc".getBytes("UTF-8")); } catch (WriteTimeoutException e) { expectedException = e; } assertNotNull(expectedException); channelMock.setReadData("data"); channelMock.enableWrite(true); final byte[] bytes = "data".getBytes("UTF-8"); stream.write(bytes, 0, -3); assertWrittenMessage(channelMock); stream.write(bytes); assertWrittenMessage(channelMock, "data"); channelMock.enableWrite(false); expectedException = null; try { stream.write('a'); } catch (WriteTimeoutException e) { expectedException = e; } assertNotNull(expectedException); expectedException = null; try { stream.write("abc".getBytes("UTF-8")); } catch (WriteTimeoutException e) { expectedException = e; } assertNotNull(expectedException); channelMock.enableWrite(true); stream.write('m'); assertWrittenMessage(channelMock, "data", "m"); stream.write('o'); assertWrittenMessage(channelMock, "data", "mo"); stream.write('r'); assertWrittenMessage(channelMock, "data", "mor"); stream.write('e'); assertWrittenMessage(channelMock, "data", "more"); } @Test public void writeThrowsException() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); channelMock.close(); // channel mock will always throw ClosedChannelException final ChannelOutputStream stream = new ChannelOutputStream(channelMock); // try to write, test twice to make sure that buffer is kept consistent ClosedChannelException expected = null; try { stream.write('a'); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.write('a'); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); // try to write bytes, test twice to make sure that buffer is kept consistent expected = null; try { stream.write("abc".getBytes("UTF-8")); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.write("abc".getBytes("UTF-8")); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); } @Test public void close() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final ChannelOutputStream stream = new ChannelOutputStream(channelMock); channelMock.enableWrite(true); // close! stream.close(); IOException expected = null; try { stream.write('a'); } catch (IOException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.write("abc".getBytes("UTF-8")); } catch (IOException e) { expected = e; } assertNotNull(expected); // close is idempotent stream.close(); expected = null; try { stream.write('a'); } catch (IOException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.write("abc".getBytes("UTF-8")); } catch (IOException e) { expected = e; } assertNotNull(expected); } @Test public void closeStreamWithTimeout() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final ChannelOutputStream stream = new ChannelOutputStream(channelMock, 15, TimeUnit.MILLISECONDS); channelMock.enableWrite(true); // close! stream.close(); IOException expected = null; try { stream.write('a'); } catch (IOException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.write("abc".getBytes("UTF-8")); } catch (IOException e) { expected = e; } assertNotNull(expected); // close is idempotent stream.close(); expected = null; try { stream.write('a'); } catch (IOException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.write("abc".getBytes("UTF-8")); } catch (IOException e) { expected = e; } assertNotNull(expected); } @Override protected long getOperationTimeout(ChannelOutputStream stream, TimeUnit timeUnit) { return stream.getWriteTimeout(timeUnit); } @Override protected void setOperationTimeout(ChannelOutputStream stream, int timeout, TimeUnit timeUnit) { stream.setWriteTimeout(timeout, timeUnit); } @Override protected ChannelOutputStream createChannelStream(long timeout, TimeUnit timeUnit) { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); return new ChannelOutputStream(channelMock, timeout, timeUnit); } private class WriteByteTask implements Runnable { private final ChannelOutputStream stream; private final byte writeByte; public WriteByteTask(ChannelOutputStream s, byte b) { stream = s; writeByte = b; } @Override public void run() { try { stream.write(writeByte); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } } private class WriteBytesTask implements Runnable { private final ChannelOutputStream stream; private final byte[] bytes; public WriteBytesTask(ChannelOutputStream s, byte[] b) { stream = s; bytes = b; } @Override public void run() { try { stream.write(bytes); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } } private class FlushTask implements Runnable { private final ChannelOutputStream stream; public FlushTask(ChannelOutputStream s) { stream = s; } @Override public void run() { try { stream.flush(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/streams/LimitedInputStreamTestCase.java000066400000000000000000000173361257016060700303060ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.streams; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import java.io.ByteArrayInputStream; import java.io.IOException; import org.junit.Test; /** * Test for {@link LimitedInputStream}. * * @author Flavia Rainone */ public class LimitedInputStreamTestCase { @Test public void limitSizeIsLessThenAvailable1() throws IOException { final ByteArrayInputStream delegateStream = new ByteArrayInputStream(new byte[] {'t', 'e', 's', 't'}); final LimitedInputStream stream = new LimitedInputStream(delegateStream, 2); assertEquals(2, stream.available()); assertEquals('t', stream.read()); assertEquals('e', stream.read()); assertEquals(-1, stream.read()); } @Test public void limitSizeIsLessThenAvailable2() throws IOException { final ByteArrayInputStream delegateStream = new ByteArrayInputStream(new byte[] {'a', 'r', 'r', 'a', 'y'}); final LimitedInputStream stream = new LimitedInputStream(delegateStream, 4); final byte[] bytes = new byte[10]; assertEquals(4, stream.available()); assertEquals(4, stream.read(bytes)); assertEquals('a', bytes[0]); assertEquals('r', bytes[1]); assertEquals('r', bytes[2]); assertEquals('a', bytes[3]); assertEquals(-1, stream.read(bytes)); } @Test public void limitSizeIsEqualToAvailable1() throws IOException { final ByteArrayInputStream delegateStream = new ByteArrayInputStream(new byte[] {'t', 'e', 's', 't'}); final LimitedInputStream stream = new LimitedInputStream(delegateStream, 4); assertEquals(4, stream.available()); assertEquals('t', stream.read()); assertEquals('e', stream.read()); assertEquals('s', stream.read()); assertEquals('t', stream.read()); assertEquals(-1, stream.read()); } @Test public void limitSizeIsEqualToAvailable2() throws IOException { final ByteArrayInputStream delegateStream = new ByteArrayInputStream(new byte[] {'a', 'b', 'c'}); final LimitedInputStream stream = new LimitedInputStream(delegateStream, 3); final byte[] bytes = new byte[5]; assertEquals(3, stream.available()); assertEquals(3, stream.read(bytes)); assertEquals('a', bytes[0]); assertEquals('b', bytes[1]); assertEquals('c', bytes[2]); assertEquals(-1, stream.read(bytes)); } @Test public void limitSizeIsMoreThanAvailable1() throws IOException { final ByteArrayInputStream delegateStream = new ByteArrayInputStream(new byte[] {'t', 'e', 's', 't'}); final LimitedInputStream stream = new LimitedInputStream(delegateStream, 10); assertEquals(4, stream.available()); assertEquals('t', stream.read()); assertEquals('e', stream.read()); assertEquals('s', stream.read()); assertEquals('t', stream.read()); assertEquals(-1, stream.read()); } @Test public void limitSizeIsMoreThanAvailable2() throws IOException { final ByteArrayInputStream delegateStream = new ByteArrayInputStream(new byte[] {'m', 'o', 'r', 'e'}); final LimitedInputStream stream = new LimitedInputStream(delegateStream, 5); final byte[] bytes = new byte[5]; assertEquals(4, stream.available()); assertEquals(4, stream.read(bytes)); assertEquals('m', bytes[0]); assertEquals('o', bytes[1]); assertEquals('r', bytes[2]); assertEquals('e', bytes[3]); assertEquals(-1, stream.read(bytes)); } @Test public void skipWithLimitSizeLessThenAvailable() throws IOException { final ByteArrayInputStream delegateStream = new ByteArrayInputStream(new byte[] {'s', 'k', 'i', 'p', 'p', 'i', 'k', 's'}); final LimitedInputStream stream = new LimitedInputStream(delegateStream, 6); assertEquals(0, stream.skip(-5)); assertEquals(6, stream.available()); assertEquals(2, stream.skip(2)); assertEquals(4, stream.available()); assertEquals(4, stream.skip(10)); assertEquals(0, stream.available()); assertEquals(0, stream.skip(10)); } @Test public void skipWithLimitSizeEqualToAvailable() throws IOException { final ByteArrayInputStream delegateStream = new ByteArrayInputStream(new byte[] {'s', 'k', 'i', 'p', 'p', 'i', 'k', 's'}); final LimitedInputStream stream = new LimitedInputStream(delegateStream, 8); assertEquals(0, stream.skip(-1)); assertEquals(8, stream.available()); assertEquals(8, stream.skip(8)); assertEquals(0, stream.available()); assertEquals(0, stream.skip(3)); assertEquals(0, stream.available()); } @Test public void skipWithLimitSizeMoreThanAvailable() throws IOException { final ByteArrayInputStream delegateStream = new ByteArrayInputStream(new byte[] {'s', 'k', 'i', 'p', 'p', 'i', 'k', 's'}); final LimitedInputStream stream = new LimitedInputStream(delegateStream, 9); assertEquals(0, stream.skip(0)); assertEquals(8, stream.available()); assertEquals(5, stream.skip(5)); assertEquals(3, stream.available()); assertEquals(3, stream.skip(10)); assertEquals(0, stream.available()); assertEquals(0, stream.skip(10)); } @Test public void closeStream() throws IOException { final ByteArrayInputStream delegateStream = new ByteArrayInputStream(new byte[] {'c', 'l', 'o', 's', 'e'}); final LimitedInputStream stream = new LimitedInputStream(delegateStream, 10); assertEquals(5, stream.available()); stream.close(); assertEquals(0, stream.available()); assertEquals(-1, stream.read()); assertEquals(-1, stream.read(new byte[3])); } @Test public void markAndReset() throws IOException { final ByteArrayInputStream delegateStream = new ByteArrayInputStream(new byte[] {'m', 'a', 'r', 'k', 'r', 'e', 's', 'e', 't'}); final LimitedInputStream stream = new LimitedInputStream(delegateStream, 8); IOException expected = null; try { stream.reset(); } catch (IOException e) { expected = e; } assertNotNull(expected); assertTrue(stream.markSupported()); assertEquals('m', stream.read()); assertEquals('a', stream.read()); stream.mark(2); assertEquals('r', stream.read()); assertEquals('k', stream.read()); stream.reset(); assertEquals('r', stream.read()); assertEquals('k', stream.read()); stream.mark(3); assertEquals('r', stream.read()); assertEquals('e', stream.read()); assertEquals('s', stream.read()); assertEquals('e', stream.read()); assertEquals(-1, stream.read()); stream.reset(); assertEquals('r', stream.read()); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/streams/LimitedOutputStreamTestCase.java000066400000000000000000000153761257016060700305110ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.streams; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; import static org.xnio.AssertReadWrite.assertWrittenMessage; import java.io.ByteArrayOutputStream; import java.io.IOException; import org.junit.Test; import org.xnio.mock.ConnectedStreamChannelMock; /** * Test for {@code LimitedOutputStream}. * * @author Flavia Rainone */ public class LimitedOutputStreamTestCase { @Test public void writeByteArray() throws Exception { final ByteArrayOutputStream delegateStream = new ByteArrayOutputStream(); final LimitedOutputStream stream = new LimitedOutputStream(delegateStream, 5); stream.write("test".getBytes("UTF-8")); byte[] writtenBytes = delegateStream.toByteArray(); assertEquals(4, writtenBytes.length); assertEquals('t', writtenBytes[0]); assertEquals('e', writtenBytes[1]); assertEquals('s', writtenBytes[2]); assertEquals('t', writtenBytes[3]); } @Test public void writeBytes() throws Exception { final ByteArrayOutputStream delegateStream = new ByteArrayOutputStream(); final LimitedOutputStream stream = new LimitedOutputStream(delegateStream, 5); stream.write('t'); stream.write('e'); stream.write('s'); stream.write('t'); byte[] writtenBytes = delegateStream.toByteArray(); assertEquals(4, writtenBytes.length); assertEquals('t', writtenBytes[0]); assertEquals('e', writtenBytes[1]); assertEquals('s', writtenBytes[2]); assertEquals('t', writtenBytes[3]); } @Test public void writeByteArrayOverflows() throws Exception { final ByteArrayOutputStream delegateStream = new ByteArrayOutputStream(); final LimitedOutputStream stream = new LimitedOutputStream(delegateStream, 5); IOException expected = null; try { stream.write("overflow".getBytes("UTF-8")); } catch (IOException e) { expected = e; } assertNotNull(expected); assertEquals(0, delegateStream.toByteArray().length); } @Test public void writeByteOverflows() throws Exception { final ByteArrayOutputStream delegateStream = new ByteArrayOutputStream(); final LimitedOutputStream stream = new LimitedOutputStream(delegateStream, 5); stream.write('o'); stream.write('v'); stream.write('e'); stream.write('r'); stream.write('f'); IOException expected = null; try { stream.write('l'); } catch (IOException e) { expected = e; } assertNotNull(expected); byte[] writtenBytes = delegateStream.toByteArray(); assertEquals(5, writtenBytes.length); assertEquals('o', writtenBytes[0]); assertEquals('v', writtenBytes[1]); assertEquals('e', writtenBytes[2]); assertEquals('r', writtenBytes[3]); assertEquals('f', writtenBytes[4]); stream.flush(); assertEquals(5, delegateStream.toByteArray().length); } @Test public void closeEmptyStream() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final ChannelOutputStream delegateStream = new ChannelOutputStream(channelMock); final LimitedOutputStream stream = new LimitedOutputStream(delegateStream, 5); stream.close(); assertTrue(channelMock.isShutdownWrites()); IOException expected = null; try { stream.write('a'); } catch (IOException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.write("bcd".getBytes("UTF-8")); } catch (IOException e) { expected = e; } assertNotNull(expected); stream.flush(); assertWrittenMessage(channelMock); // idempotent stream.close(); expected = null; try { stream.write('e'); } catch (IOException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.write("fgh".getBytes("UTF-8")); } catch (IOException e) { expected = e; } assertNotNull(expected); stream.flush(); assertWrittenMessage(channelMock); } @Test public void closeStream() throws IOException { final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final ChannelOutputStream delegateStream = new ChannelOutputStream(channelMock); final LimitedOutputStream stream = new LimitedOutputStream(delegateStream, 5); stream.write('a'); stream.write('b'); stream.write('c'); // flush assertFalse(channelMock.isFlushed()); stream.flush(); assertTrue(channelMock.isFlushed()); // close stream.close(); assertTrue(channelMock.isShutdownWrites()); IOException expected = null; try { stream.write('d'); } catch (IOException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.write("efg".getBytes("UTF-8")); } catch (IOException e) { expected = e; } assertNotNull(expected); stream.flush(); assertWrittenMessage(channelMock, "abc"); // idempotent stream.close(); expected = null; try { stream.write('h'); } catch (IOException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.write("ijk".getBytes("UTF-8")); } catch (IOException e) { expected = e; } assertNotNull(expected); stream.flush(); assertWrittenMessage(channelMock, "abc"); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/streams/PipeTestCase.java000066400000000000000000000576521257016060700254250ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.streams; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.xnio.AssertReadWrite.assertReadMessage; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.io.UnsupportedEncodingException; import org.junit.Test; /** * Test for {@link Pipe}. * * @author Flavia Rainone */ public class PipeTestCase { @Test public void readAndWriteBytes() throws IOException { final Pipe pipe = new Pipe(100); final InputStream inputStream = pipe.getIn(); assertNotNull(inputStream); assertNotNull(inputStream.toString()); final OutputStream outputStream = pipe.getOut(); assertNotNull(outputStream); assertNotNull(outputStream.toString()); outputStream.write('a'); assertEquals('a', inputStream.read()); close(outputStream); close(inputStream); } @Test public void readAndWriteByteArray() throws IOException { final Pipe pipe = new Pipe(100); final InputStream inputStream = pipe.getIn(); assertNotNull(inputStream); assertNotNull(inputStream.toString()); final OutputStream outputStream = pipe.getOut(); assertNotNull(outputStream); assertNotNull(outputStream.toString()); outputStream.write("array".getBytes()); byte[] bytes = new byte[10]; assertEquals(5, inputStream.read(bytes)); assertReadMessage(bytes, "array"); close(outputStream); close(inputStream); } @Test public void readAndWriteBytesWithBufferOverflow() throws IOException { final Pipe pipe = new Pipe(3); final InputStream inputStream = pipe.getIn(); assertNotNull(inputStream); assertNotNull(inputStream.toString()); final OutputStream outputStream = pipe.getOut(); assertNotNull(outputStream); assertNotNull(outputStream.toString()); outputStream.write('a'); outputStream.write('b'); outputStream.write('c'); assertEquals('a', inputStream.read()); assertEquals('b', inputStream.read()); assertEquals('c', inputStream.read()); outputStream.write('d'); outputStream.write('e'); outputStream.write('f'); assertEquals('d', inputStream.read()); assertEquals('e', inputStream.read()); assertEquals('f', inputStream.read()); close(outputStream); close(inputStream); } @Test public void readAndWriteByteArrayWithBufferOverflow() throws IOException { final Pipe pipe = new Pipe(3); final InputStream inputStream = pipe.getIn(); assertNotNull(inputStream); assertNotNull(inputStream.toString()); final OutputStream outputStream = pipe.getOut(); assertNotNull(outputStream); assertNotNull(outputStream.toString()); outputStream.write("abc".getBytes()); byte[] bytes = new byte[10]; assertEquals(3, inputStream.read(bytes)); assertReadMessage(bytes, "abc"); outputStream.write("def".getBytes()); inputStream.read(bytes, 3, 3); assertReadMessage(bytes, "abc", "def"); close(outputStream); close(inputStream); } @Test public void readByteFromClosedStream() throws IOException { final Pipe pipe = new Pipe(100); final InputStream inputStream = pipe.getIn(); assertNotNull(inputStream); assertNotNull(inputStream.toString()); final OutputStream outputStream = pipe.getOut(); assertNotNull(outputStream); assertNotNull(outputStream.toString()); outputStream.write('a'); close(outputStream); assertEquals('a', inputStream.read()); assertEquals(-1, inputStream.read()); close(inputStream); } @Test public void readByteArrayFromClosedStream() throws IOException { final Pipe pipe = new Pipe(100); final InputStream inputStream = pipe.getIn(); assertNotNull(inputStream); assertNotNull(inputStream.toString()); final OutputStream outputStream = pipe.getOut(); assertNotNull(outputStream); assertNotNull(outputStream.toString()); outputStream.write('a'); close(outputStream); byte[] bytes = new byte[5]; assertEquals(1, inputStream.read(bytes)); assertEquals('a', bytes[0]); assertEquals(-1, inputStream.read(bytes, 1, 4)); close(inputStream); } @Test public void readFromEmptyClosedStream() throws IOException { final Pipe pipe = new Pipe(100); final InputStream inputStream = pipe.getIn(); final OutputStream outputStream = pipe.getOut(); assertNotNull(outputStream); assertNotNull(outputStream.toString()); close(outputStream); assertEquals(-1, inputStream.read()); assertEquals(-1, inputStream.read(new byte[3])); close(inputStream); } @Test public void readByteBlocksUntilWrite() throws Exception { final Pipe pipe = new Pipe(100); final InputStream inputStream = pipe.getIn(); final OutputStream outputStream = pipe.getOut(); final ReadByteTask readTask = new ReadByteTask(inputStream); final Thread readThread = new Thread(readTask); readThread.start(); readThread.join(200); assertTrue(readThread.isAlive()); outputStream.write('b'); readThread.join(); assertEquals('b', readTask.getReadResult()); } @Test public void readByteArrayBlocksUntilWrite1() throws Exception { final Pipe pipe = new Pipe(100); final InputStream inputStream = pipe.getIn(); final OutputStream outputStream = pipe.getOut(); byte[] bytes = new byte[5]; final ReadByteArrayTask readTask = new ReadByteArrayTask(inputStream, bytes); final Thread readThread = new Thread(readTask); readThread.start(); readThread.join(200); assertTrue(readThread.isAlive()); outputStream.write("block".getBytes()); readThread.join(); assertEquals(5, readTask.getReadResult()); assertReadMessage(bytes, "block"); } @Test public void readByteArrayBlocksUntilWrite2() throws Exception { final Pipe pipe = new Pipe(10); final InputStream inputStream = pipe.getIn(); final OutputStream outputStream = pipe.getOut(); byte[] bytes1 = new byte[15]; byte[] bytes2 = new byte[15]; final ReadByteArrayTask readTask1 = new ReadByteArrayTask(inputStream, bytes1); final ReadByteArrayTask readTask2 = new ReadByteArrayTask(inputStream, bytes2); final Thread readThread1 = new Thread(readTask1); final Thread readThread2 = new Thread(readTask2); readThread1.start(); readThread1.join(200); readThread2.start(); readThread2.join(200); assertTrue(readThread1.isAlive()); assertTrue(readThread2.isAlive()); outputStream.write("abcdefghij".getBytes()); outputStream.write("klmnopqrst".getBytes()); readThread1.join(); readThread2.join(); outputStream.write("klmnopqrst".getBytes()); assertEquals(10, readTask1.getReadResult()); if (bytes1[0] == 'a') { assertReadMessage(bytes1, "abcdefghij"); assertReadMessage(bytes2, "klmnopqrst"); } else { assertReadMessage(bytes1, "klmnopqrst"); assertReadMessage(bytes2, "abcdefghij"); } } @Test public void readBytesBlocksUntilCloseOutput() throws Exception { final Pipe pipe = new Pipe(100); final InputStream inputStream = pipe.getIn(); final OutputStream outputStream = pipe.getOut(); final ReadByteTask readTask = new ReadByteTask(inputStream); final Thread readThread = new Thread(readTask); readThread.start(); readThread.join(200); assertTrue(readThread.isAlive()); outputStream.close(); readThread.join(); assertEquals(-1, readTask.getReadResult()); } @Test public void readByteArrayBlocksUntilCloseOutput() throws Exception { final Pipe pipe = new Pipe(100); final InputStream inputStream = pipe.getIn(); final OutputStream outputStream = pipe.getOut(); byte[] bytes = new byte[5]; final ReadByteArrayTask readTask = new ReadByteArrayTask(inputStream, bytes); final Thread readThread = new Thread(readTask); readThread.start(); readThread.join(200); assertTrue(readThread.isAlive()); outputStream.close(); readThread.join(); assertEquals(-1, readTask.getReadResult()); } @Test public void readBytesBlocksUntilWriteAndCloseOutput() throws Exception { final Pipe pipe = new Pipe(100); final InputStream inputStream = pipe.getIn(); final OutputStream outputStream = pipe.getOut(); final ReadByteTask readTask = new ReadByteTask(inputStream); final Thread readThread = new Thread(readTask); readThread.start(); readThread.join(200); assertTrue(readThread.isAlive()); outputStream.write('a'); outputStream.close(); readThread.join(); assertEquals('a', readTask.getReadResult()); assertEquals(-1, inputStream.read()); } @Test public void readByteArrayBlocksUntilWriteAndCloseOutput() throws Exception { final Pipe pipe = new Pipe(100); final InputStream inputStream = pipe.getIn(); final OutputStream outputStream = pipe.getOut(); byte[] bytes = new byte[5]; final ReadByteArrayTask readTask = new ReadByteArrayTask(inputStream, bytes); final Thread readThread = new Thread(readTask); readThread.start(); readThread.join(200); assertTrue(readThread.isAlive()); outputStream.write('a'); outputStream.close(); readThread.join(); assertEquals(1, readTask.getReadResult()); assertReadMessage(bytes, "a"); assertEquals(-1, inputStream.read(bytes)); } @Test public void readBlocksUntilCloseInput() throws Exception { final Pipe pipe = new Pipe(100); final InputStream inputStream = pipe.getIn(); final ReadByteTask readTask1 = new ReadByteTask(inputStream); final ReadByteArrayTask readTask2 = new ReadByteArrayTask(inputStream, new byte[3]); final Thread readThread1 = new Thread(readTask1); final Thread readThread2 = new Thread(readTask2); readThread1.start(); readThread2.start(); readThread1.join(200); assertTrue(readThread1.isAlive()); readThread2.join(200); assertTrue(readThread2.isAlive()); inputStream.close(); readThread1.join(); readThread2.join(); assertEquals(-1, readTask1.getReadResult()); assertEquals(-1, readTask2.getReadResult()); } @Test public void writeByteBlocksUntilRead() throws Exception { final Pipe pipe = new Pipe(5); final InputStream inputStream = pipe.getIn(); final OutputStream outputStream = pipe.getOut(); outputStream.write("input".getBytes()); final WriteByteTask writeTask = new WriteByteTask(outputStream, (byte) '0'); final Thread writeThread = new Thread(writeTask); writeThread.start(); writeThread.join(200); assertTrue(writeThread.isAlive()); assertEquals('i', inputStream.read()); writeThread.join(); assertNull(writeTask.getWriteException()); assertEquals('n', inputStream.read()); assertEquals('p', inputStream.read()); assertEquals('u', inputStream.read()); assertEquals('t', inputStream.read()); assertEquals('0', inputStream.read()); close(inputStream); close(outputStream); } @Test public void writeByteArrayBlocksUntilRead() throws Exception { final Pipe pipe = new Pipe(5); final InputStream inputStream = pipe.getIn(); final OutputStream outputStream = pipe.getOut(); outputStream.write("12345".getBytes()); final WriteByteArrayTask writeTask = new WriteByteArrayTask(outputStream, "67890".getBytes()); final Thread writeThread = new Thread(writeTask); writeThread.start(); writeThread.join(200); assertTrue(writeThread.isAlive()); assertEquals('1', inputStream.read()); assertEquals('2', inputStream.read()); final byte[] bytes = new byte[5]; int read = inputStream.read(bytes); writeThread.join(); assertNull(writeTask.getWriteException()); if (read == 3) { assertReadMessage(bytes, "345"); assertEquals('6', inputStream.read()); assertEquals('7', inputStream.read()); } else if (read == 5) { assertReadMessage(bytes, "34567"); } else { fail("Should've read 3 or 5 bytes but read " + read); } assertEquals('8', inputStream.read()); assertEquals('9', inputStream.read()); assertEquals('0', inputStream.read()); close(inputStream); close(outputStream); } @Test public void writeByteBlocksUntilCloseInput() throws Exception { final Pipe pipe = new Pipe(1); final InputStream inputStream = pipe.getIn(); final OutputStream outputStream = pipe.getOut(); outputStream.write('1'); final WriteByteTask writeTask = new WriteByteTask(outputStream, (byte) '2'); final Thread writeThread = new Thread(writeTask); writeThread.start(); writeThread.join(200); assertTrue(writeThread.isAlive()); close(inputStream); writeThread.join(); assertNotNull(writeTask.getWriteException()); assertEquals(-1, inputStream.read()); } @Test public void writeByteArrayBlocksUntilCloseInput() throws Exception { final Pipe pipe = new Pipe(1); final InputStream inputStream = pipe.getIn(); final OutputStream outputStream = pipe.getOut(); outputStream.write('1'); final WriteByteArrayTask writeTask = new WriteByteArrayTask(outputStream, "2".getBytes()); final Thread writeThread = new Thread(writeTask); writeThread.start(); writeThread.join(200); assertTrue(writeThread.isAlive()); close(inputStream); writeThread.join(); assertNotNull(writeTask.getWriteException()); assertEquals(-1, inputStream.read()); } @Test public void writeByteBlocksUntilCloseOutput() throws Exception { final Pipe pipe = new Pipe(3); final InputStream inputStream = pipe.getIn(); final OutputStream outputStream = pipe.getOut(); outputStream.write("123".getBytes()); final WriteByteTask writeTask = new WriteByteTask(outputStream, (byte) '4'); final Thread writeThread = new Thread(writeTask); writeThread.start(); writeThread.join(200); assertTrue(writeThread.isAlive()); close(outputStream); writeThread.join(); assertNotNull(writeTask.getWriteException()); final byte[] bytes = new byte[5]; assertEquals(3, inputStream.read(bytes)); assertReadMessage(bytes, "123"); } @Test public void writeByteArrayBlocksUntilCloseOutput() throws Exception { final Pipe pipe = new Pipe(3); final InputStream inputStream = pipe.getIn(); final OutputStream outputStream = pipe.getOut(); outputStream.write("123".getBytes()); final WriteByteArrayTask writeTask = new WriteByteArrayTask(outputStream, "45".getBytes()); final Thread writeThread = new Thread(writeTask); writeThread.start(); writeThread.join(200); assertTrue(writeThread.isAlive()); close(outputStream); writeThread.join(); assertNotNull(writeTask.getWriteException()); final byte[] bytes = new byte[5]; assertEquals(3, inputStream.read(bytes)); assertReadMessage(bytes, "123"); } @Test public void awaitReadCloses() throws Exception { final Pipe pipe = new Pipe(100); final Thread awaitThread = new Thread(new AwaitTask(pipe)); awaitThread.start(); awaitThread.join(200); assertTrue(awaitThread.isAlive()); close(pipe.getIn()); awaitThread.join(); } @Test public void awaitReadClosesAfterWriteCloses() throws Exception { final Pipe pipe = new Pipe(100); final Thread awaitThread = new Thread(new AwaitTask(pipe)); awaitThread.start(); awaitThread.join(200); assertTrue(awaitThread.isAlive()); close(pipe.getOut()); awaitThread.join(200); assertTrue(awaitThread.isAlive()); close(pipe.getIn()); awaitThread.join(); } @Test public void wrappedBytes() throws IOException { final Pipe pipe = new Pipe(10); final InputStream inputStream = pipe.getIn(); final OutputStream outputStream = pipe.getOut(); outputStream.write("12345".getBytes()); byte[] bytes = new byte[20]; assertEquals(5, inputStream.read(bytes)); assertReadMessage(bytes, "12345"); outputStream.write("6789012345".getBytes()); assertEquals(10, inputStream.read(bytes, 5, 15)); assertReadMessage(bytes, "12345", "67890", "12345"); outputStream.write("12345678".getBytes()); assertEquals(0, inputStream.read(bytes, 15, 0)); assertEquals(5, inputStream.read(bytes, 15, 5)); assertReadMessage(bytes, "12345", "67890", "12345", "12345"); assertEquals('6', inputStream.read()); assertEquals('7', inputStream.read()); assertEquals('8', inputStream.read()); outputStream.write("9012345".getBytes()); outputStream.write("678".getBytes()); assertEquals(10, inputStream.read(bytes)); outputStream.write("0123456".getBytes()); assertEquals(5, inputStream.read(bytes, 10, 5)); assertReadMessage(bytes, "9012345", "678", "01234"); outputStream.write("7890123".getBytes()); assertEquals(9, inputStream.read(bytes)); assertReadMessage(bytes, "56", "7890123"); } @Test public void closeOnlyInputStream() throws UnsupportedEncodingException, IOException { final Pipe pipe = new Pipe(100); final InputStream inputStream = pipe.getIn(); final OutputStream outputStream = pipe.getOut(); close(inputStream); IOException expected = null; try { outputStream.write("abc".getBytes("UTF-8")); } catch (IOException e) { expected = e; } assertNotNull(expected); assertEquals(-1, inputStream.read()); assertEquals(-1, inputStream.read(new byte[1])); } private void close(OutputStream stream) throws IOException { stream.close(); IOException expected = null; try { stream.write('a'); } catch (IOException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.write("abc".getBytes("UTF-8")); } catch (IOException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.write("#@abc#$%^".getBytes("UTF-8"), 2, 3); } catch (IOException e) { expected = e; } assertNotNull(expected); // close must be idempotent stream.close(); expected = null; try { stream.write('a'); } catch (IOException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.write("abc".getBytes("UTF-8")); } catch (IOException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.write("#@abc#$%^".getBytes("UTF-8"), 2, 3); } catch (IOException e) { expected = e; } assertNotNull(expected); } private void close(InputStream stream) throws IOException { stream.close(); assertEquals(-1, stream.read()); assertEquals(-1, stream.read(new byte[10])); assertEquals(-1, stream.read(new byte[10], 1, 7)); // close must be idempotent stream.close(); assertEquals(-1, stream.read()); assertEquals(-1, stream.read(new byte[10])); assertEquals(-1, stream.read(new byte[10], 1, 7)); } private static class ReadByteTask implements Runnable { private final InputStream stream; private int readResult; public ReadByteTask(InputStream s) { stream = s; } @Override public void run() { try { readResult = stream.read(); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } public int getReadResult() { return readResult; } } private static class ReadByteArrayTask implements Runnable { private final InputStream stream; private final byte[] bytes; private int readResult; public ReadByteArrayTask(InputStream s, byte[] b) { stream = s; bytes = b; } @Override public void run() { try { readResult = stream.read(bytes); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } public int getReadResult() { return readResult; } } private static class WriteByteTask implements Runnable { private final OutputStream stream; private final byte writeByte; private IOException exception; public WriteByteTask(OutputStream s, byte b) { stream = s; writeByte = b; } @Override public void run() { try { stream.write(writeByte); } catch (IOException e) { exception = e; } } public IOException getWriteException() { return exception; } } private static class WriteByteArrayTask implements Runnable { private final OutputStream stream; private final byte[] bytes; private IOException exception; public WriteByteArrayTask(OutputStream s, byte[] b) { stream = s; bytes = b; } @Override public void run() { try { stream.write(bytes); } catch (IOException e) { exception = e; } } public IOException getWriteException() { return exception; } } private static class AwaitTask implements Runnable { private final Pipe pipe; public AwaitTask(Pipe p) { pipe = p; } @Override public void run() { pipe.await(); } } } xnio-3.3.2.Final/api/src/test/java/org/xnio/streams/ReaderInputStreamTestCase.java000066400000000000000000000273421257016060700301170ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.streams; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.io.IOException; import java.io.Reader; import java.io.StringReader; import java.nio.charset.Charset; import java.nio.charset.CharsetEncoder; import org.junit.Test; /** * Test for {@link ReaderInputStream}. * * @author Flavia Rainone */ public class ReaderInputStreamTestCase { @Test public void invalidConstructorArguments() throws IOException { // null writer Exception expected = null; try { new ReaderInputStream(null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { new ReaderInputStream(null, Charset.defaultCharset()); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { new ReaderInputStream(null, Charset.defaultCharset().newEncoder()); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { new ReaderInputStream(null, "UTF-8"); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { new ReaderInputStream(null, Charset.defaultCharset().newEncoder(), 10000); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); // null char set final Reader reader = new StringReader("foo"); expected = null; try { new ReaderInputStream(reader, (Charset) null); } catch (NullPointerException e) { expected = e; } assertNotNull(expected); // null char set name expected = null; try { new ReaderInputStream(reader, (String) null); } catch (IllegalArgumentException e) { expected= e; } assertNotNull(expected); // null decoder expected = null; try { new ReaderInputStream(reader, (CharsetEncoder) null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { new ReaderInputStream(reader, null, 10000); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); // negative buffer size expected = null; try { new ReaderInputStream(reader, Charset.defaultCharset().newEncoder(), -15000); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); // zero buffer length expected = null; try { new ReaderInputStream(reader, Charset.defaultCharset().newEncoder(), 0); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void read1() throws IOException { final ReaderInputStream stream = new ReaderInputStream(new StringReader("test")); assertEquals('t', stream.read()); assertEquals('e', stream.read()); assertEquals('s', stream.read()); assertEquals('t', stream.read()); assertEquals(-1, stream.read()); closeStream(stream); } @Test public void read2() throws IOException { final ReaderInputStream stream = new ReaderInputStream(new StringReader("test"), "UTF-8"); byte[] bytes = new byte[10]; assertEquals(4, stream.read(bytes)); assertEquals('t', bytes[0]); assertEquals('e', bytes[1]); assertEquals('s', bytes[2]); assertEquals('t', bytes[3]); assertEquals(-1, stream.read(bytes)); closeStream(stream); } @Test public void read3() throws IOException { final ReaderInputStream stream = new ReaderInputStream(new StringReader("test"), Charset.defaultCharset().newEncoder(), 1); assertEquals('t', stream.read()); assertEquals('e', stream.read()); assertEquals('s', stream.read()); assertEquals('t', stream.read()); assertEquals(-1, stream.read()); closeStream(stream); } @Test public void read4() throws IOException { final ReaderInputStream stream = new ReaderInputStream(new StringReader("test"), Charset.defaultCharset().newEncoder(), 1); byte[] bytes = new byte[2]; assertEquals(2, stream.read(bytes)); assertEquals('t', bytes[0]); assertEquals('e', bytes[1]); assertEquals(2, stream.read(bytes)); assertEquals('s', bytes[0]); assertEquals('t', bytes[1]); assertEquals(-1, stream.read(bytes)); closeStream(stream); } @Test public void read5() throws IOException { final ReaderInputStream stream = new ReaderInputStream(new StringReader(""), Charset.defaultCharset().newEncoder(), 1); assertEquals(-1, stream.read(new byte[5])); assertEquals(-1, stream.read()); closeStream(stream); } @Test public void readAfterAvailable1() throws IOException { final ReaderInputStream stream = new ReaderInputStream(new StringReader("test")); assertEquals(0, stream.available()); assertEquals('t', stream.read()); assertEquals(3, stream.available()); assertEquals('e', stream.read()); assertEquals(2, stream.available()); assertEquals('s', stream.read()); assertEquals(1, stream.available()); assertEquals('t', stream.read()); assertEquals(0, stream.available()); assertEquals(-1, stream.read()); closeStream(stream); } @Test public void readAfterAvailable2() throws IOException { final ReaderInputStream stream = new ReaderInputStream(new StringReader("test"), "UTF-8"); byte[] bytes = new byte[10]; assertEquals(0, stream.available()); assertEquals(4, stream.read(bytes)); assertEquals(0, stream.available()); assertEquals('t', bytes[0]); assertEquals('e', bytes[1]); assertEquals('s', bytes[2]); assertEquals('t', bytes[3]); assertEquals(-1, stream.read(bytes)); closeStream(stream); } @Test public void readAfterAvailable3() throws IOException { final ReaderInputStream stream = new ReaderInputStream(new StringReader("test"), Charset.defaultCharset().newEncoder(), 1); assertEquals(0, stream.available()); assertEquals('t', stream.read()); assertEquals(0, stream.available()); assertEquals('e', stream.read()); assertEquals(0, stream.available()); assertEquals('s', stream.read()); assertEquals(0, stream.available()); assertEquals('t', stream.read()); assertEquals(0, stream.available()); assertEquals(-1, stream.read()); closeStream(stream); } @Test public void readAfterAvailable4() throws IOException { final ReaderInputStream stream = new ReaderInputStream(new StringReader("test"), Charset.defaultCharset().newEncoder(), 1); byte[] bytes = new byte[2]; assertEquals(0, stream.available()); assertEquals(2, stream.read(bytes)); assertEquals('t', bytes[0]); assertEquals('e', bytes[1]); assertEquals(0, stream.available()); assertEquals(2, stream.read(bytes)); assertEquals('s', bytes[0]); assertEquals('t', bytes[1]); assertEquals(0, stream.available()); assertEquals(-1, stream.read(bytes)); closeStream(stream); } @Test public void readAfterAvailable5() throws IOException { final ReaderInputStream stream = new ReaderInputStream(new StringReader(""), Charset.defaultCharset().newEncoder(), 1); assertEquals(0, stream.available()); assertEquals(-1, stream.read(new byte[5])); assertEquals(-1, stream.read()); closeStream(stream); } @Test public void skip1() throws IOException { final ReaderInputStream stream = new ReaderInputStream(new StringReader("skip all this - data")); assertEquals(16, stream.skip(16)); assertEquals(4, stream.available()); assertEquals('d', stream.read()); assertEquals(3, stream.available()); assertEquals('a', stream.read()); assertEquals(2, stream.available()); assertEquals('t', stream.read()); assertEquals(1, stream.available()); assertEquals('a', stream.read()); assertEquals(0, stream.available()); assertEquals(-1, stream.read()); closeStream(stream); } @Test public void skip2() throws IOException { final ReaderInputStream stream = new ReaderInputStream(new StringReader("skip all this - data")); assertEquals(20, stream.skip(Long.MAX_VALUE)); assertEquals(0, stream.available()); assertEquals(-1, stream.read()); closeStream(stream); } @Test public void skipEmpty() throws IOException { final ReaderInputStream stream = new ReaderInputStream(new StringReader("")); assertEquals(0, stream.skip(1000)); assertEquals(0, stream.available()); closeStream(stream); } @Test public void closeStreamBeforeRead() throws IOException { final ReaderInputStream stream = new ReaderInputStream(new StringReader("close before read")); assertEquals(0, stream.available()); closeStream(stream); } @Test public void closeStreamBeforeReadIsDone() throws IOException { final ReaderInputStream stream = new ReaderInputStream(new StringReader("close before read")); assertEquals(0, stream.available()); assertEquals('c', stream.read()); assertEquals(16, stream.available()); closeStream(stream); } private void closeStream(ReaderInputStream stream) throws IOException { stream.close(); assertEquals(0, stream.available()); IOException expected = null; try { stream.read(); } catch (IOException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.read(new byte[5]); } catch (IOException e) { expected = e; } assertNotNull(expected); // idempotent stream.close(); assertEquals(0, stream.available()); expected = null; try { stream.read(new byte[10]); } catch (IOException e) { expected = e; } assertNotNull(expected); expected = null; try { stream.read(); } catch (IOException e) { expected = e; } assertNotNull(expected); assertNotNull(stream.toString()); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/streams/StreamsTestCase.java000066400000000000000000000070711257016060700261340ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.streams; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.junit.Test; import org.xnio.mock.ConnectedStreamChannelMock; /** * Test for {@link Streams}. * * @author Flavia Rainone */ public class StreamsTestCase { @Test public void defaultCopy() throws IOException { final InputStream inputStream = new ByteArrayInputStream("copy".getBytes()); final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final OutputStream outputStream = new ChannelOutputStream(channelMock); Streams.copyStream(inputStream, outputStream); assertEquals("copy", channelMock.getWrittenText()); // check the streams are closed assertEquals(-1, inputStream.read()); assertFalse(channelMock.isWriteResumed()); } @Test public void copyWithClosedInputStream() throws IOException { final InputStream inputStream = new ByteArrayInputStream("copy".getBytes()); final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final OutputStream outputStream = new ChannelOutputStream(channelMock); inputStream.close(); Streams.copyStream(inputStream, outputStream, false); assertEquals("copy", channelMock.getWrittenText()); // check the streams are closed assertEquals(-1, inputStream.read()); assertFalse(channelMock.isWriteResumed()); } @Test public void copyWithoutClose() throws IOException { final InputStream inputStream = new ByteArrayInputStream("don't close".getBytes()); final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final OutputStream outputStream = new ChannelOutputStream(channelMock); Streams.copyStream(inputStream, outputStream, false); assertEquals("don't close", channelMock.getWrittenText()); // check the streams are closed assertEquals(-1, inputStream.read()); assertFalse(channelMock.isWriteResumed()); } @Test public void copyWithSmallBuffer() throws IOException { final InputStream inputStream = new ByteArrayInputStream("this wont fit in the small buffer".getBytes()); final ConnectedStreamChannelMock channelMock = new ConnectedStreamChannelMock(); final OutputStream outputStream = new ChannelOutputStream(channelMock); Streams.copyStream(inputStream, outputStream, false, 3); assertEquals("this wont fit in the small buffer", channelMock.getWrittenText()); // check the streams are closed assertEquals(-1, inputStream.read()); assertFalse(channelMock.isWriteResumed()); } } xnio-3.3.2.Final/api/src/test/java/org/xnio/streams/WriterOutputStreamTestCase.java000066400000000000000000000204661257016060700303720ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2012 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.streams; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import java.io.IOException; import java.io.StringWriter; import java.nio.charset.Charset; import java.nio.charset.CharsetDecoder; import org.junit.Test; /** * Test for {@link WriterOutputStream}. * * @author Flavia Rainone */ public class WriterOutputStreamTestCase { @Test public void invalidConstructorArguments() throws IOException { // null writer Exception expected = null; try { new WriterOutputStream(null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { new WriterOutputStream(null, Charset.defaultCharset()); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { new WriterOutputStream(null, Charset.defaultCharset().newDecoder()); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { new WriterOutputStream(null, "UTF-8"); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { new WriterOutputStream(null, Charset.defaultCharset().newDecoder(), 10000); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); // null char set final StringWriter writer = new StringWriter(); expected = null; try { new WriterOutputStream(writer, (Charset) null); } catch (NullPointerException e) { expected = e; } assertNotNull(expected); // null char set name expected = null; try { new WriterOutputStream(writer, (String) null); } catch (IllegalArgumentException e) { expected= e; } assertNotNull(expected); // null decoder expected = null; try { new WriterOutputStream(writer, (CharsetDecoder) null); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { new WriterOutputStream(writer, null, 10000); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); // negative buffer size expected = null; try { new WriterOutputStream(writer, Charset.defaultCharset().newDecoder(), -15000); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); // zero buffer length expected = null; try { new WriterOutputStream(writer, Charset.defaultCharset().newDecoder(), 0); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void writeBytes() throws IOException { final StringWriter writer = new StringWriter(); final WriterOutputStream stream = new WriterOutputStream(writer); stream.write('w'); stream.write('r'); stream.write('i'); stream.write('t'); stream.write('e'); assertEquals("", writer.getBuffer().toString()); stream.flush(); assertEquals("write", writer.getBuffer().toString()); closeStream(stream, writer, "write"); } @Test public void writeByteArray() throws IOException { final StringWriter writer = new StringWriter(); final WriterOutputStream stream = new WriterOutputStream(writer, "UTF-8"); stream.write("write".getBytes("UTF-8")); assertEquals("", writer.getBuffer().toString()); stream.flush(); assertEquals("write", writer.getBuffer().toString()); closeStream(stream, writer, "write"); } @Test public void writeOverflowsInternalBuffer() throws IOException { final StringWriter writer = new StringWriter(); final WriterOutputStream stream = new WriterOutputStream(writer, Charset.defaultCharset().newDecoder(), 3); stream.write('w'); stream.write('r'); stream.write('i'); assertEquals("", writer.getBuffer().toString()); stream.write('t'); assertEquals("wri", writer.getBuffer().toString()); stream.write('e'); assertEquals("wri", writer.getBuffer().toString()); stream.flush(); assertEquals("write", writer.getBuffer().toString()); closeStream(stream, writer, "write"); } @Test public void writeByteArrayOverflowsInternalBuffer() throws IOException { final StringWriter writer = new StringWriter(); final WriterOutputStream stream = new WriterOutputStream(writer, Charset.defaultCharset().newDecoder(), 3); stream.write("w r i t e".getBytes("UTF-8"), 2, 5); assertEquals("r i", writer.getBuffer().toString()); stream.flush(); assertEquals("r i t", writer.getBuffer().toString()); closeStream(stream, writer, "r i t"); } @Test public void closeStream() throws IOException { final StringWriter writer = new StringWriter(); final WriterOutputStream stream = new WriterOutputStream(writer, Charset.defaultCharset().newDecoder(), 10); stream.write('a'); stream.write("bcd".getBytes("UTF-8")); assertEquals("", writer.getBuffer().toString()); stream.flush(); assertEquals("abcd", writer.getBuffer().toString()); stream.write("eefghijklm".getBytes("UTF-8"), 1, 8); assertEquals("abcd", writer.getBuffer().toString()); stream.write('m'); assertEquals("abcd", writer.getBuffer().toString()); stream.write('n'); assertEquals("abcd", writer.getBuffer().toString()); closeStream(stream, writer, "abcdefghijklmn"); } @Test public void closeEmptyStream() throws IOException { final StringWriter writer = new StringWriter(); final WriterOutputStream stream = new WriterOutputStream(writer, Charset.defaultCharset().newDecoder(), 10); closeStream(stream, writer, ""); } private void closeStream(WriterOutputStream stream, StringWriter writer, String writtenString) throws IOException { stream.close(); assertEquals(writtenString, writer.getBuffer().toString()); IOException expected = null; try { stream.write('a'); } catch (IOException e) { expected = e; } assertNotNull(expected); assertEquals(writtenString, writer.getBuffer().toString()); expected = null; try { stream.write("abc".getBytes("UTF-8")); } catch (IOException e) { expected = e; } assertNotNull(expected); assertEquals(writtenString, writer.getBuffer().toString()); expected = null; try { stream.write("abc".getBytes("UTF-8"), 1, 1); } catch (IOException e) { expected = e; } assertNotNull(expected); assertEquals(writtenString, writer.getBuffer().toString()); expected = null; try { stream.flush(); } catch (IOException e) { expected = e; } assertNotNull(expected); assertEquals(writtenString, writer.getBuffer().toString()); assertNotNull(stream.toString()); } } xnio-3.3.2.Final/api/src/test/resources/000077500000000000000000000000001257016060700200615ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/resources/META-INF/000077500000000000000000000000001257016060700212215ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/resources/META-INF/services/000077500000000000000000000000001257016060700230445ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/resources/META-INF/services/org.xnio.XnioProvider000066400000000000000000000001211257016060700271530ustar00rootroot00000000000000 # This module defines the NIO XNIO mock provider org.xnio.mock.XnioMock$Providerxnio-3.3.2.Final/api/src/test/resources/keystore.jks000066400000000000000000000025541257016060700224450ustar00rootroot00000000000000 servercert4>e`00 +*Ov'xu~dJ!kڅ)#Cf`gAT*9#EĘ*%nUC˺;X+;'gʂ:يz:엱ʳ0SMڼyRg Y6 vVIld]pP>?.a༣مjW{k,)Z+ű*>Gdgަ sK# vrn&ңb]b+*2J]`m;黇 Uٓ<ߖKE}{_ޯLicn6"Z1V a;sw#Vi~d~ɜX., 2kIω~lU84?> pnCf- gB `}\z0!5%ĂIfY NxjFxp|9Ik8uPbm(6k6& )D)( 4jGr-p٢ Wj3L!fʌnj@H }ëKV`ilP/W_StZnk2N@*hmK(mU_z?RjZ/![FskMRV5G80k2X.509f0b0ˠhӳ0  *H  0d1 0 UJB1 0 UFoo1 0 UFoo10U  jboss.org10U  jboss.org10UJane Doe0 120114032409Z 120413032409Z0d1 0 UJB1 0 UFoo1 0 UFoo10U  jboss.org10U  jboss.org10UJane Doe00  *H 0a&-[NʽM21ZtrV-mT9819A7P@ 5 ;Bc6/"459 `(!J; &tZ!wg lK퓚ogC:f/ö3!00UliMNƵU#0  *H  ':[sWjw̬Q&ĺyp=CVEyg@>)wL{㦼K sRSSJp9%cobˋ"X\]9|אJ/Jmƺ,m_'~E8xnio-3.3.2.Final/api/src/test/resources/org/000077500000000000000000000000001257016060700206505ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/resources/org/xnio/000077500000000000000000000000001257016060700216255ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/resources/org/xnio/racecondition/000077500000000000000000000000001257016060700244465ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/resources/org/xnio/racecondition/CloseReadingSslChannelTestCase.btm000066400000000000000000000017211257016060700331210ustar00rootroot00000000000000 RULE handling NEED_WRAP CLASS org.xnio.ssl.JsseConnectedSslStreamChannel METHOD handleHandshake #AT INVOKE org.xnio.ssl.JsseConnectedSslStreamChannel.handleWrapResult AFTER INVOKE org.xnio.Pooled.getResource 1 IF TRUE DO debug("Read is trying to wrap as a result of NEED_WRAP... wait for the channel to be closed"), signalWake("handleHandshake at invoke handleWrapResult", true), waitFor("channel closed"), debug("Proceeding with handleWrapResult") ENDRULE RULE before close channel CLASS org.xnio.ssl.JsseConnectedSslStreamChannel METHOD closeAction AT ENTRY IF TRUE DO debug("Channel is closing... waiting for handleHandshake first"), waitFor("handleHandshake at invoke handleWrapResult"), debug("Proceeding with closeAction") ENDRULE RULE after close channel CLASS org.xnio.ssl.JsseConnectedSslStreamChannel METHOD closeAction AT EXIT IF TRUE DO debug("Channel is closed... waking read"), signalWake("channel closed", true) ENDRULE xnio-3.3.2.Final/api/src/test/resources/org/xnio/racecondition/CloseWritingSslChannelTestCase.btm000066400000000000000000000016271257016060700332000ustar00rootroot00000000000000 RULE handling NEED_UNWRAP CLASS org.xnio.ssl.JsseConnectedSslStreamChannel METHOD handleHandshake AFTER INVOKE org.xnio.Pooled.getResource 3 IF TRUE DO debug("write is trying to unwrap as a result of NEED_UNWRAP... wait for the channel to be closed"), signalWake("handleHandshake at invoke handleUnwrapResult", true), waitFor("channel closed"), debug("Proceeding with handleUnwrapResult") ENDRULE RULE before close channel CLASS org.xnio.ssl.JsseConnectedSslStreamChannel METHOD closeAction AT ENTRY IF TRUE DO debug("Channel is closing... waiting for handleHandshake first"), waitFor("handleHandshake at invoke handleUnwrapResult"), debug("Proceeding with closeAction") ENDRULE RULE after close engine CLASS org.xnio.ssl.JsseConnectedSslStreamChannel METHOD closeAction AT EXIT IF TRUE DO debug("Channel is closed... waking write"), signalWake("channel closed", true) ENDRULE ResumeReadsOnHandlingReadableChannelTestCase.btm000066400000000000000000000030271257016060700356230ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/resources/org/xnio/racecondition RULE enable race condition scenario CLASS org.xnio.racecondition.ResumeReadsOnHandlingReadableChannelTestCase METHOD test AT INVOKE java.lang.Thread.start 1 IF TRUE DO debug("Enabling race condition scenario"), flag("race condition enabled for ResumeReadsOnHandlingReadableChannelTestCase") ENDRULE RULE handle readable checked read requested is false CLASS org.xnio.mock.ConnectedStreamChannelMock METHOD suspendReads AT ENTRY IF flagged("race condition enabled for ResumeReadsOnHandlingReadableChannelTestCase") DO debug("TranslatingSuspendableChannel just checked that read is not requested... waiting for resumeReads"), signalWake("read not requested checked", true), waitFor("read requested"), debug("Now read is requested... proceeding with handleReadable after a check that read is not requested") ENDRULE RULE resumeReads after handleReadable checked read is not requested CLASS org.xnio.channels.TranslatingSuspendableChannel METHOD resumeReads AT ENTRY IF flagged("race condition enabled for ResumeReadsOnHandlingReadableChannelTestCase") DO debug("resumeReads... waiting for handle readable to check read is not requested"), waitFor("read not requested checked"), debug("Proceeding with resumeReads") ENDRULE RULE after resumeReads CLASS org.xnio.channels.TranslatingSuspendableChannel METHOD resumeReads AT EXIT IF flagged("race condition enabled for ResumeReadsOnHandlingReadableChannelTestCase") DO debug("Finished resumeReads... waking handleReadable"), signalWake("read requested", true) ENDRULEResumeWritesOnHandlingWritableChannelTestCase.btm000066400000000000000000000030571257016060700361170ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/resources/org/xnio/racecondition RULE enable race condition scenario CLASS org.xnio.racecondition.ResumeWritesOnHandlingWritableChannelTestCase METHOD test AT INVOKE java.lang.Thread.start 1 IF TRUE DO debug("Enabling race condition scenario"), flag("race condition enabled for ResumeWritesOnHandlingWritableChannelTestCase") ENDRULE RULE handle writable checked write requested is false CLASS org.xnio.mock.ConnectedStreamChannelMock METHOD suspendWrites AT ENTRY IF flagged("race condition enabled for ResumeWritesOnHandlingWritableChannelTestCase") DO debug("TranslatingSuspendableChannel just checked that write is not requested... waiting for resumeWrites"), signalWake("write not requested checked", true), waitFor("write requested"), debug("Now write is requested... proceeding with handleWritable after a check that write is not requested") ENDRULE RULE resumeWrites after handleWritable checked write is not requested CLASS org.xnio.channels.TranslatingSuspendableChannel METHOD resumeWrites AT ENTRY IF flagged("race condition enabled for ResumeWritesOnHandlingWritableChannelTestCase") DO debug("resumeWrites... waiting for handle writable to check write is not requested"), waitFor("write not requested checked"), debug("Proceeding with resumeWrites") ENDRULE RULE after resumeWrites CLASS org.xnio.channels.TranslatingSuspendableChannel METHOD resumeWrites AT EXIT IF flagged("race condition enabled for ResumeWritesOnHandlingWritableChannelTestCase") DO debug("Finished resumeWrites... waking handleWritable"), signalWake("write requested", true) ENDRULESetReadListenerOnHandlingReadableChannelTestCase.btm000066400000000000000000000075401257016060700364450ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/resources/org/xnio/racecondition RULE handle readable before anything else CLASS org.xnio.racecondition.SetReadListenerOnHandlingReadableChannelTestCase$SetReadListener METHOD run AT ENTRY IF TRUE DO debug("wait for handleReadable#1"), waitFor("handleReadable#1"), debug("proceed with SetReadListener#run") ENDRULE RULE handle readable 1 CLASS org.xnio.racecondition.SetReadListenerOnHandlingReadableChannelTestCase$InvokeHandleReadable METHOD run AFTER INVOKE org.xnio.racecondition.SetReadListenerOnHandlingReadableChannelTestCase$MyTranslatingSuspendableChannel.handleReadable 1 IF TRUE DO debug("Finished attempt 1 to handle readable"), signalWake("handleReadable#1", true), flag("handle readable1 finished") ENDRULE RULE suspend reads CLASS org.xnio.racecondition.SetReadListenerOnHandlingReadableChannelTestCase$SetReadListener METHOD run AFTER INVOKE org.xnio.racecondition.SetReadListenerOnHandlingReadableChannelTestCase$MyTranslatingSuspendableChannel.suspendReads() IF TRUE DO debug("Suspended reads... waking handleReadable#2"), signalWake("suspend reads", true), debug("Waiting for handleReadable#2 to complete"), waitFor("handleReadable#2"), debug("Proceeding with set read listener") ENDRULE RULE at handle readable 2 CLASS org.xnio.channels.TranslatingSuspendableChannel METHOD handleReadable AT INVOKE org.xnio.channels.TranslatingSuspendableChannel.clearFlags 1 IF flagged("handle readable1 finished") AND NOT flagged("handle readable2 finished") DO debug("Waiting for suspended reads before proceeding with attempt 2 to handle readable"), waitFor("suspend reads") ENDRULE RULE after handle readable 2 CLASS org.xnio.racecondition.SetReadListenerOnHandlingReadableChannelTestCase$InvokeHandleReadable METHOD run AFTER INVOKE org.xnio.racecondition.SetReadListenerOnHandlingReadableChannelTestCase$MyTranslatingSuspendableChannel.handleReadable 2 IF TRUE DO debug("Finished attempt 2 to handle readable"), signalWake("handleReadable#2", true), flag("handle readable2 finished") ENDRULE RULE set read listener CLASS org.xnio.racecondition.SetReadListenerOnHandlingReadableChannelTestCase$SetReadListener METHOD run AFTER INVOKE org.xnio.ChannelListener$Setter.set IF TRUE DO debug("Changed listener... waking handleReadable#3"), signalWake("set listener", true), debug("Waiting for handleReadable#3 to complete"), waitFor("handleReadable#3"), debug("Proceeding with resumeReads") ENDRULE RULE at handle readable 3 CLASS org.xnio.channels.TranslatingSuspendableChannel METHOD handleReadable AT INVOKE org.xnio.Bits.anyAreSet 1 IF flagged("handle readable2 finished") AND NOT flagged("handle readable3 finished") DO debug("Waiting for set listener before proceeding with attempt 3 to handle readable"), waitFor("set listener") ENDRULE RULE after handle readable 3 CLASS org.xnio.racecondition.SetReadListenerOnHandlingReadableChannelTestCase$InvokeHandleReadable METHOD run AFTER INVOKE org.xnio.racecondition.SetReadListenerOnHandlingReadableChannelTestCase$MyTranslatingSuspendableChannel.handleReadable 3 IF TRUE DO debug("Finished attempt 3 to handle readable"), signalWake("handleReadable#3", true), flag("handle readable3 finished") ENDRULE RULE resume reads CLASS org.xnio.racecondition.SetReadListenerOnHandlingReadableChannelTestCase$SetReadListener METHOD run AFTER INVOKE org.xnio.racecondition.SetReadListenerOnHandlingReadableChannelTestCase$MyTranslatingSuspendableChannel.resumeReads IF TRUE DO debug("Resumed reads... waking handleReadable#4"), signalWake("resume reads", true) ENDRULE RULE at handle readable 4 CLASS org.xnio.channels.TranslatingSuspendableChannel METHOD handleReadable AT INVOKE org.xnio.channels.TranslatingSuspendableChannel.clearFlags 1 IF flagged("handle readable3 finished") DO debug("Waiting for resume reads before proceeding with attempt 4 to handle readable"), waitFor("resume reads") ENDRULESetReadReadyOnHandlingReadableChannelTestCase.btm000066400000000000000000000030511257016060700357150ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/resources/org/xnio/racecondition RULE enable race condition scenario CLASS org.xnio.racecondition.SetReadReadyOnHandlingReadableChannelTestCase METHOD test AT INVOKE java.lang.Thread.start 1 IF TRUE DO debug("Enabling race condition scenario"), flag("race condition enabled for SetReadReadyOnHandlingReadableChannelTestCase") ENDRULE RULE handle readable checked read ready is false CLASS org.xnio.channels.TranslatingSuspendableChannel METHOD handleReadable AFTER INVOKE org.xnio.Bits.allAreClear 1 IF flagged("race condition enabled for SetReadReadyOnHandlingReadableChannelTestCase") DO debug("TranslatingSuspendableChannel just checked that read is not ready... waiting for setReadReady"), signalWake("read not ready checked", true), waitFor("read ready"), debug("Now read is ready... proceeding with handleReadable after a check that read is not ready") ENDRULE RULE setReadReady after handleReadable checked read ready is false CLASS org.xnio.channels.TranslatingSuspendableChannel METHOD setReadReady AT ENTRY IF flagged("race condition enabled for SetReadReadyOnHandlingReadableChannelTestCase") DO debug("setReadReady... waiting for handle readable to check read ready is false"), waitFor("read not ready checked"), debug("Proceeding with setReadReady") ENDRULE RULE after setReadReady CLASS org.xnio.channels.TranslatingSuspendableChannel METHOD setReadReady AT EXIT IF flagged("race condition enabled for SetReadReadyOnHandlingReadableChannelTestCase") DO debug("Finished setReadReady... waking handleReadable"), signalWake("read ready", true) ENDRULESetReadRequiresWriteOnWritingSslChannelTestCase.btm000066400000000000000000000022021257016060700364210ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/resources/org/xnio/racecondition RULE write cannot handle NEED_UNWRAP CLASS org.xnio.ssl.JsseConnectedSslStreamChannel METHOD handleHandshake #AT INVOKE org.xnio.ssl.JsseConnectedSslStreamChannel.readRequiresWrite 2 AFTER INVOKE org.xnio.ssl.JsseConnectedSslStreamChannel.handleUnwrapResult IF TRUE DO debug("write could not handle NEED_UNWRAP... waking red thread before setWriteRequiresRead"), signalWake("write cannot handle NEED_UNWRAP", true), # if this thread manages to wait without timing out, an assert !readRequiesWrite() will fail waitFor("read thread finished", 300), debug("proceeding with assert !readRequiresWrite; setWriteRequiresRead"); ENDRULE RULE start Read thread CLASS org.xnio.racecondition.SetReadRequiresWriteOnWritingSslChannelTestCase$Read METHOD run AT ENTRY IF TRUE DO debug("holding read thread"), waitFor("write cannot handle NEED_UNWRAP"), debug("starting read thread") ENDRULE RULE finish Read thread CLASS org.xnio.racecondition.SetReadRequiresWriteOnWritingSslChannelTestCase$Read METHOD run AT EXIT IF TRUE DO debug("finished read thread... waking write thread"), signalWake("read thread finished") ENDRULE SetWriteListenerOnHandlingWritableChannelTestCase.btm000066400000000000000000000076001257016060700367330ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/resources/org/xnio/racecondition RULE handle writable before anything else CLASS org.xnio.racecondition.SetWriteListenerOnHandlingWritableChannelTestCase$SetWriteListener METHOD run AT ENTRY IF TRUE DO debug("wait for handleWritable#1"), waitFor("handleWritable#1"), debug("proceed with SetWriteListener#run") ENDRULE RULE handle writable 1 CLASS org.xnio.racecondition.SetWriteListenerOnHandlingWritableChannelTestCase$InvokeHandleWritable METHOD run AFTER INVOKE org.xnio.racecondition.SetWriteListenerOnHandlingWritableChannelTestCase$MyTranslatingSuspendableChannel.handleWritable 1 IF TRUE DO debug("Finished attempt 1 to handle writable"), signalWake("handleWritable#1", true), flag("handle writable1 finished") ENDRULE RULE suspend writes CLASS org.xnio.racecondition.SetWriteListenerOnHandlingWritableChannelTestCase$SetWriteListener METHOD run AFTER INVOKE org.xnio.racecondition.SetWriteListenerOnHandlingWritableChannelTestCase$MyTranslatingSuspendableChannel.suspendWrites() IF TRUE DO debug("Suspended writes... waking handleWritable#2"), signalWake("suspend writes", true), debug("Waiting for handleWritable#2 to complete"), waitFor("handleWritable#2"), debug("Proceeding with set write listener") ENDRULE RULE at handle writable 2 CLASS org.xnio.channels.TranslatingSuspendableChannel METHOD handleWritable AT INVOKE org.xnio.channels.TranslatingSuspendableChannel.clearFlags 1 IF flagged("handle writable1 finished") AND NOT flagged("handle writable2 finished") DO debug("Waiting for suspended writes before proceeding with attempt 2 to handle writable"), waitFor("suspend writes") ENDRULE RULE after handle writable 2 CLASS org.xnio.racecondition.SetWriteListenerOnHandlingWritableChannelTestCase$InvokeHandleWritable METHOD run AFTER INVOKE org.xnio.racecondition.SetWriteListenerOnHandlingWritableChannelTestCase$MyTranslatingSuspendableChannel.handleWritable 2 IF TRUE DO debug("Finished attempt 2 to handle writable"), signalWake("handleWritable#2", true), flag("handle writable2 finished") ENDRULE RULE set write listener CLASS org.xnio.racecondition.SetWriteListenerOnHandlingWritableChannelTestCase$SetWriteListener METHOD run AFTER INVOKE org.xnio.ChannelListener$Setter.set IF TRUE DO debug("Changed listener... waking handleWritable#3"), signalWake("set listener", true), debug("Waiting for handleWritable#3 to complete"), waitFor("handleWritable#3"), debug("Proceeding with resumeWrites") ENDRULE RULE at handle writable 3 CLASS org.xnio.channels.TranslatingSuspendableChannel METHOD handleWritable AT INVOKE org.xnio.Bits.anyAreSet 1 IF flagged("handle writable2 finished") AND NOT flagged("handle writable3 finished") DO debug("Waiting for set listener before proceeding with attempt 3 to handle writable"), waitFor("set listener") ENDRULE RULE after handle writable 3 CLASS org.xnio.racecondition.SetWriteListenerOnHandlingWritableChannelTestCase$InvokeHandleWritable METHOD run AFTER INVOKE org.xnio.racecondition.SetWriteListenerOnHandlingWritableChannelTestCase$MyTranslatingSuspendableChannel.handleWritable 3 IF TRUE DO debug("Finished attempt 3 to handle writable"), signalWake("handleWritable#3", true), flag("handle writable3 finished") ENDRULE RULE resume writes CLASS org.xnio.racecondition.SetWriteListenerOnHandlingWritableChannelTestCase$SetWriteListener METHOD run AFTER INVOKE org.xnio.racecondition.SetWriteListenerOnHandlingWritableChannelTestCase$MyTranslatingSuspendableChannel.resumeWrites IF TRUE DO debug("Resumed writes... waking handleWritable#4"), signalWake("resume writes", true) ENDRULE RULE at handle writable 4 CLASS org.xnio.channels.TranslatingSuspendableChannel METHOD handleWritable AT INVOKE org.xnio.channels.TranslatingSuspendableChannel.clearFlags 1 IF flagged("handle writable3 finished") DO debug("Waiting for resume writes before proceeding with attempt 4 to handle writable"), waitFor("resume writes") ENDRULESetWriteReadyOnHandlingWritableChannelTestCase.btm000066400000000000000000000031001257016060700362010ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/resources/org/xnio/racecondition RULE enable race condition scenario CLASS org.xnio.racecondition.SetWriteReadyOnHandlingWritableChannelTestCase METHOD test AT INVOKE java.lang.Thread.start 1 IF TRUE DO debug("Enabling race condition scenario"), flag("race condition enabled for SetWriteReadyOnHandlingWritableChannelTestCase") ENDRULE RULE handle writable checked write ready is false CLASS org.xnio.channels.TranslatingSuspendableChannel METHOD handleWritable AFTER INVOKE org.xnio.Bits.allAreClear 1 IF flagged("race condition enabled for SetWriteReadyOnHandlingWritableChannelTestCase") DO debug("TranslatingSuspendableChannel just checked that write is not ready... waiting for setWriteReady"), signalWake("write not ready checked", true), waitFor("write ready"), debug("Now write is ready... proceeding with handleWritable after a check that write is not ready") ENDRULE RULE setWriteReady after handleWritable checked write ready is false CLASS org.xnio.channels.TranslatingSuspendableChannel METHOD setWriteReady AT ENTRY IF flagged("race condition enabled for SetWriteReadyOnHandlingWritableChannelTestCase") DO debug("setWriteReady... waiting for handle writable to check write ready is false"), waitFor("write not ready checked"), debug("Proceeding with setWriteReady") ENDRULE RULE after setWriteReady CLASS org.xnio.channels.TranslatingSuspendableChannel METHOD setWriteReady AT EXIT IF flagged("race condition enabled for SetWriteReadyOnHandlingWritableChannelTestCase") DO debug("Finished setWriteReady... waking handleWritable"), signalWake("write ready", true) ENDRULESetWriteRequiresReadOnReadingSslChannelTestCase.btm000066400000000000000000000020651257016060700363560ustar00rootroot00000000000000xnio-3.3.2.Final/api/src/test/resources/org/xnio/racecondition RULE read cannot handle NEED_WRAP CLASS org.xnio.ssl.JsseConnectedSslStreamChannel METHOD handleHandshake AFTER INVOKE org.xnio.ssl.JsseConnectedSslStreamChannel.handleWrapResult IF TRUE DO debug("read could not handle NEED_WRAP... waking write thread before setReadRequiresWrite"), signalWake("read cannot handle NEED_WRAP", true), # if this thread manages to wait without timing out, an assert !writeRequiresRead() will fail waitFor("write thread finished", 300), debug("proceeding with assert !writeRequiresRead; setReadRequiresWrite"); ENDRULE RULE start Write thread CLASS org.xnio.racecondition.SetWriteRequiresReadOnReadingSslChannelTestCase$Write METHOD run AT ENTRY IF TRUE DO debug("holding write thread"), waitFor("read cannot handle NEED_WRAP"), debug("starting write thread") ENDRULE RULE finish Write thread CLASS org.xnio.racecondition.SetWriteRequiresReadOnReadingSslChannelTestCase$Write METHOD run AT EXIT IF TRUE DO debug("finished write thread... waking read thread"), signalWake("write thread finished") ENDRULE xnio-3.3.2.Final/api/src/test/resources/security.policy000066400000000000000000000003421257016060700231500ustar00rootroot00000000000000grant { permission java.util.PropertyPermission "java.security.policy", "write"; permission java.lang.RuntimePermission "createSecurityManager"; permission java.lang.RuntimePermission "setSecurityManager"; };xnio-3.3.2.Final/nio-impl/000077500000000000000000000000001257016060700152545ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/pom.xml000066400000000000000000000137121257016060700165750ustar00rootroot00000000000000 4.0.0 XNIO NIO Implementation The NIO implementation of the XNIO project xnio-nio jar org.jboss.xnio xnio-all 3.3.2.Final INFO false org.jboss.logging jboss-logging provided org.jboss.logging jboss-logging-processor provided org.jboss.logging jboss-logging-annotations provided org.jboss.xnio xnio-api junit junit test org.jboss.logmanager jboss-logmanager test org.jboss.byteman byteman test org.jboss.byteman byteman-bmunit test testng org.testng org.jboss.byteman byteman-install test ${project.basedir}/src/main/resources true maven-compiler-plugin maven-jar-plugin org.xnio.nio.Version ${project.version} ${project.artifactId} maven-source-plugin maven-surefire-plugin java.util.logging.manager org.jboss.logmanager.LogManager test.level ${test.level} xnio.nio.selector.main ${xnio.nio.selector.main} xnio.nio.selector.temp ${xnio.nio.selector.temp} xnio.nio.selector.provider ${xnio.nio.selector.provider} xnio.nio.old-locking ${xnio.nio.old-locking} true true xnio-3.3.2.Final/nio-impl/src/000077500000000000000000000000001257016060700160435ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/main/000077500000000000000000000000001257016060700167675ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/main/java/000077500000000000000000000000001257016060700177105ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/main/java/org/000077500000000000000000000000001257016060700204775ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/000077500000000000000000000000001257016060700214545ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/000077500000000000000000000000001257016060700222415ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/AbstractNioChannel.java000066400000000000000000000034571257016060700266170ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.CloseableChannel; abstract class AbstractNioChannel> implements CloseableChannel { // default buffer size used by subclasses protected static final int DEFAULT_BUFFER_SIZE = 0x10000; private final ChannelListener.SimpleSetter closeSetter = new ChannelListener.SimpleSetter(); protected final NioXnioWorker worker; AbstractNioChannel(final NioXnioWorker worker) { this.worker = worker; } public final XnioWorker getWorker() { return worker; } public final ChannelListener.Setter getCloseSetter() { return closeSetter; } public XnioIoThread getIoThread() { return worker.chooseThread(); } @SuppressWarnings("unchecked") protected final C typed() { return (C) this; } protected final void invokeCloseHandler() { ChannelListeners.invokeChannelListener(typed(), closeSetter.get()); } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/AbstractNioStreamConnection.java000066400000000000000000000027021257016060700305120ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio; import org.xnio.StreamConnection; import org.xnio.conduits.StreamSinkConduit; import org.xnio.conduits.StreamSourceConduit; /** * @author David M. Lloyd */ abstract class AbstractNioStreamConnection extends StreamConnection { protected AbstractNioStreamConnection(final WorkerThread workerThread) { super(workerThread); } protected void setSourceConduit(final StreamSourceConduit conduit) { super.setSourceConduit(conduit); } protected void setSinkConduit(final StreamSinkConduit conduit) { super.setSinkConduit(conduit); } protected boolean readClosed() { return super.readClosed(); } protected boolean writeClosed() { return super.writeClosed(); } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/Log.java000066400000000000000000000122351257016060700236300ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio; import static org.jboss.logging.Logger.Level.*; import static org.jboss.logging.annotations.Transform.TransformType.*; import java.io.IOException; import java.io.InterruptedIOException; import java.nio.channels.spi.SelectorProvider; import java.util.concurrent.RejectedExecutionException; import org.jboss.logging.BasicLogger; import org.jboss.logging.Logger; import org.jboss.logging.annotations.Cause; import org.jboss.logging.annotations.Field; import org.jboss.logging.annotations.LogMessage; import org.jboss.logging.annotations.Message; import org.jboss.logging.annotations.MessageLogger; import org.jboss.logging.annotations.Transform; import org.xnio.ClosedWorkerException; import org.xnio.channels.ReadTimeoutException; import org.xnio.channels.WriteTimeoutException; /** * @author David M. Lloyd */ @MessageLogger(projectCode = "XNIO") interface Log extends BasicLogger { Log log = Logger.getMessageLogger(Log.class, "org.xnio.nio"); Log socketLog = Logger.getMessageLogger(Log.class, "org.xnio.nio.socket"); Log selectorLog = Logger.getMessageLogger(Log.class, "org.xnio.nio.selector"); Log tcpServerLog = Logger.getMessageLogger(Log.class, "org.xnio.nio.tcp.server"); Log udpServerChannelLog = Logger.getMessageLogger(Log.class, "org.xnio.nio.udp.server.channel"); // Greeting @LogMessage(level = INFO) @Message(value = "XNIO NIO Implementation Version %s") void greeting(String version); // Validation messages - cross-check with xnio-api @LogMessage(level = ERROR) @Message(id = 11, value = "Task %s failed with an exception") void taskFailed(Runnable command, @Cause Throwable cause); @Message(id = 15, value = "Parameter '%s' is out of range") IllegalArgumentException parameterOutOfRange(String name); @Message(id = 39, value = "Value for option '%s' is out of range") IllegalArgumentException optionOutOfRange(String name); // I/O errors - cross-check with xnio-api @Message(id = 800, value = "Read timed out") ReadTimeoutException readTimeout(); @Message(id = 801, value = "Write timed out") WriteTimeoutException writeTimeout(); @Message(id = 808, value = "I/O operation was interrupted") InterruptedIOException interruptedIO(); InterruptedIOException interruptedIO(@Field int bytesTransferred); @Message(id = 815, value = "Worker is shut down") ClosedWorkerException workerShutDown(); // Unsupported implementation operations - cross-check with xnio-api @Message(id = 900, value = "Method '%s' is not supported on this implementation") UnsupportedOperationException unsupported(String methodName); // General run-time messages - cross-check with xnio-api @Message(id = 1006, value = "Failed to invoke file watch callback") @LogMessage(level = ERROR) void failedToInvokeFileWatchCallback(@Cause Throwable cause); // Validation messages @Message(id = 7000, value = "No threads configured") IllegalArgumentException noThreads(); @Message(id = 7001, value = "Balancing token count must be greater than zero and less than thread count") IllegalArgumentException balancingTokens(); @Message(id = 7002, value = "Balancing connection count must be greater than zero when tokens are used") IllegalArgumentException balancingConnectionCount(); @Message(id = 7003, value = "Buffer is too large") IllegalArgumentException bufferTooLarge(); @Message(id = 7004, value = "No functional selector provider is available") IllegalStateException noSelectorProvider(); @Message(id = 7005, value = "Unexpected exception opening a selector") IllegalStateException unexpectedSelectorOpenProblem(@Cause Throwable cause); @Message(id = 7006, value = "XNIO IO factory is from the wrong provider") IllegalArgumentException notNioProvider(); @Message(id = 7007, value = "Thread is terminating") RejectedExecutionException threadExiting(); // I/O messages @LogMessage(level = WARN) @Message(id = 8000, value = "Received an I/O error on selection: %s") void selectionError(IOException e); // Trace @LogMessage(level = TRACE) @Message(value = "Starting up with selector provider %s") void selectorProvider(@Transform(GET_CLASS) SelectorProvider provider); @LogMessage(level = TRACE) @Message(value = "Using %s for main selectors and %s for temp selectors") void selectors(Object mainSelectorCreator, Object tempSelectorCreator); } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/NioHandle.java000066400000000000000000000050171257016060700247500ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio; import java.nio.channels.CancelledKeyException; import java.nio.channels.SelectionKey; import static org.xnio.Bits.allAreClear; import static org.xnio.Bits.allAreSet; /** * @author David M. Lloyd */ abstract class NioHandle { private final WorkerThread workerThread; private final SelectionKey selectionKey; protected NioHandle(final WorkerThread workerThread, final SelectionKey selectionKey) { this.workerThread = workerThread; this.selectionKey = selectionKey; } void resume(final int ops) { try { if (! allAreSet(selectionKey.interestOps(), ops)) { workerThread.setOps(selectionKey, ops); } } catch (CancelledKeyException ignored) {} } void wakeup(final int ops) { workerThread.queueTask(new Runnable() { public void run() { handleReady(ops); } }); try { if (! allAreSet(selectionKey.interestOps(), ops)) { workerThread.setOps(selectionKey, ops); } } catch (CancelledKeyException ignored) {} } void suspend(final int ops) { try { if (! allAreClear(selectionKey.interestOps(), ops)) { workerThread.clearOps(selectionKey, ops); } } catch (CancelledKeyException ignored) {} } boolean isResumed(final int ops) { try { return allAreSet(selectionKey.interestOps(), ops); } catch (CancelledKeyException ignored) { return false; } } abstract void handleReady(final int ops); abstract void forceTermination(); abstract void terminated(); WorkerThread getWorkerThread() { return workerThread; } SelectionKey getSelectionKey() { return selectionKey; } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/NioPipeSinkConduit.java000066400000000000000000000144311257016060700266250ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio; import static org.xnio.nio.Log.log; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.nio.channels.Pipe; import java.nio.channels.SelectionKey; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import org.xnio.Xnio; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.StreamSourceChannel; import org.xnio.channels.WriteTimeoutException; import org.xnio.conduits.Conduits; import org.xnio.conduits.StreamSinkConduit; import org.xnio.conduits.WriteReadyHandler; /** * @author David M. Lloyd */ final class NioPipeSinkConduit extends NioHandle implements StreamSinkConduit { private final Pipe.SinkChannel sinkChannel; private final NioPipeStreamConnection connection; private WriteReadyHandler writeReadyHandler; @SuppressWarnings("unused") private volatile int writeTimeout; private long lastWrite; @SuppressWarnings("rawtypes") private static final AtomicIntegerFieldUpdater writeTimeoutUpdater = AtomicIntegerFieldUpdater.newUpdater(NioPipeSinkConduit.class, "writeTimeout"); NioPipeSinkConduit(final WorkerThread workerThread, final SelectionKey selectionKey, final NioPipeStreamConnection connection) { super(workerThread, selectionKey); this.connection = connection; this.sinkChannel = (Pipe.SinkChannel) selectionKey.channel(); } void handleReady(int ops) { try { writeReadyHandler.writeReady(); } catch (Throwable ignored) { } } public XnioWorker getWorker() { return getWorkerThread().getWorker(); } void forceTermination() { final WriteReadyHandler write = writeReadyHandler; if (write != null) write.forceTermination(); } void terminated() { final WriteReadyHandler write = writeReadyHandler; if (write != null) write.terminated(); } // Write methods int getAndSetWriteTimeout(int newVal) { return writeTimeoutUpdater.getAndSet(this, newVal); } int getWriteTimeout() { return writeTimeout; } private void checkWriteTimeout(final boolean xfer) throws WriteTimeoutException { int timeout = writeTimeout; if (timeout > 0) { if (xfer) { lastWrite = System.nanoTime(); } else { long lastWrite = this.lastWrite; if (lastWrite > 0L && ((System.nanoTime() - lastWrite) / 1000000L) > (long) timeout) { throw log.writeTimeout(); } } } } public final long transferFrom(final FileChannel src, final long position, final long count) throws IOException { long res = src.transferTo(position, count, sinkChannel); checkWriteTimeout(res > 0L); return res; } public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { return Conduits.transfer(source, count, throughBuffer, this); } public int write(final ByteBuffer src) throws IOException { int res = sinkChannel.write(src); checkWriteTimeout(res > 0); return res; } public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException { if (length == 1) { return write(srcs[offset]); } long res = sinkChannel.write(srcs, offset, length); checkWriteTimeout(res > 0L); return res; } @Override public int writeFinal(ByteBuffer src) throws IOException { return Conduits.writeFinalBasic(this, src); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { return Conduits.writeFinalBasic(this, srcs, offset, length); } public boolean flush() throws IOException { return true; } public void terminateWrites() throws IOException { if (connection.writeClosed()) try { sinkChannel.close(); } catch (ClosedChannelException ignored) { } finally { writeTerminated(); } } public void truncateWrites() throws IOException { terminateWrites(); } void writeTerminated() { final WriteReadyHandler writeReadyHandler = this.writeReadyHandler; if (writeReadyHandler != null) try { writeReadyHandler.terminated(); } catch (Throwable ignored) {} } public boolean isWriteShutdown() { return connection.isWriteShutdown(); } public void resumeWrites() { resume(SelectionKey.OP_WRITE); } public void suspendWrites() { suspend(SelectionKey.OP_WRITE); } public void wakeupWrites() { wakeup(SelectionKey.OP_WRITE); } public boolean isWriteResumed() { return isResumed(SelectionKey.OP_WRITE); } public void awaitWritable() throws IOException { Xnio.checkBlockingAllowed(); SelectorUtils.await((NioXnio)getWorker().getXnio(), sinkChannel, SelectionKey.OP_WRITE); } public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException { Xnio.checkBlockingAllowed(); SelectorUtils.await((NioXnio)getWorker().getXnio(), sinkChannel, SelectionKey.OP_WRITE, time, timeUnit); } public XnioIoThread getWriteThread() { return getWorkerThread(); } public void setWriteReadyHandler(final WriteReadyHandler handler) { writeReadyHandler = handler; } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/NioPipeSourceConduit.java000066400000000000000000000141021257016060700271540ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio; import static org.xnio.nio.Log.log; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.CancelledKeyException; import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.nio.channels.Pipe; import java.nio.channels.SelectionKey; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import org.xnio.Xnio; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.ReadTimeoutException; import org.xnio.channels.StreamSinkChannel; import org.xnio.conduits.Conduits; import org.xnio.conduits.ReadReadyHandler; import org.xnio.conduits.StreamSourceConduit; /** * @author David M. Lloyd */ final class NioPipeSourceConduit extends NioHandle implements StreamSourceConduit { private final Pipe.SourceChannel sourceChannel; private final NioPipeStreamConnection connection; private ReadReadyHandler readReadyHandler; @SuppressWarnings("unused") private volatile int readTimeout; private long lastRead; @SuppressWarnings("rawtypes") private static final AtomicIntegerFieldUpdater readTimeoutUpdater = AtomicIntegerFieldUpdater.newUpdater(NioPipeSourceConduit.class, "readTimeout"); NioPipeSourceConduit(final WorkerThread workerThread, final SelectionKey selectionKey, final NioPipeStreamConnection connection) { super(workerThread, selectionKey); this.connection = connection; this.sourceChannel = (Pipe.SourceChannel) selectionKey.channel(); } void handleReady(int ops) { try { readReadyHandler.readReady(); } catch (CancelledKeyException ignored) {} } public XnioWorker getWorker() { return getWorkerThread().getWorker(); } void forceTermination() { final ReadReadyHandler read = readReadyHandler; if (read != null) read.forceTermination(); } void terminated() { final ReadReadyHandler read = readReadyHandler; if (read != null) read.terminated(); } // Read methods int getAndSetReadTimeout(int newVal) { return readTimeoutUpdater.getAndSet(this, newVal); } int getReadTimeout() { return readTimeout; } private void checkReadTimeout(final boolean xfer) throws ReadTimeoutException { int timeout = readTimeout; if (timeout > 0) { if (xfer) { lastRead = System.nanoTime(); } else { long lastRead = this.lastRead; if (lastRead > 0L && ((System.nanoTime() - lastRead) / 1000000L) > (long) timeout) { throw log.readTimeout(); } } } } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { long res = target.transferFrom(sourceChannel, position, count); checkReadTimeout(res > 0L); return res; } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { return Conduits.transfer(this, count, throughBuffer, target); } public int read(final ByteBuffer dst) throws IOException { int res; try { res = sourceChannel.read(dst); } catch (ClosedChannelException e) { return -1; } if (res != -1) checkReadTimeout(res > 0); return res; } public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { if (length == 1) { return read(dsts[offset]); } long res; try { res = sourceChannel.read(dsts, offset, length); } catch (ClosedChannelException e) { return -1L; } if (res != -1L) checkReadTimeout(res > 0L); return res; } public void terminateReads() throws IOException { if (connection.readClosed()) try { sourceChannel.close(); } catch (ClosedChannelException ignored) { } finally { readTerminated(); } } void readTerminated() { final ReadReadyHandler readReadyHandler = this.readReadyHandler; if (readReadyHandler != null) try { readReadyHandler.terminated(); } catch (Throwable ignored) {} } public boolean isReadShutdown() { return connection.isReadShutdown(); } public void resumeReads() { resume(SelectionKey.OP_READ); } public void suspendReads() { suspend(SelectionKey.OP_READ); } public void wakeupReads() { wakeup(SelectionKey.OP_READ); } public boolean isReadResumed() { return isResumed(SelectionKey.OP_READ); } public void awaitReadable() throws IOException { Xnio.checkBlockingAllowed(); SelectorUtils.await((NioXnio)getWorker().getXnio(), sourceChannel, SelectionKey.OP_READ); } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { Xnio.checkBlockingAllowed(); SelectorUtils.await((NioXnio)getWorker().getXnio(), sourceChannel, SelectionKey.OP_READ, time, timeUnit); } public XnioIoThread getReadThread() { return getWorkerThread(); } public void setReadReadyHandler(final ReadReadyHandler handler) { this.readReadyHandler = handler; } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/NioPipeStreamConnection.java000066400000000000000000000120771257016060700276520ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio; import java.io.IOException; import java.net.SocketAddress; import java.nio.channels.Channel; import java.nio.channels.ClosedChannelException; import java.nio.channels.Pipe; import java.nio.channels.SelectionKey; import org.xnio.Option; import org.xnio.Options; import static org.xnio.IoUtils.safeClose; /** * @author David M. Lloyd */ final class NioPipeStreamConnection extends AbstractNioStreamConnection { private final Pipe.SourceChannel sourceChannel; private final Pipe.SinkChannel sinkChannel; private final NioPipeSourceConduit sourceConduit; private final NioPipeSinkConduit sinkConduit; NioPipeStreamConnection(final WorkerThread workerThread, final SelectionKey sourceKey, final SelectionKey sinkKey) { super(workerThread); if (sourceKey != null) { setSourceConduit(sourceConduit = new NioPipeSourceConduit(workerThread, sourceKey, this)); sourceKey.attach(sourceConduit); sourceChannel = (Pipe.SourceChannel) sourceKey.channel(); } else { sourceConduit = null; sourceChannel = null; } if (sinkKey != null) { setSinkConduit(sinkConduit = new NioPipeSinkConduit(workerThread, sinkKey, this)); sinkKey.attach(sinkConduit); sinkChannel = (Pipe.SinkChannel) sinkKey.channel(); } else { sinkConduit = null; sinkChannel = null; } } public SocketAddress getPeerAddress() { return null; } public SocketAddress getLocalAddress() { return null; } protected boolean readClosed() { return super.readClosed(); } protected boolean writeClosed() { return super.writeClosed(); } protected void notifyWriteClosed() { final NioPipeSinkConduit conduit = sinkConduit; if (conduit != null) conduit.writeTerminated(); } protected void notifyReadClosed() { final NioPipeSourceConduit conduit = sourceConduit; if (conduit != null) conduit.readTerminated(); } private void cancelKey(final NioHandle handle) { if (handle != null) handle.getWorkerThread().cancelKey(handle.getSelectionKey()); } private void closeChannel(final Channel channel) throws IOException { if (channel != null) try { channel.close(); } catch (ClosedChannelException ignored) {} } protected void closeAction() throws IOException { try { cancelKey(sourceConduit); cancelKey(sinkConduit); closeChannel(sourceChannel); closeChannel(sinkChannel); } finally { safeClose(sourceChannel); safeClose(sinkChannel); } } public boolean supportsOption(final Option option) { return option == Options.READ_TIMEOUT && sourceConduit != null || option == Options.WRITE_TIMEOUT && sinkConduit != null; } public T getOption(final Option option) throws IOException { if (option == Options.READ_TIMEOUT) { final NioPipeSourceConduit conduit = sourceConduit; return conduit == null ? null : option.cast(Integer.valueOf(conduit.getReadTimeout())); } else if (option == Options.WRITE_TIMEOUT) { final NioPipeSinkConduit conduit = sinkConduit; return conduit == null ? null : option.cast(Integer.valueOf(conduit.getWriteTimeout())); } else { return null; } } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { T result; if (option == Options.READ_TIMEOUT) { final NioPipeSourceConduit conduit = sourceConduit; result = conduit == null ? null : option.cast(Integer.valueOf(conduit.getAndSetReadTimeout(value == null ? 0 : Options.READ_TIMEOUT.cast(value).intValue()))); } else if (option == Options.WRITE_TIMEOUT) { final NioPipeSinkConduit conduit = sinkConduit; result = conduit == null ? null : option.cast(Integer.valueOf(conduit.getAndSetWriteTimeout(value == null ? 0 : Options.WRITE_TIMEOUT.cast(value).intValue()))); } else { return null; } return result; } Pipe.SourceChannel getSourcePipeChannel() { return sourceChannel; } Pipe.SinkChannel getSinkPipeChannel() { return sinkChannel; } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/NioSocketConduit.java000066400000000000000000000270061257016060700263350ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio; import static org.xnio.nio.Log.log; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.CancelledKeyException; import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import org.xnio.Bits; import org.xnio.Xnio; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.ReadTimeoutException; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; import org.xnio.channels.WriteTimeoutException; import org.xnio.conduits.Conduits; import org.xnio.conduits.ReadReadyHandler; import org.xnio.conduits.StreamSinkConduit; import org.xnio.conduits.StreamSourceConduit; import org.xnio.conduits.WriteReadyHandler; final class NioSocketConduit extends NioHandle implements StreamSourceConduit, StreamSinkConduit { private final SocketChannel socketChannel; private final NioSocketStreamConnection connection; private ReadReadyHandler readReadyHandler; private WriteReadyHandler writeReadyHandler; @SuppressWarnings("unused") private volatile int readTimeout; private long lastRead; @SuppressWarnings("rawtypes") private static final AtomicIntegerFieldUpdater readTimeoutUpdater = AtomicIntegerFieldUpdater.newUpdater(NioSocketConduit.class, "readTimeout"); @SuppressWarnings("unused") private volatile int writeTimeout; private long lastWrite; @SuppressWarnings("rawtypes") private static final AtomicIntegerFieldUpdater writeTimeoutUpdater = AtomicIntegerFieldUpdater.newUpdater(NioSocketConduit.class, "writeTimeout"); NioSocketConduit(final WorkerThread workerThread, final SelectionKey selectionKey, final NioSocketStreamConnection connection) { super(workerThread, selectionKey); this.connection = connection; this.socketChannel = (SocketChannel) selectionKey.channel(); } void handleReady(int ops) { try { if (ops == 0) { // the dreaded bug final SelectionKey key = getSelectionKey(); final int interestOps = key.interestOps(); if (interestOps != 0) { ops = interestOps; } else { // urp forceTermination(); return; } } if (Bits.allAreSet(ops, SelectionKey.OP_READ)) try { if (isReadShutdown()) suspendReads(); readReadyHandler.readReady(); } catch (Throwable ignored) { } if (Bits.allAreSet(ops, SelectionKey.OP_WRITE)) try { if (isWriteShutdown()) suspendWrites(); writeReadyHandler.writeReady(); } catch (Throwable ignored) { } } catch (CancelledKeyException ignored) {} } public XnioWorker getWorker() { return getWorkerThread().getWorker(); } void forceTermination() { final ReadReadyHandler read = readReadyHandler; if (read != null) read.forceTermination(); final WriteReadyHandler write = writeReadyHandler; if (write != null) write.forceTermination(); } void terminated() { final ReadReadyHandler read = readReadyHandler; if (read != null) read.terminated(); final WriteReadyHandler write = writeReadyHandler; if (write != null) write.terminated(); } // Write methods int getAndSetWriteTimeout(int newVal) { return writeTimeoutUpdater.getAndSet(this, newVal); } int getWriteTimeout() { return writeTimeout; } private void checkWriteTimeout(final boolean xfer) throws WriteTimeoutException { int timeout = writeTimeout; if (timeout > 0) { if (xfer) { lastWrite = System.nanoTime(); } else { long lastRead = this.lastWrite; if (lastRead > 0L && ((System.nanoTime() - lastRead) / 1000000L) > (long) timeout) { throw log.writeTimeout(); } } } } public final long transferFrom(final FileChannel src, final long position, final long count) throws IOException { long res = src.transferTo(position, count, socketChannel); checkWriteTimeout(res > 0L); return res; } public long transferFrom(final StreamSourceChannel source, final long count, final ByteBuffer throughBuffer) throws IOException { return Conduits.transfer(source, count, throughBuffer, this); } public int write(final ByteBuffer src) throws IOException { int res = socketChannel.write(src); checkWriteTimeout(res > 0); return res; } public long write(final ByteBuffer[] srcs, final int offset, final int length) throws IOException { if (length == 1) { return write(srcs[offset]); } long res = socketChannel.write(srcs, offset, length); checkWriteTimeout(res > 0L); return res; } @Override public int writeFinal(ByteBuffer src) throws IOException { return Conduits.writeFinalBasic(this, src); } @Override public long writeFinal(ByteBuffer[] srcs, int offset, int length) throws IOException { return Conduits.writeFinalBasic(this, srcs, offset, length); } public boolean flush() throws IOException { return true; } public void terminateWrites() throws IOException { if (connection.writeClosed()) try { suspend(SelectionKey.OP_WRITE); socketChannel.socket().shutdownOutput(); } catch (ClosedChannelException ignored) { } finally { writeTerminated(); } } public void truncateWrites() throws IOException { terminateWrites(); } void writeTerminated() { final WriteReadyHandler writeReadyHandler = this.writeReadyHandler; if (writeReadyHandler != null) try { writeReadyHandler.terminated(); } catch (Throwable ignored) {} } public boolean isWriteShutdown() { return connection.isWriteShutdown(); } public void resumeWrites() { resume(SelectionKey.OP_WRITE); } public void suspendWrites() { suspend(SelectionKey.OP_WRITE); } public void wakeupWrites() { wakeup(SelectionKey.OP_WRITE); } public boolean isWriteResumed() { return isResumed(SelectionKey.OP_WRITE); } public void awaitWritable() throws IOException { Xnio.checkBlockingAllowed(); if (isWriteShutdown()) { return; } SelectorUtils.await((NioXnio)getWorker().getXnio(), socketChannel, SelectionKey.OP_WRITE); } public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException { Xnio.checkBlockingAllowed(); if (isWriteShutdown()) { return; } SelectorUtils.await((NioXnio)getWorker().getXnio(), socketChannel, SelectionKey.OP_WRITE, time, timeUnit); } public XnioIoThread getWriteThread() { return getWorkerThread(); } public void setWriteReadyHandler(final WriteReadyHandler handler) { writeReadyHandler = handler; } // Read methods int getAndSetReadTimeout(int newVal) { return readTimeoutUpdater.getAndSet(this, newVal); } int getReadTimeout() { return readTimeout; } private void checkReadTimeout(final boolean xfer) throws ReadTimeoutException { int timeout = readTimeout; if (timeout > 0) { if (xfer) { lastRead = System.nanoTime(); } else { long lastRead = this.lastRead; if (lastRead > 0L && ((System.nanoTime() - lastRead) / 1000000L) > (long) timeout) { throw log.readTimeout(); } } } } public long transferTo(final long position, final long count, final FileChannel target) throws IOException { long res = target.transferFrom(socketChannel, position, count); checkReadTimeout(res > 0L); return res; } public long transferTo(final long count, final ByteBuffer throughBuffer, final StreamSinkChannel target) throws IOException { return Conduits.transfer(this, count, throughBuffer, target); } public int read(final ByteBuffer dst) throws IOException { int res; try { res = socketChannel.read(dst); } catch (ClosedChannelException e) { return -1; } if (res != -1) checkReadTimeout(res > 0); else terminateReads(); return res; } public long read(final ByteBuffer[] dsts, final int offset, final int length) throws IOException { if (length == 1) { return read(dsts[offset]); } long res; try { res = socketChannel.read(dsts, offset, length); } catch (ClosedChannelException e) { return -1L; } if (res != -1L) checkReadTimeout(res > 0L); else terminateReads(); return res; } public void terminateReads() throws IOException { if (connection.readClosed()) try { suspend(SelectionKey.OP_READ); socketChannel.socket().shutdownInput(); } catch (ClosedChannelException ignored) { } finally { readTerminated(); } } void readTerminated() { final ReadReadyHandler readReadyHandler = this.readReadyHandler; if (readReadyHandler != null) try { readReadyHandler.terminated(); } catch (Throwable ignored) {} } public boolean isReadShutdown() { return connection.isReadShutdown(); } public void resumeReads() { resume(SelectionKey.OP_READ); } public void suspendReads() { suspend(SelectionKey.OP_READ); } public void wakeupReads() { wakeup(SelectionKey.OP_READ); } public boolean isReadResumed() { return isResumed(SelectionKey.OP_READ); } public void awaitReadable() throws IOException { Xnio.checkBlockingAllowed(); SelectorUtils.await((NioXnio)getWorker().getXnio(), socketChannel, SelectionKey.OP_READ); } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { Xnio.checkBlockingAllowed(); SelectorUtils.await((NioXnio)getWorker().getXnio(), socketChannel, SelectionKey.OP_READ, time, timeUnit); } public XnioIoThread getReadThread() { return getWorkerThread(); } public void setReadReadyHandler(final ReadReadyHandler handler) { this.readReadyHandler = handler; } SocketChannel getSocketChannel() { return socketChannel; } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/NioSocketStreamConnection.java000066400000000000000000000163061257016060700302040ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio; import java.io.IOException; import java.net.InetSocketAddress; import java.net.Socket; import java.net.SocketAddress; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectionKey; import java.nio.channels.SocketChannel; import java.util.Set; import org.xnio.Option; import org.xnio.Options; /** * @author David M. Lloyd */ final class NioSocketStreamConnection extends AbstractNioStreamConnection { private final NioTcpServerHandle serverConduit; private final NioSocketConduit conduit; NioSocketStreamConnection(final WorkerThread workerThread, final SelectionKey key, final NioTcpServerHandle serverConduit) { super(workerThread); conduit = new NioSocketConduit(workerThread, key, this); key.attach(conduit); this.serverConduit = serverConduit; setSinkConduit(conduit); setSourceConduit(conduit); } public SocketAddress getPeerAddress() { final Socket socket = conduit.getSocketChannel().socket(); return new InetSocketAddress(socket.getInetAddress(), socket.getPort()); } public SocketAddress getLocalAddress() { final Socket socket = conduit.getSocketChannel().socket(); return new InetSocketAddress(socket.getLocalAddress(), socket.getLocalPort()); } private static final Set> OPTIONS = Option.setBuilder() .add(Options.CLOSE_ABORT) .add(Options.IP_TRAFFIC_CLASS) .add(Options.KEEP_ALIVE) .add(Options.READ_TIMEOUT) .add(Options.RECEIVE_BUFFER) .add(Options.SEND_BUFFER) .add(Options.TCP_NODELAY) .add(Options.TCP_OOB_INLINE) .add(Options.WRITE_TIMEOUT) .create(); public boolean supportsOption(final Option option) { return OPTIONS.contains(option); } public T getOption(final Option option) throws IOException { if (option == Options.CLOSE_ABORT) { return option.cast(Boolean.valueOf(conduit.getSocketChannel().socket().getSoLinger() == 0)); } else if (option == Options.IP_TRAFFIC_CLASS) { return option.cast(Integer.valueOf(conduit.getSocketChannel().socket().getTrafficClass())); } else if (option == Options.KEEP_ALIVE) { return option.cast(Boolean.valueOf(conduit.getSocketChannel().socket().getKeepAlive())); } else if (option == Options.READ_TIMEOUT) { return option.cast(Integer.valueOf(conduit.getReadTimeout())); } else if (option == Options.RECEIVE_BUFFER) { return option.cast(Integer.valueOf(conduit.getSocketChannel().socket().getReceiveBufferSize())); } else if (option == Options.SEND_BUFFER) { return option.cast(Integer.valueOf(conduit.getSocketChannel().socket().getSendBufferSize())); } else if (option == Options.TCP_NODELAY) { return option.cast(Boolean.valueOf(conduit.getSocketChannel().socket().getTcpNoDelay())); } else if (option == Options.TCP_OOB_INLINE) { return option.cast(Boolean.valueOf(conduit.getSocketChannel().socket().getOOBInline())); } else if (option == Options.WRITE_TIMEOUT) { return option.cast(Integer.valueOf(conduit.getWriteTimeout())); } else { return null; } } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { T result; if (option == Options.CLOSE_ABORT) { result = option.cast(Boolean.valueOf(conduit.getSocketChannel().socket().getSoLinger() == 0)); conduit.getSocketChannel().socket().setSoLinger(Options.CLOSE_ABORT.cast(value, Boolean.FALSE).booleanValue(), 0); } else if (option == Options.IP_TRAFFIC_CLASS) { result = option.cast(Integer.valueOf(conduit.getSocketChannel().socket().getTrafficClass())); conduit.getSocketChannel().socket().setTrafficClass(Options.IP_TRAFFIC_CLASS.cast(value).intValue()); } else if (option == Options.KEEP_ALIVE) { result = option.cast(Boolean.valueOf(conduit.getSocketChannel().socket().getKeepAlive())); conduit.getSocketChannel().socket().setKeepAlive(Options.KEEP_ALIVE.cast(value, Boolean.FALSE).booleanValue()); } else if (option == Options.READ_TIMEOUT) { result = option.cast(Integer.valueOf(conduit.getAndSetReadTimeout(value == null ? 0 : Options.READ_TIMEOUT.cast(value).intValue()))); } else if (option == Options.RECEIVE_BUFFER) { result = option.cast(Integer.valueOf(conduit.getSocketChannel().socket().getReceiveBufferSize())); conduit.getSocketChannel().socket().setReceiveBufferSize(Options.RECEIVE_BUFFER.cast(value).intValue()); } else if (option == Options.SEND_BUFFER) { result = option.cast(Integer.valueOf(conduit.getSocketChannel().socket().getSendBufferSize())); conduit.getSocketChannel().socket().setSendBufferSize(Options.SEND_BUFFER.cast(value).intValue()); } else if (option == Options.TCP_NODELAY) { result = option.cast(Boolean.valueOf(conduit.getSocketChannel().socket().getTcpNoDelay())); conduit.getSocketChannel().socket().setTcpNoDelay(Options.TCP_NODELAY.cast(value, Boolean.FALSE).booleanValue()); } else if (option == Options.TCP_OOB_INLINE) { result = option.cast(Boolean.valueOf(conduit.getSocketChannel().socket().getOOBInline())); conduit.getSocketChannel().socket().setOOBInline(Options.TCP_OOB_INLINE.cast(value, Boolean.FALSE).booleanValue()); } else if (option == Options.WRITE_TIMEOUT) { result = option.cast(Integer.valueOf(conduit.getAndSetWriteTimeout(value == null ? 0 : Options.WRITE_TIMEOUT.cast(value).intValue()))); } else { return null; } return result; } protected void closeAction() throws IOException { try { conduit.getWorkerThread().cancelKey(conduit.getSelectionKey()); conduit.getSocketChannel().close(); } catch (ClosedChannelException ignored) { } finally { final NioTcpServerHandle conduit = this.serverConduit; if (conduit!= null) conduit.channelClosed(); } } protected void notifyWriteClosed() { conduit.writeTerminated(); } protected void notifyReadClosed() { conduit.readTerminated(); } SocketChannel getChannel() { return conduit.getSocketChannel(); } NioSocketConduit getConduit() { return conduit; } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/NioTcpServer.java000066400000000000000000000521051257016060700254720ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio; import java.io.Closeable; import java.io.IOException; import java.net.ServerSocket; import java.net.Socket; import java.net.SocketAddress; import java.nio.channels.SelectionKey; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.util.Set; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicLongFieldUpdater; import org.jboss.logging.Logger; import org.xnio.IoUtils; import org.xnio.Option; import org.xnio.ChannelListener; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.StreamConnection; import org.xnio.XnioExecutor; import org.xnio.channels.AcceptListenerSettable; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.UnsupportedOptionException; import org.xnio.management.XnioServerMXBean; import static org.xnio.IoUtils.safeClose; import static org.xnio.nio.Log.log; import static org.xnio.nio.Log.tcpServerLog; final class NioTcpServer extends AbstractNioChannel implements AcceptingChannel, AcceptListenerSettable { private static final String FQCN = NioTcpServer.class.getName(); private volatile ChannelListener acceptListener; private final NioTcpServerHandle[] handles; private final ServerSocketChannel channel; private final ServerSocket socket; private final Closeable mbeanHandle; private static final Set> options = Option.setBuilder() .add(Options.REUSE_ADDRESSES) .add(Options.RECEIVE_BUFFER) .add(Options.SEND_BUFFER) .add(Options.KEEP_ALIVE) .add(Options.TCP_OOB_INLINE) .add(Options.TCP_NODELAY) .add(Options.CONNECTION_HIGH_WATER) .add(Options.CONNECTION_LOW_WATER) .add(Options.READ_TIMEOUT) .add(Options.WRITE_TIMEOUT) .create(); @SuppressWarnings("unused") private volatile int keepAlive; @SuppressWarnings("unused") private volatile int oobInline; @SuppressWarnings("unused") private volatile int tcpNoDelay; @SuppressWarnings("unused") private volatile int sendBuffer = -1; @SuppressWarnings("unused") private volatile long connectionStatus = CONN_LOW_MASK | CONN_HIGH_MASK; @SuppressWarnings("unused") private volatile int readTimeout; @SuppressWarnings("unused") private volatile int writeTimeout; private volatile int tokenConnectionCount; volatile boolean resumed; private static final long CONN_LOW_MASK = 0x000000007FFFFFFFL; private static final long CONN_LOW_BIT = 0L; @SuppressWarnings("unused") private static final long CONN_LOW_ONE = 1L; private static final long CONN_HIGH_MASK = 0x3FFFFFFF80000000L; private static final long CONN_HIGH_BIT = 31L; @SuppressWarnings("unused") private static final long CONN_HIGH_ONE = 1L << CONN_HIGH_BIT; private static final AtomicIntegerFieldUpdater keepAliveUpdater = AtomicIntegerFieldUpdater.newUpdater(NioTcpServer.class, "keepAlive"); private static final AtomicIntegerFieldUpdater oobInlineUpdater = AtomicIntegerFieldUpdater.newUpdater(NioTcpServer.class, "oobInline"); private static final AtomicIntegerFieldUpdater tcpNoDelayUpdater = AtomicIntegerFieldUpdater.newUpdater(NioTcpServer.class, "tcpNoDelay"); private static final AtomicIntegerFieldUpdater sendBufferUpdater = AtomicIntegerFieldUpdater.newUpdater(NioTcpServer.class, "sendBuffer"); private static final AtomicIntegerFieldUpdater readTimeoutUpdater = AtomicIntegerFieldUpdater.newUpdater(NioTcpServer.class, "readTimeout"); private static final AtomicIntegerFieldUpdater writeTimeoutUpdater = AtomicIntegerFieldUpdater.newUpdater(NioTcpServer.class, "writeTimeout"); private static final AtomicLongFieldUpdater connectionStatusUpdater = AtomicLongFieldUpdater.newUpdater(NioTcpServer.class, "connectionStatus"); NioTcpServer(final NioXnioWorker worker, final ServerSocketChannel channel, final OptionMap optionMap) throws IOException { super(worker); this.channel = channel; final WorkerThread[] threads = worker.getAll(); final int threadCount = threads.length; if (threadCount == 0) { throw log.noThreads(); } final int tokens = optionMap.get(Options.BALANCING_TOKENS, -1); final int connections = optionMap.get(Options.BALANCING_CONNECTIONS, 16); if (tokens != -1) { if (tokens < 1 || tokens >= threadCount) { throw log.balancingTokens(); } if (connections < 1) { throw log.balancingConnectionCount(); } tokenConnectionCount = connections; } socket = channel.socket(); if (optionMap.contains(Options.SEND_BUFFER)) { final int sendBufferSize = optionMap.get(Options.SEND_BUFFER, DEFAULT_BUFFER_SIZE); if (sendBufferSize < 1) { throw log.parameterOutOfRange("sendBufferSize"); } sendBufferUpdater.set(this, sendBufferSize); } if (optionMap.contains(Options.KEEP_ALIVE)) { keepAliveUpdater.lazySet(this, optionMap.get(Options.KEEP_ALIVE, false) ? 1 : 0); } if (optionMap.contains(Options.TCP_OOB_INLINE)) { oobInlineUpdater.lazySet(this, optionMap.get(Options.TCP_OOB_INLINE, false) ? 1 : 0); } if (optionMap.contains(Options.TCP_NODELAY)) { tcpNoDelayUpdater.lazySet(this, optionMap.get(Options.TCP_NODELAY, false) ? 1 : 0); } if (optionMap.contains(Options.READ_TIMEOUT)) { readTimeoutUpdater.lazySet(this, optionMap.get(Options.READ_TIMEOUT, 0)); } if (optionMap.contains(Options.WRITE_TIMEOUT)) { writeTimeoutUpdater.lazySet(this, optionMap.get(Options.WRITE_TIMEOUT, 0)); } int perThreadLow, perThreadLowRem; int perThreadHigh, perThreadHighRem; if (optionMap.contains(Options.CONNECTION_HIGH_WATER) || optionMap.contains(Options.CONNECTION_LOW_WATER)) { final int highWater = optionMap.get(Options.CONNECTION_HIGH_WATER, Integer.MAX_VALUE); final int lowWater = optionMap.get(Options.CONNECTION_LOW_WATER, highWater); if (highWater <= 0) { throw badHighWater(); } if (lowWater <= 0 || lowWater > highWater) { throw badLowWater(highWater); } final long highLowWater = (long) highWater << CONN_HIGH_BIT | (long) lowWater << CONN_LOW_BIT; connectionStatusUpdater.lazySet(this, highLowWater); perThreadLow = lowWater / threadCount; perThreadLowRem = lowWater % threadCount; perThreadHigh = highWater / threadCount; perThreadHighRem = highWater % threadCount; } else { perThreadLow = Integer.MAX_VALUE; perThreadLowRem = 0; perThreadHigh = Integer.MAX_VALUE; perThreadHighRem = 0; connectionStatusUpdater.lazySet(this, CONN_LOW_MASK | CONN_HIGH_MASK); } final NioTcpServerHandle[] handles = new NioTcpServerHandle[threadCount]; for (int i = 0, length = threadCount; i < length; i++) { final SelectionKey key = threads[i].registerChannel(channel); handles[i] = new NioTcpServerHandle(this, key, threads[i], i < perThreadHighRem ? perThreadHigh + 1 : perThreadHigh, i < perThreadLowRem ? perThreadLow + 1 : perThreadLow); key.attach(handles[i]); } this.handles = handles; if (tokens > 0) { for (int i = 0; i < threadCount; i ++) { handles[i].initializeTokenCount(i < tokens ? connections : 0); } } mbeanHandle = NioXnio.register(new XnioServerMXBean() { public String getProviderName() { return "nio"; } public String getWorkerName() { return worker.getName(); } public String getBindAddress() { return String.valueOf(getLocalAddress()); } public int getConnectionCount() { final AtomicInteger counter = new AtomicInteger(); final CountDownLatch latch = new CountDownLatch(handles.length); for (final NioTcpServerHandle handle : handles) { handle.getWorkerThread().execute(new Runnable() { public void run() { counter.getAndAdd(handle.getConnectionCount()); latch.countDown(); } }); } try { latch.await(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return counter.get(); } public int getConnectionLimitHighWater() { return getHighWater(connectionStatus); } public int getConnectionLimitLowWater() { return getLowWater(connectionStatus); } }); } private static IllegalArgumentException badLowWater(final int highWater) { return new IllegalArgumentException("Low water must be greater than 0 and less than or equal to high water (" + highWater + ")"); } private static IllegalArgumentException badHighWater() { return new IllegalArgumentException("High water must be greater than 0"); } public void close() throws IOException { try { channel.close(); } finally { for (NioTcpServerHandle handle : handles) { handle.getWorkerThread().cancelKey(handle.getSelectionKey()); } safeClose(mbeanHandle); } } public boolean supportsOption(final Option option) { return options.contains(option); } public T getOption(final Option option) throws UnsupportedOptionException, IOException { if (option == Options.REUSE_ADDRESSES) { return option.cast(Boolean.valueOf(socket.getReuseAddress())); } else if (option == Options.RECEIVE_BUFFER) { return option.cast(Integer.valueOf(socket.getReceiveBufferSize())); } else if (option == Options.SEND_BUFFER) { final int value = sendBuffer; return value == -1 ? null : option.cast(Integer.valueOf(value)); } else if (option == Options.KEEP_ALIVE) { return option.cast(Boolean.valueOf(keepAlive != 0)); } else if (option == Options.TCP_OOB_INLINE) { return option.cast(Boolean.valueOf(oobInline != 0)); } else if (option == Options.TCP_NODELAY) { return option.cast(Boolean.valueOf(tcpNoDelay != 0)); } else if (option == Options.READ_TIMEOUT) { return option.cast(Integer.valueOf(readTimeout)); } else if (option == Options.WRITE_TIMEOUT) { return option.cast(Integer.valueOf(writeTimeout)); } else if (option == Options.CONNECTION_HIGH_WATER) { return option.cast(Integer.valueOf(getHighWater(connectionStatus))); } else if (option == Options.CONNECTION_LOW_WATER) { return option.cast(Integer.valueOf(getLowWater(connectionStatus))); } else { return null; } } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { final Object old; if (option == Options.REUSE_ADDRESSES) { old = Boolean.valueOf(socket.getReuseAddress()); socket.setReuseAddress(Options.REUSE_ADDRESSES.cast(value, Boolean.FALSE).booleanValue()); } else if (option == Options.RECEIVE_BUFFER) { old = Integer.valueOf(socket.getReceiveBufferSize()); final int newValue = Options.RECEIVE_BUFFER.cast(value, Integer.valueOf(DEFAULT_BUFFER_SIZE)).intValue(); if (newValue < 1) { throw log.optionOutOfRange("RECEIVE_BUFFER"); } socket.setReceiveBufferSize(newValue); } else if (option == Options.SEND_BUFFER) { final int newValue = Options.SEND_BUFFER.cast(value, Integer.valueOf(DEFAULT_BUFFER_SIZE)).intValue(); if (newValue < 1) { throw log.optionOutOfRange("SEND_BUFFER"); } final int oldValue = sendBufferUpdater.getAndSet(this, newValue); old = oldValue == -1 ? null : Integer.valueOf(oldValue); } else if (option == Options.KEEP_ALIVE) { old = Boolean.valueOf(keepAliveUpdater.getAndSet(this, Options.KEEP_ALIVE.cast(value, Boolean.FALSE).booleanValue() ? 1 : 0) != 0); } else if (option == Options.TCP_OOB_INLINE) { old = Boolean.valueOf(oobInlineUpdater.getAndSet(this, Options.TCP_OOB_INLINE.cast(value, Boolean.FALSE).booleanValue() ? 1 : 0) != 0); } else if (option == Options.TCP_NODELAY) { old = Boolean.valueOf(tcpNoDelayUpdater.getAndSet(this, Options.TCP_NODELAY.cast(value, Boolean.FALSE).booleanValue() ? 1 : 0) != 0); } else if (option == Options.READ_TIMEOUT) { old = Integer.valueOf(readTimeoutUpdater.getAndSet(this, Options.READ_TIMEOUT.cast(value, Integer.valueOf(0)).intValue())); } else if (option == Options.WRITE_TIMEOUT) { old = Integer.valueOf(writeTimeoutUpdater.getAndSet(this, Options.WRITE_TIMEOUT.cast(value, Integer.valueOf(0)).intValue())); } else if (option == Options.CONNECTION_HIGH_WATER) { old = Integer.valueOf(getHighWater(updateWaterMark(-1, Options.CONNECTION_HIGH_WATER.cast(value, Integer.valueOf(Integer.MAX_VALUE)).intValue()))); } else if (option == Options.CONNECTION_LOW_WATER) { old = Integer.valueOf(getLowWater(updateWaterMark(Options.CONNECTION_LOW_WATER.cast(value, Integer.valueOf(Integer.MAX_VALUE)).intValue(), -1))); } else { return null; } return option.cast(old); } private long updateWaterMark(int reqNewLowWater, int reqNewHighWater) { // at least one must be specified assert reqNewLowWater != -1 || reqNewHighWater != -1; // if both given, low must be less than high assert reqNewLowWater == -1 || reqNewHighWater == -1 || reqNewLowWater <= reqNewHighWater; long oldVal, newVal; int oldHighWater, oldLowWater; int newLowWater, newHighWater; do { oldVal = connectionStatus; oldLowWater = getLowWater(oldVal); oldHighWater = getHighWater(oldVal); newLowWater = reqNewLowWater == -1 ? oldLowWater : reqNewLowWater; newHighWater = reqNewHighWater == -1 ? oldHighWater : reqNewHighWater; // Make sure the new values make sense if (reqNewLowWater != -1 && newLowWater > newHighWater) { newHighWater = newLowWater; } else if (reqNewHighWater != -1 && newHighWater < newLowWater) { newLowWater = newHighWater; } // See if the change would be redundant if (oldLowWater == newLowWater && oldHighWater == newHighWater) { return oldVal; } newVal = (long)newLowWater << CONN_LOW_BIT | (long)newHighWater << CONN_HIGH_BIT; } while (! connectionStatusUpdater.compareAndSet(this, oldVal, newVal)); final NioTcpServerHandle[] conduits = handles; final int threadCount = conduits.length; int perThreadLow, perThreadLowRem; int perThreadHigh, perThreadHighRem; perThreadLow = newLowWater / threadCount; perThreadLowRem = newLowWater % threadCount; perThreadHigh = newHighWater / threadCount; perThreadHighRem = newHighWater % threadCount; for (int i = 0; i < conduits.length; i++) { NioTcpServerHandle conduit = conduits[i]; conduit.executeSetTask(i < perThreadHighRem ? perThreadHigh + 1 : perThreadHigh, i < perThreadLowRem ? perThreadLow + 1 : perThreadLow); } return oldVal; } private static int getHighWater(final long value) { return (int) ((value & CONN_HIGH_MASK) >> CONN_HIGH_BIT); } private static int getLowWater(final long value) { return (int) ((value & CONN_LOW_MASK) >> CONN_LOW_BIT); } public NioSocketStreamConnection accept() throws IOException { final WorkerThread current = WorkerThread.getCurrent(); final NioTcpServerHandle handle = handles[current.getNumber()]; if (! handle.getConnection()) { return null; } final SocketChannel accepted; boolean ok = false; try { accepted = channel.accept(); if (accepted != null) try { accepted.configureBlocking(false); final Socket socket = accepted.socket(); socket.setKeepAlive(keepAlive != 0); socket.setOOBInline(oobInline != 0); socket.setTcpNoDelay(tcpNoDelay != 0); final int sendBuffer = this.sendBuffer; if (sendBuffer > 0) socket.setSendBufferSize(sendBuffer); final SelectionKey selectionKey = current.registerChannel(accepted); final NioSocketStreamConnection newConnection = new NioSocketStreamConnection(current, selectionKey, handle); newConnection.setOption(Options.READ_TIMEOUT, Integer.valueOf(readTimeout)); newConnection.setOption(Options.WRITE_TIMEOUT, Integer.valueOf(writeTimeout)); ok = true; return newConnection; } finally { if (! ok) safeClose(accepted); } } catch (IOException e) { return null; } finally { if (! ok) { handle.freeConnection(); } } // by contract, only a resume will do return null; } public String toString() { return String.format("TCP server (NIO) <%s>", Integer.toHexString(hashCode())); } public ChannelListener getAcceptListener() { return acceptListener; } public void setAcceptListener(final ChannelListener acceptListener) { this.acceptListener = acceptListener; } public ChannelListener.Setter getAcceptSetter() { return new AcceptListenerSettable.Setter(this); } public boolean isOpen() { return channel.isOpen(); } public SocketAddress getLocalAddress() { return socket.getLocalSocketAddress(); } public A getLocalAddress(final Class type) { final SocketAddress address = getLocalAddress(); return type.isInstance(address) ? type.cast(address) : null; } public void suspendAccepts() { resumed = false; doResume(0); } public void resumeAccepts() { resumed = true; doResume(SelectionKey.OP_ACCEPT); } public boolean isAcceptResumed() { return resumed; } private void doResume(final int op) { if (op == 0) { for (NioTcpServerHandle handle : handles) { handle.suspend(); } } else { for (NioTcpServerHandle handle : handles) { handle.resume(); } } } public void wakeupAccepts() { tcpServerLog.logf(FQCN, Logger.Level.TRACE, null, "Wake up accepts on %s", this); resumeAccepts(); final NioTcpServerHandle[] handles = this.handles; final int idx = IoUtils.getThreadLocalRandom().nextInt(handles.length); handles[idx].wakeup(SelectionKey.OP_ACCEPT); } public void awaitAcceptable() throws IOException { throw log.unsupported("awaitAcceptable"); } public void awaitAcceptable(final long time, final TimeUnit timeUnit) throws IOException { throw log.unsupported("awaitAcceptable"); } @Deprecated public XnioExecutor getAcceptThread() { return getIoThread(); } NioTcpServerHandle getHandle(final int number) { return handles[number]; } int getTokenConnectionCount() { return tokenConnectionCount; } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/NioTcpServerHandle.java000066400000000000000000000134651257016060700266140ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio; import java.nio.channels.SelectionKey; import org.xnio.ChannelListeners; import static java.lang.Thread.currentThread; import static org.xnio.IoUtils.safeClose; /** * @author David M. Lloyd */ final class NioTcpServerHandle extends NioHandle { private final Runnable freeTask; private final NioTcpServer server; private int count; private int low; private int high; private int tokenCount = -1; private boolean stopped; NioTcpServerHandle(final NioTcpServer server, final SelectionKey key, final WorkerThread thread, final int low, final int high) { super(thread, key); this.server = server; this.low = low; this.high = high; freeTask = new Runnable() { public void run() { freeConnection(); } }; } void handleReady(final int ops) { ChannelListeners.invokeChannelListener(server, server.getAcceptListener()); } void forceTermination() { safeClose(server); } void terminated() { server.invokeCloseHandler(); } Runnable getFreeTask() { return freeTask; } void resume() { final WorkerThread thread = getWorkerThread(); if (thread == currentThread()) { if (! stopped && server.resumed) super.resume(SelectionKey.OP_ACCEPT); } else { thread.execute(new Runnable() { public void run() { resume(); } }); } } void suspend() { final WorkerThread thread = getWorkerThread(); if (thread == currentThread()) { if (stopped || ! server.resumed) super.suspend(SelectionKey.OP_ACCEPT); } else { thread.execute(new Runnable() { public void run() { suspend(); } }); } } void channelClosed() { final WorkerThread thread = getWorkerThread(); if (thread == currentThread()) { freeConnection(); } else { thread.execute(freeTask); } } void freeConnection() { assert currentThread() == getWorkerThread(); if (count-- <= low && tokenCount != 0 && stopped) { stopped = false; if (server.resumed) { super.resume(SelectionKey.OP_ACCEPT); } } } void setTokenCount(final int newCount) { WorkerThread workerThread = getWorkerThread(); if (workerThread == currentThread()) { if (tokenCount == 0) { tokenCount = newCount; if (count <= low && stopped) { stopped = false; if (server.resumed) { super.resume(SelectionKey.OP_ACCEPT); } } return; } workerThread = workerThread.getNextThread(); } setThreadNewCount(workerThread, newCount); } private void setThreadNewCount(final WorkerThread workerThread, final int newCount) { final int number = workerThread.getNumber(); workerThread.execute(new Runnable() { public void run() { server.getHandle(number).setTokenCount(newCount); } }); } void initializeTokenCount(final int newCount) { WorkerThread workerThread = getWorkerThread(); final int number = workerThread.getNumber(); if (workerThread == currentThread()) { tokenCount = newCount; if (newCount == 0) { stopped = true; super.suspend(SelectionKey.OP_ACCEPT); } } else { workerThread.execute(new Runnable() { public void run() { server.getHandle(number).initializeTokenCount(newCount); } }); } } boolean getConnection() { assert currentThread() == getWorkerThread(); if (stopped) { return false; } if (tokenCount != -1 && --tokenCount == 0) { setThreadNewCount(getWorkerThread().getNextThread(), server.getTokenConnectionCount()); } if (++count >= high || tokenCount == 0) { stopped = true; super.suspend(SelectionKey.OP_ACCEPT); } return true; } public void executeSetTask(final int high, final int low) { final WorkerThread thread = getWorkerThread(); if (thread == currentThread()) { this.high = high; this.low = low; if (count >= high && ! stopped) { stopped = true; suspend(); } else if (count <= low && stopped) { stopped = false; if (server.resumed) resume(); } } else { thread.execute(new Runnable() { public void run() { executeSetTask(high, low); } }); } } int getConnectionCount() { assert currentThread() == getWorkerThread(); return count; } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/NioUdpChannel.java000066400000000000000000000336171257016060700256050ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio; import java.io.IOException; import java.net.DatagramSocket; import java.net.InetAddress; import java.net.NetworkInterface; import java.net.SocketAddress; import java.net.StandardSocketOptions; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.DatagramChannel; import java.nio.channels.MembershipKey; import java.nio.channels.SelectionKey; import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.xnio.Buffers; import org.xnio.Option; import org.xnio.ChannelListener; import org.xnio.Options; import org.xnio.XnioExecutor; import org.xnio.channels.MulticastMessageChannel; import org.xnio.channels.ReadListenerSettable; import org.xnio.channels.SocketAddressBuffer; import org.xnio.channels.UnsupportedOptionException; import org.xnio.channels.WriteListenerSettable; import static org.xnio.Xnio.NIO2; import static org.xnio.nio.Log.log; import static org.xnio.nio.Log.udpServerChannelLog; /** * */ class NioUdpChannel extends AbstractNioChannel implements MulticastMessageChannel, ReadListenerSettable, WriteListenerSettable { private final NioUdpChannelHandle handle; private ChannelListener readListener; private ChannelListener writeListener; private final DatagramChannel datagramChannel; private final AtomicBoolean callFlag = new AtomicBoolean(false); NioUdpChannel(final NioXnioWorker worker, final DatagramChannel datagramChannel) throws ClosedChannelException { super(worker); this.datagramChannel = datagramChannel; final WorkerThread workerThread = worker.chooseThread(); final SelectionKey key = workerThread.registerChannel(datagramChannel); handle = new NioUdpChannelHandle(workerThread, key, this); key.attach(handle); } public SocketAddress getLocalAddress() { return datagramChannel.socket().getLocalSocketAddress(); } public A getLocalAddress(final Class type) { return type.isInstance(getLocalAddress()) ? type.cast(getLocalAddress()) : null; } public int receiveFrom(final SocketAddressBuffer addressBuffer, final ByteBuffer buffer) throws IOException { final int o = buffer.remaining(); final SocketAddress sourceAddress; try { sourceAddress = datagramChannel.receive(buffer); } catch (ClosedChannelException e) { return -1; } if (sourceAddress == null) { return 0; } else { final int t = o - buffer.remaining(); if (addressBuffer != null) { addressBuffer.setSourceAddress(sourceAddress); addressBuffer.setDestinationAddress(null); } return t; } } public long receiveFrom(final SocketAddressBuffer addressBuffer, final ByteBuffer[] buffers) throws IOException { return receiveFrom(addressBuffer, buffers, 0, buffers.length); } public long receiveFrom(final SocketAddressBuffer addressBuffer, final ByteBuffer[] buffers, final int offs, final int len) throws IOException { if (len == 0) { return 0L; } if (len == 1) { return receiveFrom(addressBuffer, buffers[offs]); } final int o = (int) Math.min(Buffers.remaining(buffers, offs, len), 65536L); final ByteBuffer buffer = ByteBuffer.allocate(o); final SocketAddress sourceAddress; try { sourceAddress = datagramChannel.receive(buffer); } catch (ClosedChannelException e) { return -1L; } if (sourceAddress == null) { return 0L; } else { final int t = o - buffer.remaining(); buffer.flip(); Buffers.copy(buffers, offs, len, buffer); if (addressBuffer != null) { addressBuffer.setSourceAddress(sourceAddress); addressBuffer.setDestinationAddress(null); } return t; } } public boolean sendTo(final SocketAddress target, final ByteBuffer buffer) throws IOException { return datagramChannel.send(buffer, target) != 0; } public boolean sendTo(final SocketAddress target, final ByteBuffer[] buffers) throws IOException { return sendTo(target, buffers, 0, buffers.length); } public boolean sendTo(final SocketAddress target, final ByteBuffer[] buffers, final int offset, final int length) throws IOException { if (length == 0) { return false; } if (length == 1) { return sendTo(target, buffers[offset]); } final long o = Buffers.remaining(buffers, offset, length); if (o > 65535L) { // there will never be enough room throw log.bufferTooLarge(); } final ByteBuffer buffer = ByteBuffer.allocate((int) o); Buffers.copy(buffer, buffers, offset, length); buffer.flip(); return datagramChannel.send(buffer, target) != 0; } public ChannelListener getReadListener() { return readListener; } public void setReadListener(final ChannelListener readListener) { this.readListener = readListener; } public ChannelListener getWriteListener() { return writeListener; } public void setWriteListener(final ChannelListener writeListener) { this.writeListener = writeListener; } public ChannelListener.Setter getReadSetter() { return new ReadListenerSettable.Setter(this); } public ChannelListener.Setter getWriteSetter() { return new WriteListenerSettable.Setter(this); } public boolean flush() throws IOException { return true; } public boolean isOpen() { return datagramChannel.isOpen(); } public void close() throws IOException { if (!callFlag.getAndSet(true)) { udpServerChannelLog.tracef("Closing %s", this); try { cancelKeys(); } catch (Throwable ignored) {} try { datagramChannel.close(); } finally { invokeCloseHandler(); } } } private void cancelKeys() { try { handle.getWorkerThread().cancelKey(handle.getSelectionKey()); } catch (Throwable ignored) {} } public void suspendReads() { handle.suspend(SelectionKey.OP_READ); } public void suspendWrites() { handle.suspend(SelectionKey.OP_WRITE); } public void resumeReads() { handle.resume(SelectionKey.OP_READ); } public void resumeWrites() { handle.resume(SelectionKey.OP_WRITE); } public boolean isReadResumed() { return handle.isResumed(SelectionKey.OP_READ); } public boolean isWriteResumed() { return handle.isResumed(SelectionKey.OP_WRITE); } public void wakeupReads() { handle.wakeup(SelectionKey.OP_READ); } public void wakeupWrites() { handle.wakeup(SelectionKey.OP_WRITE); } public void shutdownReads() throws IOException { throw log.unsupported("shutdownReads"); } public void shutdownWrites() throws IOException { throw log.unsupported("shutdownWrites"); } public void awaitReadable() throws IOException { SelectorUtils.await(worker.getXnio(), datagramChannel, SelectionKey.OP_READ); } public void awaitReadable(final long time, final TimeUnit timeUnit) throws IOException { SelectorUtils.await(worker.getXnio(), datagramChannel, SelectionKey.OP_READ, time, timeUnit); } @Deprecated public XnioExecutor getReadThread() { return getIoThread(); } public void awaitWritable() throws IOException { SelectorUtils.await(worker.getXnio(), datagramChannel, SelectionKey.OP_WRITE); } public void awaitWritable(final long time, final TimeUnit timeUnit) throws IOException { SelectorUtils.await(worker.getXnio(), datagramChannel, SelectionKey.OP_WRITE, time, timeUnit); } @Deprecated public XnioExecutor getWriteThread() { return getIoThread(); } public Key join(final InetAddress group, final NetworkInterface iface) throws IOException { return new NioKey(datagramChannel.join(group, iface)); } public Key join(final InetAddress group, final NetworkInterface iface, final InetAddress source) throws IOException { return new NioKey(datagramChannel.join(group, iface, source)); } private static final Set> OPTIONS = Option.setBuilder() .add(Options.BROADCAST) .add(Options.RECEIVE_BUFFER) .add(Options.SEND_BUFFER) .add(Options.IP_TRAFFIC_CLASS) .add(Options.MULTICAST_TTL) .create(); public boolean supportsOption(final Option option) { return OPTIONS.contains(option); } public T getOption(final Option option) throws UnsupportedOptionException, IOException { final DatagramChannel channel = datagramChannel; final DatagramSocket socket = channel.socket(); if (option == Options.RECEIVE_BUFFER) { return option.cast(Integer.valueOf(socket.getReceiveBufferSize())); } else if (option == Options.SEND_BUFFER) { return option.cast(Integer.valueOf(socket.getSendBufferSize())); } else if (option == Options.BROADCAST) { return option.cast(Boolean.valueOf(socket.getBroadcast())); } else if (option == Options.IP_TRAFFIC_CLASS) { return option.cast(Integer.valueOf(socket.getTrafficClass())); } else { if (NIO2) { if (option == Options.MULTICAST_TTL) { return option.cast(channel.getOption(StandardSocketOptions.IP_MULTICAST_TTL)); } else { return null; } } else { return null; } } } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { final DatagramChannel channel = datagramChannel; final DatagramSocket socket = channel.socket(); final Object old; if (option == Options.RECEIVE_BUFFER) { old = Integer.valueOf(socket.getReceiveBufferSize()); int newValue = Options.RECEIVE_BUFFER.cast(value, Integer.valueOf(DEFAULT_BUFFER_SIZE)).intValue(); if (newValue < 1) { throw log.optionOutOfRange("RECEIVE_BUFFER"); } socket.setReceiveBufferSize(newValue); } else if (option == Options.SEND_BUFFER) { old = Integer.valueOf(socket.getSendBufferSize()); int newValue = Options.SEND_BUFFER.cast(value, Integer.valueOf(DEFAULT_BUFFER_SIZE)).intValue(); if (newValue < 1) { throw log.optionOutOfRange("SEND_BUFFER"); } socket.setSendBufferSize(newValue); } else if (option == Options.IP_TRAFFIC_CLASS) { old = Integer.valueOf(socket.getTrafficClass()); socket.setTrafficClass(Options.IP_TRAFFIC_CLASS.cast(value, Integer.valueOf(0)).intValue()); } else if (option == Options.BROADCAST) { old = Boolean.valueOf(socket.getBroadcast()); socket.setBroadcast(Options.BROADCAST.cast(value, Boolean.FALSE).booleanValue()); } else { if (NIO2) { if (option == Options.MULTICAST_TTL) { old = option.cast(channel.getOption(StandardSocketOptions.IP_MULTICAST_TTL)); channel.setOption(StandardSocketOptions.IP_MULTICAST_TTL, (Integer) value); } else { return null; } } else { return null; } } return option.cast(old); } @Override public String toString() { return String.format("UDP socket channel (NIO) <%h>", this); } class NioKey implements Key { private final MembershipKey key; NioKey(final MembershipKey key) { this.key = key; } public Key block(final InetAddress source) throws IOException, UnsupportedOperationException, IllegalStateException, IllegalArgumentException { key.block(source); return this; } public Key unblock(final InetAddress source) throws IOException, IllegalStateException, UnsupportedOperationException { key.unblock(source); return this; } public MulticastMessageChannel getChannel() { return NioUdpChannel.this; } public InetAddress getGroup() { return key.group(); } public NetworkInterface getNetworkInterface() { return key.networkInterface(); } public InetAddress getSourceAddress() { return key.sourceAddress(); } public boolean isOpen() { return key.isValid(); } public void close() throws IOException { key.drop(); } } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/NioUdpChannelHandle.java000066400000000000000000000044221257016060700267110ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio; import java.nio.channels.CancelledKeyException; import java.nio.channels.SelectionKey; import org.xnio.Bits; import org.xnio.ChannelListeners; import org.xnio.IoUtils; /** * @author David M. Lloyd */ final class NioUdpChannelHandle extends NioHandle { private final NioUdpChannel channel; NioUdpChannelHandle(final WorkerThread workerThread, final SelectionKey selectionKey, final NioUdpChannel channel) { super(workerThread, selectionKey); this.channel = channel; } void handleReady(int ops) { try { if (ops == 0) { // the dreaded bug final SelectionKey key = getSelectionKey(); final int interestOps = key.interestOps(); if (interestOps != 0) { ops = interestOps; } else { // urp forceTermination(); return; } } if (Bits.allAreSet(ops, SelectionKey.OP_READ)) try { ChannelListeners.invokeChannelListener(channel, channel.getReadListener()); } catch (Throwable ignored) { } if (Bits.allAreSet(ops, SelectionKey.OP_WRITE)) try { ChannelListeners.invokeChannelListener(channel, channel.getWriteListener()); } catch (Throwable ignored) { } } catch (CancelledKeyException ignored) {} } void forceTermination() { IoUtils.safeClose(channel); } void terminated() { channel.invokeCloseHandler(); } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/NioXnio.java000066400000000000000000000307311257016060700244730ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2014 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio; import java.io.Closeable; import java.io.IOException; import java.nio.channels.Selector; import java.nio.channels.spi.SelectorProvider; import java.security.AccessController; import java.security.PrivilegedAction; import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import org.xnio.FileSystemWatcher; import org.xnio.IoUtils; import org.xnio.Options; import org.xnio.Xnio; import org.xnio.OptionMap; import org.xnio.XnioWorker; import org.xnio.management.XnioProviderMXBean; import org.xnio.management.XnioServerMXBean; import org.xnio.management.XnioWorkerMXBean; import static org.xnio.nio.Log.log; /** * An NIO-based XNIO provider for a standalone application. */ final class NioXnio extends Xnio { interface SelectorCreator { Selector open() throws IOException; } final SelectorCreator tempSelectorCreator; final SelectorCreator mainSelectorCreator; static { log.greeting(Version.getVersionString()); AccessController.doPrivileged(new PrivilegedAction() { public Void run() { final String bugLevel = System.getProperty("sun.nio.ch.bugLevel"); if (bugLevel == null) System.setProperty("sun.nio.ch.bugLevel", ""); return null; } }); } /** * Construct a new NIO-based XNIO provider instance. Should only be invoked by the service loader. */ NioXnio() { super("nio"); final Object[] objects = AccessController.doPrivileged( new PrivilegedAction() { public Object[] run() { final SelectorProvider defaultProvider = SelectorProvider.provider(); final String chosenProvider = System.getProperty("xnio.nio.selector.provider"); SelectorProvider provider = null; if (chosenProvider != null) { try { provider = Class.forName(chosenProvider, true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance(); provider.openSelector().close(); } catch (Throwable e) { // not available provider = null; } } if (provider == null) { try { // Mac OS X and BSD provider = Class.forName("sun.nio.ch.KQueueSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance(); provider.openSelector().close(); } catch (Throwable e) { // not available provider = null; } } if (provider == null) { try { // Linux provider = Class.forName("sun.nio.ch.EPollSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance(); provider.openSelector().close(); } catch (Throwable e) { // not available provider = null; } } if (provider == null) { try { // Solaris provider = Class.forName("sun.nio.ch.DevPollSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance(); provider.openSelector().close(); } catch (Throwable e) { // not available provider = null; } } if (provider == null) { try { // AIX provider = Class.forName("sun.nio.ch.PollsetSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance(); provider.openSelector().close(); } catch (Throwable e) { // not available provider = null; } } if (provider == null) { try { defaultProvider.openSelector().close(); provider = defaultProvider; } catch (Throwable e) { // not available } } if (provider == null) { try { // Nothing else works, not even the default provider = Class.forName("sun.nio.ch.PollSelectorProvider", true, NioXnio.class.getClassLoader()).asSubclass(SelectorProvider.class).getConstructor().newInstance(); provider.openSelector().close(); } catch (Throwable e) { // not available provider = null; } } if (provider == null) { throw log.noSelectorProvider(); } log.selectorProvider(provider); final boolean defaultIsPoll = "sun.nio.ch.PollSelectorProvider".equals(provider.getClass().getName()); final String chosenMainSelector = System.getProperty("xnio.nio.selector.main"); final String chosenTempSelector = System.getProperty("xnio.nio.selector.temp"); final SelectorCreator defaultSelectorCreator = new DefaultSelectorCreator(provider); final Object[] objects = new Object[3]; objects[0] = provider; if (chosenTempSelector != null) try { final ConstructorSelectorCreator creator = new ConstructorSelectorCreator(chosenTempSelector, provider); IoUtils.safeClose(creator.open()); objects[1] = creator; } catch (Exception e) { // not available } if (chosenMainSelector != null) try { final ConstructorSelectorCreator creator = new ConstructorSelectorCreator(chosenMainSelector, provider); IoUtils.safeClose(creator.open()); objects[2] = creator; } catch (Exception e) { // not available } if (! defaultIsPoll) { // default is fine for main selectors; we should try to get poll for temp though if (objects[1] == null) try { final ConstructorSelectorCreator creator = new ConstructorSelectorCreator("sun.nio.ch.PollSelectorImpl", provider); IoUtils.safeClose(creator.open()); objects[1] = creator; } catch (Exception e) { // not available } } if (objects[1] == null) { objects[1] = defaultSelectorCreator; } if (objects[2] == null) { objects[2] = defaultSelectorCreator; } return objects; } } ); tempSelectorCreator = (SelectorCreator) objects[1]; mainSelectorCreator = (SelectorCreator) objects[2]; log.selectors(mainSelectorCreator, tempSelectorCreator); register(new XnioProviderMXBean() { public String getName() { return "nio"; } public String getVersion() { return Version.getVersionString(); } }); } public XnioWorker createWorker(final ThreadGroup threadGroup, final OptionMap optionMap, final Runnable terminationTask) throws IOException, IllegalArgumentException { final NioXnioWorker worker = new NioXnioWorker(this, threadGroup, optionMap, terminationTask); worker.start(); return worker; } @Override public FileSystemWatcher createFileSystemWatcher(String name, OptionMap options) { try { boolean daemonThread = options.get(Options.THREAD_DAEMON, true); return new WatchServiceFileSystemWatcher(name, daemonThread); } catch (LinkageError e) { //ignore } return super.createFileSystemWatcher(name, options); } private final ThreadLocal selectorThreadLocal = new ThreadLocal() { public void remove() { // if no selector was created, none will be closed IoUtils.safeClose(get()); super.remove(); } }; Selector getSelector() throws IOException { final ThreadLocal threadLocal = selectorThreadLocal; Selector selector = threadLocal.get(); if (selector == null) { selector = tempSelectorCreator.open(); threadLocal.set(selector); } return selector; } private static class DefaultSelectorCreator implements SelectorCreator { private final SelectorProvider provider; private DefaultSelectorCreator(final SelectorProvider provider) { this.provider = provider; } public Selector open() throws IOException { return provider.openSelector(); } public String toString() { return "Default system selector creator for provider " + provider.getClass(); } } private static class ConstructorSelectorCreator implements SelectorCreator { private final Constructor constructor; private final SelectorProvider provider; public ConstructorSelectorCreator(final String name, final SelectorProvider provider) throws ClassNotFoundException, NoSuchMethodException { this.provider = provider; final Class selectorImplClass = Class.forName(name, true, null).asSubclass(Selector.class); final Constructor constructor = selectorImplClass.getDeclaredConstructor(SelectorProvider.class); constructor.setAccessible(true); this.constructor = constructor; } public Selector open() throws IOException { try { return constructor.newInstance(provider); } catch (InstantiationException e) { return Selector.open(); } catch (IllegalAccessException e) { return Selector.open(); } catch (InvocationTargetException e) { try { throw e.getTargetException(); } catch (IOException | Error | RuntimeException e2) { throw e2; } catch (Throwable t) { throw log.unexpectedSelectorOpenProblem(t); } } } public String toString() { return String.format("Selector creator %s for provider %s", constructor.getDeclaringClass(), provider.getClass()); } } protected static Closeable register(XnioWorkerMXBean workerMXBean) { return Xnio.register(workerMXBean); } protected static Closeable register(XnioServerMXBean serverMXBean) { return Xnio.register(serverMXBean); } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/NioXnioProvider.java000066400000000000000000000022541257016060700262050ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio; import org.xnio.Xnio; import org.xnio.XnioProvider; /** * The NIO XNIO provider. * * @author David M. Lloyd */ public final class NioXnioProvider implements XnioProvider { private static final Xnio INSTANCE = new NioXnio(); /** {@inheritDoc} */ public Xnio getInstance() { return INSTANCE; } /** {@inheritDoc} */ public String getName() { return INSTANCE.getName(); } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/NioXnioWorker.java000066400000000000000000000321301257016060700256600ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio; import java.io.Closeable; import java.io.IOException; import java.net.Inet6Address; import java.net.InetAddress; import java.net.InetSocketAddress; import java.net.StandardProtocolFamily; import java.nio.channels.DatagramChannel; import java.nio.channels.ServerSocketChannel; import java.util.List; import java.util.Random; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicReferenceFieldUpdater; import java.util.concurrent.locks.LockSupport; import org.xnio.Bits; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.ClosedWorkerException; import org.xnio.IoUtils; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.StreamConnection; import org.xnio.XnioWorker; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.MulticastMessageChannel; import org.xnio.management.XnioWorkerMXBean; import static org.xnio.IoUtils.safeClose; import static org.xnio.nio.Log.log; /** * @author David M. Lloyd */ final class NioXnioWorker extends XnioWorker { private static final int CLOSE_REQ = (1 << 31); private static final int CLOSE_COMP = (1 << 30); // start at 1 for the provided thread pool private volatile int state = 1; private final WorkerThread[] workerThreads; private final Closeable mbeanHandle; @SuppressWarnings("unused") private volatile Thread shutdownWaiter; private static final AtomicReferenceFieldUpdater shutdownWaiterUpdater = AtomicReferenceFieldUpdater.newUpdater(NioXnioWorker.class, Thread.class, "shutdownWaiter"); private static final AtomicIntegerFieldUpdater stateUpdater = AtomicIntegerFieldUpdater.newUpdater(NioXnioWorker.class, "state"); @SuppressWarnings("deprecation") NioXnioWorker(final NioXnio xnio, final ThreadGroup threadGroup, final OptionMap optionMap, final Runnable terminationTask) throws IOException { super(xnio, threadGroup, optionMap, terminationTask); final int threadCount; if (optionMap.contains(Options.WORKER_IO_THREADS)) { threadCount = optionMap.get(Options.WORKER_IO_THREADS, 0); } else { threadCount = Math.max(optionMap.get(Options.WORKER_READ_THREADS, 1), optionMap.get(Options.WORKER_WRITE_THREADS, 1)); } if (threadCount < 0) { throw log.optionOutOfRange("WORKER_IO_THREADS"); } final long workerStackSize = optionMap.get(Options.STACK_SIZE, 0L); if (workerStackSize < 0L) { throw log.optionOutOfRange("STACK_SIZE"); } final String workerName = getName(); WorkerThread[] workerThreads; workerThreads = new WorkerThread[threadCount]; final boolean markWorkerThreadAsDaemon = optionMap.get(Options.THREAD_DAEMON, false); boolean ok = false; try { for (int i = 0; i < threadCount; i++) { final WorkerThread workerThread = new WorkerThread(this, xnio.mainSelectorCreator.open(), String.format("%s I/O-%d", workerName, Integer.valueOf(i + 1)), threadGroup, workerStackSize, i); // Mark as daemon if the Options.THREAD_DAEMON has been set if (markWorkerThreadAsDaemon) { workerThread.setDaemon(true); } workerThreads[i] = workerThread; } ok = true; } finally { if (! ok) { for (WorkerThread worker : workerThreads) { if (worker != null) safeClose(worker.getSelector()); } } } this.workerThreads = workerThreads; mbeanHandle = NioXnio.register(new XnioWorkerMXBean() { public String getProviderName() { return "nio"; } public String getName() { return workerName; } public boolean isShutdownRequested() { return isShutdown(); } public int getCoreWorkerPoolSize() { return NioXnioWorker.this.getCoreWorkerPoolSize(); } public int getMaxWorkerPoolSize() { return NioXnioWorker.this.getMaxWorkerPoolSize(); } public int getIoThreadCount() { return threadCount; } public int getWorkerQueueSize() { return NioXnioWorker.this.getWorkerQueueSize(); } }); } void start() { for (WorkerThread worker : workerThreads) { openResourceUnconditionally(); worker.start(); } } protected WorkerThread chooseThread() { final WorkerThread[] workerThreads = this.workerThreads; final int length = workerThreads.length; if (length == 0) { throw log.noThreads(); } if (length == 1) { return workerThreads[0]; } final Random random = IoUtils.getThreadLocalRandom(); return workerThreads[random.nextInt(length)]; } public int getIoThreadCount() { return workerThreads.length; } WorkerThread[] getAll() { return workerThreads; } protected AcceptingChannel createTcpConnectionServer(final InetSocketAddress bindAddress, final ChannelListener> acceptListener, final OptionMap optionMap) throws IOException { checkShutdown(); boolean ok = false; final ServerSocketChannel channel = ServerSocketChannel.open(); try { if (optionMap.contains(Options.RECEIVE_BUFFER)) channel.socket().setReceiveBufferSize(optionMap.get(Options.RECEIVE_BUFFER, -1)); channel.socket().setReuseAddress(optionMap.get(Options.REUSE_ADDRESSES, true)); channel.configureBlocking(false); if (optionMap.contains(Options.BACKLOG)) { channel.socket().bind(bindAddress, optionMap.get(Options.BACKLOG, 128)); } else { channel.socket().bind(bindAddress); } final NioTcpServer server = new NioTcpServer(this, channel, optionMap); server.setAcceptListener(acceptListener); ok = true; return server; } finally { if (! ok) { IoUtils.safeClose(channel); } } } /** {@inheritDoc} */ public MulticastMessageChannel createUdpServer(final InetSocketAddress bindAddress, final ChannelListener bindListener, final OptionMap optionMap) throws IOException { checkShutdown(); final DatagramChannel channel; if (NioXnio.NIO2 && bindAddress != null) { InetAddress address = bindAddress.getAddress(); if (address instanceof Inet6Address) { channel = DatagramChannel.open(StandardProtocolFamily.INET6); } else { channel = DatagramChannel.open(StandardProtocolFamily.INET); } } else { channel = DatagramChannel.open(); } channel.configureBlocking(false); if (optionMap.contains(Options.BROADCAST)) channel.socket().setBroadcast(optionMap.get(Options.BROADCAST, false)); if (optionMap.contains(Options.IP_TRAFFIC_CLASS)) channel.socket().setTrafficClass(optionMap.get(Options.IP_TRAFFIC_CLASS, -1)); if (optionMap.contains(Options.RECEIVE_BUFFER)) channel.socket().setReceiveBufferSize(optionMap.get(Options.RECEIVE_BUFFER, -1)); channel.socket().setReuseAddress(optionMap.get(Options.REUSE_ADDRESSES, true)); if (optionMap.contains(Options.SEND_BUFFER)) channel.socket().setSendBufferSize(optionMap.get(Options.SEND_BUFFER, -1)); channel.socket().bind(bindAddress); final NioUdpChannel udpChannel = new NioUdpChannel(this, channel); ChannelListeners.invokeChannelListener(udpChannel, bindListener); return udpChannel; } public boolean isShutdown() { return (state & CLOSE_REQ) != 0; } public boolean isTerminated() { return (state & CLOSE_COMP) != 0; } /** * Open a resource unconditionally (i.e. accepting a connection on an open server). */ void openResourceUnconditionally() { int oldState = stateUpdater.getAndIncrement(this); if (log.isTraceEnabled()) { log.tracef("CAS %s %08x -> %08x", this, Integer.valueOf(oldState), Integer.valueOf(oldState + 1)); } } void checkShutdown() throws ClosedWorkerException { if (isShutdown()) throw log.workerShutDown(); } void closeResource() { int oldState = stateUpdater.decrementAndGet(this); if (log.isTraceEnabled()) { log.tracef("CAS %s %08x -> %08x", this, Integer.valueOf(oldState + 1), Integer.valueOf(oldState)); } while (oldState == CLOSE_REQ) { if (stateUpdater.compareAndSet(this, CLOSE_REQ, CLOSE_REQ | CLOSE_COMP)) { log.tracef("CAS %s %08x -> %08x (close complete)", this, Integer.valueOf(CLOSE_REQ), Integer.valueOf(CLOSE_REQ | CLOSE_COMP)); safeUnpark(shutdownWaiterUpdater.getAndSet(this, null)); final Runnable task = getTerminationTask(); if (task != null) try { task.run(); } catch (Throwable ignored) {} return; } oldState = state; } } public void shutdown() { int oldState; oldState = state; while ((oldState & CLOSE_REQ) == 0) { // need to do the close ourselves... if (! stateUpdater.compareAndSet(this, oldState, oldState | CLOSE_REQ)) { // changed in the meantime oldState = state; continue; } log.tracef("Initiating shutdown of %s", this); for (WorkerThread worker : workerThreads) { worker.shutdown(); } shutDownTaskPool(); return; } log.tracef("Idempotent shutdown of %s", this); return; } public List shutdownNow() { shutdown(); return shutDownTaskPoolNow(); } public boolean awaitTermination(final long timeout, final TimeUnit unit) throws InterruptedException { int oldState = state; if (Bits.allAreSet(oldState, CLOSE_COMP)) { return true; } long then = System.nanoTime(); long duration = unit.toNanos(timeout); final Thread myThread = Thread.currentThread(); while (Bits.allAreClear(oldState = state, CLOSE_COMP)) { final Thread oldThread = shutdownWaiterUpdater.getAndSet(this, myThread); try { if (Bits.allAreSet(oldState = state, CLOSE_COMP)) { break; } LockSupport.parkNanos(this, duration); if (Thread.interrupted()) { throw new InterruptedException(); } long now = System.nanoTime(); duration -= now - then; if (duration < 0L) { oldState = state; break; } } finally { safeUnpark(oldThread); } } return Bits.allAreSet(oldState, CLOSE_COMP); } public void awaitTermination() throws InterruptedException { int oldState = state; if (Bits.allAreSet(oldState, CLOSE_COMP)) { return; } final Thread myThread = Thread.currentThread(); while (Bits.allAreClear(state, CLOSE_COMP)) { final Thread oldThread = shutdownWaiterUpdater.getAndSet(this, myThread); try { if (Bits.allAreSet(state, CLOSE_COMP)) { break; } LockSupport.park(this); if (Thread.interrupted()) { throw new InterruptedException(); } } finally { safeUnpark(oldThread); } } } private static void safeUnpark(final Thread waiter) { if (waiter != null) LockSupport.unpark(waiter); } protected void taskPoolTerminated() { safeClose(mbeanHandle); closeResource(); } public NioXnio getXnio() { return (NioXnio) super.getXnio(); } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/SelectorUtils.java000066400000000000000000000050411257016060700257050ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio; import static org.xnio.nio.Log.log; import java.io.IOException; import java.io.InterruptedIOException; import java.nio.channels.ClosedChannelException; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.util.concurrent.TimeUnit; import org.xnio.Xnio; final class SelectorUtils { private SelectorUtils() { } public static void await(NioXnio nioXnio, SelectableChannel channel, int op) throws IOException { Xnio.checkBlockingAllowed(); final Selector selector = nioXnio.getSelector(); final SelectionKey selectionKey; try { selectionKey = channel.register(selector, op); } catch (ClosedChannelException e) { return; } selector.select(); selector.selectedKeys().clear(); if (Thread.currentThread().isInterrupted()) { throw log.interruptedIO(); } selectionKey.cancel(); selector.selectNow(); } public static void await(NioXnio nioXnio, SelectableChannel channel, int op, long time, TimeUnit unit) throws IOException { if (time <= 0) { await(nioXnio, channel, op); return; } Xnio.checkBlockingAllowed(); final Selector selector = nioXnio.getSelector(); final SelectionKey selectionKey; try { selectionKey = channel.register(selector, op); } catch (ClosedChannelException e) { return; } long timeoutInMillis = unit.toMillis(time); selector.select(timeoutInMillis == 0 ? 1: timeoutInMillis); selector.selectedKeys().clear(); if (Thread.currentThread().isInterrupted()) { throw log.interruptedIO(); } selectionKey.cancel(); selector.selectNow(); } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/Version.java000066400000000000000000000050601257016060700245320ustar00rootroot00000000000000 /* * JBoss, Home of Professional Open Source * * Copyright 2014 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio; import java.io.IOException; import java.io.InputStream; import java.io.InputStreamReader; import java.util.Properties; /** * The version class. * * @apiviz.exclude */ public final class Version { private Version() {} /** * Print out the current XNIO version on {@code System.out}. * * @param args ignored */ public static void main(String[] args) { System.out.print(VERSION_STRING); } private static final String JAR_NAME; private static final String VERSION_STRING; static { Properties versionProps = new Properties(); String jarName = "(unknown)"; String versionString = "(unknown)"; try { final InputStream stream = Version.class.getResourceAsStream("Version.properties"); try { final InputStreamReader reader = new InputStreamReader(stream); try { versionProps.load(reader); jarName = versionProps.getProperty("jarName", jarName); versionString = versionProps.getProperty("version", versionString); } finally { try { reader.close(); } catch (Throwable ignored) { } } } finally { try { stream.close(); } catch (Throwable ignored) { } } } catch (IOException ignored) { } JAR_NAME = jarName; VERSION_STRING = versionString; } /** * Get the name of the program JAR. * * @return the name */ public static String getJarName() { return JAR_NAME; } /** * Get the version string. * * @return the version string */ public static String getVersionString() { return VERSION_STRING; } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/WatchServiceFileSystemWatcher.java000066400000000000000000000242601257016060700310220ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio; import org.xnio.FileChangeCallback; import org.xnio.FileChangeEvent; import org.xnio.FileSystemWatcher; import org.xnio.IoUtils; import java.io.File; import java.io.IOException; import java.nio.file.ClosedWatchServiceException; import java.nio.file.FileSystems; import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardWatchEventKinds; import java.nio.file.WatchEvent; import java.nio.file.WatchKey; import java.nio.file.WatchService; import java.util.ArrayDeque; import java.util.ArrayList; import java.util.Collections; import java.util.Deque; import java.util.HashMap; import java.util.HashSet; import java.util.IdentityHashMap; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; import static java.nio.file.StandardWatchEventKinds.ENTRY_CREATE; import static java.nio.file.StandardWatchEventKinds.ENTRY_DELETE; import static java.nio.file.StandardWatchEventKinds.ENTRY_MODIFY; import static org.xnio.nio.Log.log; /** * File system watcher service based on JDK7 {@link WatchService}. Instantiating this class will create a new thread, * that will run until {@link #close()} is called. * * @author Stuart Douglas */ class WatchServiceFileSystemWatcher implements FileSystemWatcher, Runnable { private static final AtomicInteger threadIdCounter = new AtomicInteger(0); public static final String THREAD_NAME = "xnio-file-watcher"; private WatchService watchService; private final Map files = Collections.synchronizedMap(new HashMap()); private final Map pathDataByKey = Collections.synchronizedMap(new IdentityHashMap()); private volatile boolean stopped = false; private final Thread watchThread; WatchServiceFileSystemWatcher(final String name, final boolean daemon) { try { watchService = FileSystems.getDefault().newWatchService(); } catch (IOException e) { throw new RuntimeException(e); } watchThread = new Thread(this, THREAD_NAME + "[" + name + "]-" + threadIdCounter); watchThread.setDaemon(daemon); watchThread.start(); } @Override public void run() { while (!stopped) { try { final WatchKey key = watchService.take(); if (key != null) { try { PathData pathData = pathDataByKey.get(key); if (pathData != null) { final List results = new ArrayList(); List> events = key.pollEvents(); final Set addedFiles = new HashSet(); final Set deletedFiles = new HashSet(); for (WatchEvent event : events) { Path eventPath = (Path) event.context(); File targetFile = ((Path) key.watchable()).resolve(eventPath).toFile(); FileChangeEvent.Type type; if (event.kind() == StandardWatchEventKinds.ENTRY_CREATE) { type = FileChangeEvent.Type.ADDED; addedFiles.add(targetFile); if (targetFile.isDirectory()) { try { addWatchedDirectory(pathData, targetFile); } catch (IOException e) { log.debugf(e, "Could not add watched directory %s", targetFile); } } } else if (event.kind() == StandardWatchEventKinds.ENTRY_MODIFY) { type = FileChangeEvent.Type.MODIFIED; } else if (event.kind() == StandardWatchEventKinds.ENTRY_DELETE) { type = FileChangeEvent.Type.REMOVED; deletedFiles.add(targetFile); } else { continue; } results.add(new FileChangeEvent(targetFile, type)); } key.pollEvents().clear(); //now we need to prune the results, to remove duplicates //e.g. if the file is modified after creation we only want to //show the create event Iterator it = results.iterator(); while (it.hasNext()) { FileChangeEvent event = it.next(); if (event.getType() == FileChangeEvent.Type.MODIFIED) { if (addedFiles.contains(event.getFile()) || deletedFiles.contains(event.getFile())) { it.remove(); } } else if (event.getType() == FileChangeEvent.Type.ADDED) { if (deletedFiles.contains(event.getFile())) { it.remove(); } } else if (event.getType() == FileChangeEvent.Type.REMOVED) { if (addedFiles.contains(event.getFile())) { it.remove(); } } } if (!results.isEmpty()) { for (FileChangeCallback callback : pathData.callbacks) { invokeCallback(callback, results); } } } } finally { //if the key is no longer valid remove it from the files list if (!key.reset()) { files.remove(key.watchable()); } } } } catch (InterruptedException e) { //ignore } catch (ClosedWatchServiceException cwse) { // the watcher service is closed, so no more waiting on events // @see https://developer.jboss.org/message/911519 break; } } } @Override public synchronized void watchPath(File file, FileChangeCallback callback) { try { PathData data = files.get(file); if (data == null) { Set allDirectories = doScan(file).keySet(); Path path = Paths.get(file.toURI()); data = new PathData(path); for (File dir : allDirectories) { addWatchedDirectory(data, dir); } files.put(file, data); } data.callbacks.add(callback); } catch (IOException e) { throw new RuntimeException(e); } } private void addWatchedDirectory(PathData data, File dir) throws IOException { Path path = Paths.get(dir.toURI()); WatchKey key = path.register(watchService, ENTRY_CREATE, ENTRY_DELETE, ENTRY_MODIFY); pathDataByKey.put(key, data); data.keys.add(key); } @Override public synchronized void unwatchPath(File file, final FileChangeCallback callback) { PathData data = files.get(file); if (data != null) { data.callbacks.remove(callback); if (data.callbacks.isEmpty()) { files.remove(file); for (WatchKey key : data.keys) { key.cancel(); pathDataByKey.remove(key); } } } } @Override public void close() throws IOException { this.stopped = true; watchThread.interrupt(); IoUtils.safeClose(watchService); } private static Map doScan(File file) { final Map results = new HashMap(); final Deque toScan = new ArrayDeque(); toScan.add(file); while (!toScan.isEmpty()) { File next = toScan.pop(); if (next.isDirectory()) { results.put(next, next.lastModified()); File[] list = next.listFiles(); if (list != null) { for (File f : list) { toScan.push(new File(f.getAbsolutePath())); } } } } return results; } private static void invokeCallback(FileChangeCallback callback, List results) { try { callback.handleChanges(results); } catch (Exception e) { log.failedToInvokeFileWatchCallback(e); } } private class PathData { final Path path; final List callbacks = new ArrayList(); final List keys = new ArrayList(); private PathData(Path path) { this.path = path; } } } xnio-3.3.2.Final/nio-impl/src/main/java/org/xnio/nio/WorkerThread.java000066400000000000000000001045071257016060700255140ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio; import java.io.IOException; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.channels.CancelledKeyException; import java.nio.channels.ClosedChannelException; import java.nio.channels.Pipe; import java.nio.channels.SelectableChannel; import java.nio.channels.SelectionKey; import java.nio.channels.Selector; import java.nio.channels.ServerSocketChannel; import java.nio.channels.SocketChannel; import java.nio.channels.spi.AbstractSelectableChannel; import java.security.AccessController; import java.util.ArrayDeque; import java.util.Arrays; import java.util.Iterator; import java.util.Queue; import java.util.Set; import java.util.TreeSet; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicIntegerFieldUpdater; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.atomic.AtomicReference; import org.jboss.logging.Logger; import org.xnio.Cancellable; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.ChannelPipe; import org.xnio.ClosedWorkerException; import org.xnio.FailedIoFuture; import org.xnio.FinishedIoFuture; import org.xnio.FutureResult; import org.xnio.IoFuture; import org.xnio.Option; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.ReadPropertyAction; import org.xnio.StreamConnection; import org.xnio.XnioExecutor; import org.xnio.XnioIoFactory; import org.xnio.XnioIoThread; import org.xnio.XnioWorker; import org.xnio.channels.BoundChannel; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; import static java.lang.System.identityHashCode; import static java.lang.System.nanoTime; import static java.util.concurrent.locks.LockSupport.park; import static java.util.concurrent.locks.LockSupport.unpark; import static org.xnio.IoUtils.safeClose; import static org.xnio.nio.Log.log; import static org.xnio.nio.Log.selectorLog; /** * @author David M. Lloyd */ final class WorkerThread extends XnioIoThread implements XnioExecutor { private static final long LONGEST_DELAY = 9223372036853L; private static final String FQCN = WorkerThread.class.getName(); private static final boolean OLD_LOCKING; private static final boolean THREAD_SAFE_SELECTION_KEYS; private static final long START_TIME = System.nanoTime(); private final Selector selector; private final Object workLock = new Object(); private final Queue selectorWorkQueue = new ArrayDeque(); private final TreeSet delayWorkQueue = new TreeSet(); private volatile int state; private static final int SHUTDOWN = (1 << 31); private static final AtomicIntegerFieldUpdater stateUpdater = AtomicIntegerFieldUpdater.newUpdater(WorkerThread.class, "state"); static { OLD_LOCKING = Boolean.parseBoolean(AccessController.doPrivileged(new ReadPropertyAction("xnio.nio.old-locking", "false"))); THREAD_SAFE_SELECTION_KEYS = Boolean.parseBoolean(AccessController.doPrivileged(new ReadPropertyAction("xnio.xnio.thread-safe-selection-keys", "false"))); } WorkerThread(final NioXnioWorker worker, final Selector selector, final String name, final ThreadGroup group, final long stackSize, final int number) { super(worker, number, group, name, stackSize); this.selector = selector; } static WorkerThread getCurrent() { final Thread thread = currentThread(); return thread instanceof WorkerThread ? (WorkerThread) thread : null; } public NioXnioWorker getWorker() { return (NioXnioWorker) super.getWorker(); } protected IoFuture acceptTcpStreamConnection(final InetSocketAddress destination, final ChannelListener openListener, final ChannelListener bindListener, final OptionMap optionMap) { try { getWorker().checkShutdown(); } catch (ClosedWorkerException e) { return new FailedIoFuture(e); } final FutureResult futureResult = new FutureResult(this); try { boolean ok = false; final ServerSocketChannel serverChannel = ServerSocketChannel.open(); try { serverChannel.configureBlocking(false); if (optionMap.contains(Options.RECEIVE_BUFFER)) { serverChannel.socket().setReceiveBufferSize(optionMap.get(Options.RECEIVE_BUFFER, -1)); } serverChannel.socket().setReuseAddress(optionMap.get(Options.REUSE_ADDRESSES, true)); serverChannel.bind(destination); if (bindListener != null) ChannelListeners.invokeChannelListener(new BoundChannel() { public SocketAddress getLocalAddress() { return serverChannel.socket().getLocalSocketAddress(); } public A getLocalAddress(final Class type) { final SocketAddress address = getLocalAddress(); return type.isInstance(address) ? type.cast(address) : null; } public ChannelListener.Setter getCloseSetter() { return new ChannelListener.SimpleSetter(); } public XnioWorker getWorker() { return WorkerThread.this.getWorker(); } public XnioIoThread getIoThread() { return WorkerThread.this; } public void close() throws IOException { serverChannel.close(); } public boolean isOpen() { return serverChannel.isOpen(); } public boolean supportsOption(final Option option) { return false; } public T getOption(final Option option) throws IOException { return null; } public T setOption(final Option option, final T value) throws IllegalArgumentException, IOException { return null; } }, bindListener); final SelectionKey key = this.registerChannel(serverChannel); final NioHandle handle = new NioHandle(this, key) { void handleReady(final int ops) { boolean ok = false; try { final SocketChannel channel = serverChannel.accept(); if (channel == null) { ok = true; return; } else { safeClose(serverChannel); } try { channel.configureBlocking(false); if (optionMap.contains(Options.TCP_OOB_INLINE)) channel.socket().setOOBInline(optionMap.get(Options.TCP_OOB_INLINE, false)); if (optionMap.contains(Options.TCP_NODELAY)) channel.socket().setTcpNoDelay(optionMap.get(Options.TCP_NODELAY, false)); if (optionMap.contains(Options.IP_TRAFFIC_CLASS)) channel.socket().setTrafficClass(optionMap.get(Options.IP_TRAFFIC_CLASS, -1)); if (optionMap.contains(Options.CLOSE_ABORT)) channel.socket().setSoLinger(optionMap.get(Options.CLOSE_ABORT, false), 0); if (optionMap.contains(Options.KEEP_ALIVE)) channel.socket().setKeepAlive(optionMap.get(Options.KEEP_ALIVE, false)); if (optionMap.contains(Options.SEND_BUFFER)) channel.socket().setSendBufferSize(optionMap.get(Options.SEND_BUFFER, -1)); final SelectionKey selectionKey = WorkerThread.this.registerChannel(channel); final NioSocketStreamConnection connection = new NioSocketStreamConnection(WorkerThread.this, selectionKey, null); if (futureResult.setResult(connection)) { ok = true; ChannelListeners.invokeChannelListener(connection, openListener); } } finally { if (! ok) safeClose(channel); } } catch (IOException e) { futureResult.setException(e); } finally { if (! ok) { safeClose(serverChannel); } } } void terminated() { } void forceTermination() { futureResult.setCancelled(); } }; key.attach(handle); handle.resume(SelectionKey.OP_ACCEPT); ok = true; futureResult.addCancelHandler(new Cancellable() { public Cancellable cancel() { if (futureResult.setCancelled()) { safeClose(serverChannel); } return this; } }); return futureResult.getIoFuture(); } finally { if (! ok) safeClose(serverChannel); } } catch (IOException e) { return new FailedIoFuture(e); } } protected IoFuture openTcpStreamConnection(final InetSocketAddress bindAddress, final InetSocketAddress destinationAddress, final ChannelListener openListener, final ChannelListener bindListener, final OptionMap optionMap) { try { getWorker().checkShutdown(); } catch (ClosedWorkerException e) { return new FailedIoFuture(e); } try { final SocketChannel channel = SocketChannel.open(); boolean ok = false; try { channel.configureBlocking(false); if (optionMap.contains(Options.TCP_OOB_INLINE)) channel.socket().setOOBInline(optionMap.get(Options.TCP_OOB_INLINE, false)); if (optionMap.contains(Options.TCP_NODELAY)) channel.socket().setTcpNoDelay(optionMap.get(Options.TCP_NODELAY, false)); if (optionMap.contains(Options.IP_TRAFFIC_CLASS)) channel.socket().setTrafficClass(optionMap.get(Options.IP_TRAFFIC_CLASS, -1)); if (optionMap.contains(Options.CLOSE_ABORT)) channel.socket().setSoLinger(optionMap.get(Options.CLOSE_ABORT, false), 0); if (optionMap.contains(Options.KEEP_ALIVE)) channel.socket().setKeepAlive(optionMap.get(Options.KEEP_ALIVE, false)); if (optionMap.contains(Options.RECEIVE_BUFFER)) channel.socket().setReceiveBufferSize(optionMap.get(Options.RECEIVE_BUFFER, -1)); if (optionMap.contains(Options.REUSE_ADDRESSES)) channel.socket().setReuseAddress(optionMap.get(Options.REUSE_ADDRESSES, false)); if (optionMap.contains(Options.SEND_BUFFER)) channel.socket().setSendBufferSize(optionMap.get(Options.SEND_BUFFER, -1)); final SelectionKey key = registerChannel(channel); final NioSocketStreamConnection connection = new NioSocketStreamConnection(this, key, null); channel.socket().bind(bindAddress); ChannelListeners.invokeChannelListener(connection, bindListener); if (channel.connect(destinationAddress)) { execute(ChannelListeners.getChannelListenerTask(connection, openListener)); final FinishedIoFuture finishedIoFuture = new FinishedIoFuture(connection); ok = true; return finishedIoFuture; } final FutureResult futureResult = new FutureResult(this); final ConnectHandle connectHandle = new ConnectHandle(this, key, futureResult, connection, openListener); key.attach(connectHandle); futureResult.addCancelHandler(new Cancellable() { public Cancellable cancel() { if (futureResult.setCancelled()) { safeClose(connection); } return this; } }); connectHandle.resume(SelectionKey.OP_CONNECT); ok = true; return futureResult.getIoFuture(); } finally { if (! ok) safeClose(channel); } } catch (IOException e) { return new FailedIoFuture(e); } } WorkerThread getNextThread() { final WorkerThread[] all = getWorker().getAll(); final int number = getNumber(); if (number == all.length - 1) { return all[0]; } else { return all[number + 1]; } } static final class ConnectHandle extends NioHandle { private final FutureResult futureResult; private final NioSocketStreamConnection connection; private final ChannelListener openListener; ConnectHandle(final WorkerThread workerThread, final SelectionKey selectionKey, final FutureResult futureResult, final NioSocketStreamConnection connection, final ChannelListener openListener) { super(workerThread, selectionKey); this.futureResult = futureResult; this.connection = connection; this.openListener = openListener; } void handleReady(final int ops) { final SocketChannel channel = getChannel(); boolean ok = false; try { if (channel.finishConnect()) { suspend(SelectionKey.OP_CONNECT); getSelectionKey().attach(connection.getConduit()); if (futureResult.setResult(connection)) { ok = true; ChannelListeners.invokeChannelListener(connection, openListener); } } } catch (IOException e) { futureResult.setException(e); } finally { if (! ok) safeClose(connection); } } private SocketChannel getChannel() { return (SocketChannel) getSelectionKey().channel(); } void forceTermination() { futureResult.setCancelled(); safeClose(getChannel()); } void terminated() { } } private static WorkerThread getPeerThread(final XnioIoFactory peer) throws ClosedWorkerException { final WorkerThread peerThread; if (peer instanceof NioXnioWorker) { final NioXnioWorker peerWorker = (NioXnioWorker) peer; peerWorker.checkShutdown(); peerThread = peerWorker.chooseThread(); } else if (peer instanceof WorkerThread) { peerThread = (WorkerThread) peer; peerThread.getWorker().checkShutdown(); } else { throw log.notNioProvider(); } return peerThread; } public ChannelPipe createFullDuplexPipeConnection(XnioIoFactory peer) throws IOException { getWorker().checkShutdown(); boolean ok = false; final Pipe topPipe = Pipe.open(); try { topPipe.source().configureBlocking(false); topPipe.sink().configureBlocking(false); final Pipe bottomPipe = Pipe.open(); try { bottomPipe.source().configureBlocking(false); bottomPipe.sink().configureBlocking(false); final WorkerThread peerThread = getPeerThread(peer); final SelectionKey topSourceKey = registerChannel(topPipe.source()); final SelectionKey topSinkKey = peerThread.registerChannel(topPipe.sink()); final SelectionKey bottomSourceKey = peerThread.registerChannel(bottomPipe.source()); final SelectionKey bottomSinkKey = registerChannel(bottomPipe.sink()); final NioPipeStreamConnection leftConnection = new NioPipeStreamConnection(this, bottomSourceKey, topSinkKey); final NioPipeStreamConnection rightConnection = new NioPipeStreamConnection(this, topSourceKey, bottomSinkKey); final ChannelPipe result = new ChannelPipe(leftConnection, rightConnection); ok = true; return result; } finally { if (! ok) { safeClose(bottomPipe.sink()); safeClose(bottomPipe.source()); } } } finally { if (! ok) { safeClose(topPipe.sink()); safeClose(topPipe.source()); } } } public ChannelPipe createHalfDuplexPipe(final XnioIoFactory peer) throws IOException { getWorker().checkShutdown(); final Pipe pipe = Pipe.open(); boolean ok = false; try { pipe.source().configureBlocking(false); pipe.sink().configureBlocking(false); final WorkerThread peerThread = getPeerThread(peer); final SelectionKey readKey = registerChannel(pipe.source()); final SelectionKey writeKey = peerThread.registerChannel(pipe.sink()); final NioPipeStreamConnection leftConnection = new NioPipeStreamConnection(this, readKey, null); final NioPipeStreamConnection rightConnection = new NioPipeStreamConnection(this, null, writeKey); leftConnection.writeClosed(); rightConnection.readClosed(); final ChannelPipe result = new ChannelPipe(leftConnection.getSourceChannel(), rightConnection.getSinkChannel()); ok = true; return result; } finally { if (! ok) { safeClose(pipe.sink()); safeClose(pipe.source()); } } } public void run() { final Selector selector = this.selector; try { log.tracef("Starting worker thread %s", this); final Object lock = workLock; final Queue workQueue = selectorWorkQueue; final TreeSet delayQueue = delayWorkQueue; log.debugf("Started channel thread '%s', selector %s", currentThread().getName(), selector); Runnable task; Iterator iterator; long delayTime = Long.MAX_VALUE; Set selectedKeys; SelectionKey[] keys = new SelectionKey[16]; int oldState; int keyCount; for (;;) { // Run all tasks do { synchronized (lock) { task = workQueue.poll(); if (task == null) { iterator = delayQueue.iterator(); delayTime = Long.MAX_VALUE; if (iterator.hasNext()) { final long now = nanoTime(); do { final TimeKey key = iterator.next(); if (key.deadline <= (now - START_TIME)) { workQueue.add(key.command); iterator.remove(); } else { delayTime = key.deadline - (now - START_TIME); // the rest are in the future break; } } while (iterator.hasNext()); } task = workQueue.poll(); } } safeRun(task); } while (task != null); // all tasks have been run oldState = state; if ((oldState & SHUTDOWN) != 0) { synchronized (lock) { keyCount = selector.keys().size(); state = keyCount | SHUTDOWN; if (keyCount == 0 && workQueue.isEmpty()) { // no keys or tasks left, shut down (delay tasks are discarded) return; } } synchronized (selector) { final Set keySet = selector.keys(); synchronized (keySet) { keys = keySet.toArray(keys); Arrays.fill(keys, keySet.size(), keys.length, null); } } // shut em down for (int i = 0; i < keys.length; i++) { final SelectionKey key = keys[i]; if (key == null) break; //end of list keys[i] = null; final NioHandle attachment = (NioHandle) key.attachment(); if (attachment != null) { safeClose(key.channel()); attachment.forceTermination(); } } Arrays.fill(keys, 0, keys.length, null); } // perform select try { if ((oldState & SHUTDOWN) != 0) { selectorLog.tracef("Beginning select on %s (shutdown in progress)", selector); selector.selectNow(); } else if (delayTime == Long.MAX_VALUE) { selectorLog.tracef("Beginning select on %s", selector); selector.select(); } else { final long millis = 1L + delayTime / 1000000L; selectorLog.tracef("Beginning select on %s (with timeout)", selector); selector.select(millis); } } catch (CancelledKeyException ignored) { // Mac and other buggy implementations sometimes spits these out selectorLog.trace("Spurious cancelled key exception"); } catch (IOException e) { selectorLog.selectionError(e); // hopefully transient; should never happen } selectorLog.tracef("Selected on %s", selector); // iterate the ready key set synchronized (selector) { selectedKeys = selector.selectedKeys(); synchronized (selectedKeys) { // copy so that handlers can safely cancel keys keys = selectedKeys.toArray(keys); Arrays.fill(keys, selectedKeys.size(), keys.length, null); selectedKeys.clear(); } } for (int i = 0; i < keys.length; i++) { final SelectionKey key = keys[i]; if (key == null) break; //end of list keys[i] = null; final int ops; try { ops = key.interestOps(); if (ops != 0) { selectorLog.tracef("Selected key %s for %s", key, key.channel()); final NioHandle handle = (NioHandle) key.attachment(); if (handle == null) { cancelKey(key); } else { handle.handleReady(key.readyOps()); } } } catch (CancelledKeyException ignored) { selectorLog.tracef("Skipping selection of cancelled key %s", key); } catch (Throwable t) { selectorLog.tracef(t, "Unexpected failure of selection of key %s", key); } } // all selected keys invoked; loop back to run tasks } } finally { log.tracef("Shutting down channel thread \"%s\"", this); safeClose(selector); getWorker().closeResource(); } } private static void safeRun(final Runnable command) { if (command != null) try { log.tracef("Running task %s", command); command.run(); } catch (Throwable t) { log.taskFailed(command, t); } } public void execute(final Runnable command) { if ((state & SHUTDOWN) != 0) { throw log.threadExiting(); } synchronized (workLock) { selectorWorkQueue.add(command); } if(currentThread() != this) { selector.wakeup(); } } void shutdown() { int oldState; do { oldState = state; if ((oldState & SHUTDOWN) != 0) { // idempotent return; } } while (! stateUpdater.compareAndSet(this, oldState, oldState | SHUTDOWN)); if(currentThread() != this) { selector.wakeup(); } } public Key executeAfter(final Runnable command, final long time, final TimeUnit unit) { final long millis = unit.toMillis(time); if ((state & SHUTDOWN) != 0) { throw log.threadExiting(); } if (millis <= 0) { execute(command); return Key.IMMEDIATE; } final long deadline = (nanoTime() - START_TIME) + Math.min(millis, LONGEST_DELAY) * 1000000L; final TimeKey key = new TimeKey(deadline, command); synchronized (workLock) { final TreeSet queue = delayWorkQueue; queue.add(key); if (queue.iterator().next() == key) { // we're the next one up; poke the selector to update its delay time if(currentThread() != this) { selector.wakeup(); } } return key; } } class RepeatKey implements Key, Runnable { private final Runnable command; private final long millis; private final AtomicReference current = new AtomicReference<>(); RepeatKey(final Runnable command, final long millis) { this.command = command; this.millis = millis; } public boolean remove() { final Key removed = current.getAndSet(this); // removed key should not be null because remove cannot be called before it is populated. assert removed != null; return removed != this && removed.remove(); } void setFirst(Key key) { current.compareAndSet(null, key); } public void run() { try { command.run(); } finally { Key o, n; o = current.get(); if (o != this) { n = executeAfter(this, millis, TimeUnit.MILLISECONDS); if (!current.compareAndSet(o, n)) { n.remove(); } } } } } public Key executeAtInterval(final Runnable command, final long time, final TimeUnit unit) { final long millis = unit.toMillis(time); final RepeatKey repeatKey = new RepeatKey(command, millis); final Key firstKey = executeAfter(repeatKey, millis, TimeUnit.MILLISECONDS); repeatKey.setFirst(firstKey); return repeatKey; } SelectionKey registerChannel(final AbstractSelectableChannel channel) throws ClosedChannelException { if (currentThread() == this) { return channel.register(selector, 0); } else if (THREAD_SAFE_SELECTION_KEYS) { try { return channel.register(selector, 0); } finally { selector.wakeup(); } } else { final SynchTask task = new SynchTask(); queueTask(task); try { // Prevent selector from sleeping until we're done! selector.wakeup(); return channel.register(selector, 0); } finally { task.done(); } } } void queueTask(final Runnable task) { synchronized (workLock) { selectorWorkQueue.add(task); } } void cancelKey(final SelectionKey key) { assert key.selector() == selector; final SelectableChannel channel = key.channel(); if (currentThread() == this) { log.logf(FQCN, Logger.Level.TRACE, null, "Cancelling key %s of %s (same thread)", key, channel); try { key.cancel(); try { selector.selectNow(); } catch (IOException e) { log.selectionError(e); } } catch (Throwable t) { log.logf(FQCN, Logger.Level.TRACE, t, "Error cancelling key %s of %s (same thread)", key, channel); } } else if (OLD_LOCKING) { log.logf(FQCN, Logger.Level.TRACE, null, "Cancelling key %s of %s (same thread, old locking)", key, channel); final SynchTask task = new SynchTask(); queueTask(task); try { // Prevent selector from sleeping until we're done! selector.wakeup(); key.cancel(); } catch (Throwable t) { log.logf(FQCN, Logger.Level.TRACE, t, "Error cancelling key %s of %s (same thread, old locking)", key, channel); } finally { task.done(); } } else { log.logf(FQCN, Logger.Level.TRACE, null, "Cancelling key %s of %s (other thread)", key, channel); try { key.cancel(); selector.wakeup(); } catch (Throwable t) { log.logf(FQCN, Logger.Level.TRACE, t, "Error cancelling key %s of %s (other thread)", key, channel); } } } void setOps(final SelectionKey key, final int ops) { if (currentThread() == this) { try { key.interestOps(key.interestOps() | ops); } catch (CancelledKeyException ignored) {} } else if (OLD_LOCKING) { final SynchTask task = new SynchTask(); queueTask(task); try { // Prevent selector from sleeping until we're done! selector.wakeup(); key.interestOps(key.interestOps() | ops); } catch (CancelledKeyException ignored) { } finally { task.done(); } } else { try { key.interestOps(key.interestOps() | ops); selector.wakeup(); } catch (CancelledKeyException ignored) { } } } void clearOps(final SelectionKey key, final int ops) { if (currentThread() == this || ! OLD_LOCKING) { try { key.interestOps(key.interestOps() & ~ops); } catch (CancelledKeyException ignored) {} } else { final SynchTask task = new SynchTask(); queueTask(task); try { // Prevent selector from sleeping until we're done! selector.wakeup(); key.interestOps(key.interestOps() & ~ops); } catch (CancelledKeyException ignored) { } finally { task.done(); } } } Selector getSelector() { return selector; } public boolean equals(final Object obj) { return obj == this; } public int hashCode() { return identityHashCode(this); } static final AtomicLong seqGen = new AtomicLong(); final class TimeKey implements XnioExecutor.Key, Comparable { private final long deadline; private final long seq = seqGen.incrementAndGet(); private final Runnable command; TimeKey(final long deadline, final Runnable command) { this.deadline = deadline; this.command = command; } public boolean remove() { synchronized (workLock) { return delayWorkQueue.remove(this); } } public int compareTo(final TimeKey o) { int r = Long.signum(deadline - o.deadline); if (r == 0) r = Long.signum(seq - o.seq); return r; } } final class SynchTask implements Runnable { volatile boolean done; public void run() { while (! done) { park(); } } void done() { done = true; unpark(WorkerThread.this); } } } xnio-3.3.2.Final/nio-impl/src/main/resources/000077500000000000000000000000001257016060700210015ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/main/resources/META-INF/000077500000000000000000000000001257016060700221415ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/main/resources/META-INF/services/000077500000000000000000000000001257016060700237645ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/main/resources/META-INF/services/org.xnio.XnioProvider000066400000000000000000000013751257016060700301070ustar00rootroot00000000000000# # JBoss, Home of Professional Open Source. # Copyright 2012 Red Hat, Inc., and individual contributors # as indicated by the @author tags. # # 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. # # # This module defines the NIO XNIO provider org.xnio.nio.NioXnioProvider xnio-3.3.2.Final/nio-impl/src/main/resources/org/000077500000000000000000000000001257016060700215705ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/main/resources/org/xnio/000077500000000000000000000000001257016060700225455ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/main/resources/org/xnio/nio/000077500000000000000000000000001257016060700233325ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/main/resources/org/xnio/nio/Version.properties000066400000000000000000000000711257016060700270730ustar00rootroot00000000000000version=${project.version} jarName=${project.artifactId} xnio-3.3.2.Final/nio-impl/src/test/000077500000000000000000000000001257016060700170225ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/test/java/000077500000000000000000000000001257016060700177435ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/test/java/org/000077500000000000000000000000001257016060700205325ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/000077500000000000000000000000001257016060700215075ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/000077500000000000000000000000001257016060700222745ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/000077500000000000000000000000001257016060700232535ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/AbstractNioChannelPipeTest.java000066400000000000000000000504671257016060700313120ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.nio.channels.Channel; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import org.jboss.logging.Logger; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.ChannelPipe; import org.xnio.IoUtils; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.Xnio; import org.xnio.XnioWorker; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; /** * Abstract test class for {@link ChannelPipe} usage test. * * @author Flavia Rainone * */ public abstract class AbstractNioChannelPipeTest { private static final Logger log = Logger.getLogger("TEST"); protected final List problems = new CopyOnWriteArrayList(); protected AtomicBoolean leftChannelOK; protected AtomicBoolean rightChannelOK; /** * Create the pipe channel. * * @param worker the worker * @return the create pipe channel */ protected abstract ChannelPipe createPipeChannel(XnioWorker worker) throws IOException; @SuppressWarnings({ "unchecked", "rawtypes" }) protected void doConnectionTest(final Runnable body, final ChannelListener leftChannelHandler, final ChannelListener rightChannelHandler) throws Exception { final Xnio xnio = Xnio.getInstance("nio", NioFullDuplexChannelPipeTestCase.class.getClassLoader()); @SuppressWarnings("deprecation") final XnioWorker worker = xnio.createWorker(OptionMap.create(Options.WORKER_WRITE_THREADS, 2, Options.WORKER_READ_THREADS, 2)); try { final ChannelPipe channelPipe = createPipeChannel(worker); try { final Thread invokeLeftChannelHandler = new Thread(new ChannelListenerInvoker(leftChannelHandler, channelPipe.getLeftSide())); final Thread invokeRightChannelHandler = new Thread(new ChannelListenerInvoker(rightChannelHandler, channelPipe.getRightSide())); invokeLeftChannelHandler.start(); invokeRightChannelHandler.start(); invokeLeftChannelHandler.join(); invokeRightChannelHandler.join(); body.run(); channelPipe.getLeftSide().close(); channelPipe.getRightSide().close(); } catch (Exception e) { log.errorf(e, "Error running body"); throw e; } catch (Error e) { log.errorf(e, "Error running body"); throw e; }finally { IoUtils.safeClose(channelPipe.getLeftSide()); IoUtils.safeClose(channelPipe.getRightSide()); } } finally { worker.shutdown(); worker.awaitTermination(1L, TimeUnit.MINUTES); } } @Before public void setupTest() { problems.clear(); leftChannelOK = new AtomicBoolean(false); rightChannelOK = new AtomicBoolean(false); } @After public void checkProblems() { assertTrue(leftChannelOK.get()); assertTrue(rightChannelOK.get()); for (Throwable problem : problems) { log.error("Test exception", problem); } assertTrue(problems.isEmpty()); } @Test public void pipeCreation() throws Exception { log.info("Test: pipeCreation"); doConnectionTest(new Runnable() {public void run(){} }, null, ChannelListeners.closingChannelListener()); leftChannelOK.set(true); rightChannelOK.set(true); } @Test public void leftChannelClose() throws Exception { log.info("Test: leftChannelClose"); final CountDownLatch latch = new CountDownLatch(4); doConnectionTest(new LatchAwaiter(latch), new ChannelListener() { public void handleEvent(final S channel) { log.info("In pipe creation, leftChannel setup"); try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamSourceChannel channel) { log.info("In left channel close"); latch.countDown(); } }); channel.close(); leftChannelOK.set(true); latch.countDown(); } catch (Throwable t) { log.error("In left channel", t); latch.countDown(); throw new RuntimeException(t); } } }, new ChannelListener() { public void handleEvent(final T channel) { log.info("In pipe creation, rightChannel setup"); channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamSinkChannel channel) { log.info("In right channel close"); latch.countDown(); } }); channel.getWriteSetter().set(new ChannelListener() { public void handleEvent(final StreamSinkChannel channel) { log.info("In right channel readable"); try { channel.write(ByteBuffer.allocate(100)); } catch (IOException e) { rightChannelOK.set(true); IoUtils.safeClose(channel); } latch.countDown(); } }); channel.resumeWrites(); } }); } @Test public void rightChannelClose() throws Exception { log.info("Test: rightChannelClose"); final CountDownLatch latch = new CountDownLatch(2); doConnectionTest(new LatchAwaiter(latch), new ChannelListener() { public void handleEvent(final S channel) { try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamSourceChannel channel) { latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final StreamSourceChannel channel) { try { final int c = channel.read(ByteBuffer.allocate(100)); if (c == -1) { leftChannelOK.set(true); channel.close(); return; } // retry return; } catch (IOException e) { throw new RuntimeException(e); } } }); channel.resumeReads(); } catch (Throwable t) { try { channel.close(); } catch (Throwable t2) { log.errorf(t2, "Failed to close channel (propagating as RT exception)"); latch.countDown(); throw new RuntimeException(t); } throw new RuntimeException(t); } } }, new ChannelListener() { public void handleEvent(final T channel) { try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamSinkChannel channel) { rightChannelOK.set(true); latch.countDown(); } }); channel.close(); } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); latch.countDown(); throw new RuntimeException(t); } } }); } @Test public void oneWayTransfer() throws Exception { log.info("Test: oneWayTransfer"); final CountDownLatch latch = new CountDownLatch(2); final AtomicInteger leftChannelReceived = new AtomicInteger(0); final AtomicInteger rightChannelSent = new AtomicInteger(0); doConnectionTest(new LatchAwaiter(latch), new ChannelListener() { public void handleEvent(final S channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamSourceChannel channel) { latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final StreamSourceChannel channel) { try { int c; while ((c = channel.read(ByteBuffer.allocate(100))) > 0) { leftChannelReceived.addAndGet(c); } if (c == -1) { IoUtils.safeClose(channel); } } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }); final ByteBuffer buffer = ByteBuffer.allocate(100); try { buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } channel.resumeReads(); } }, new ChannelListener() { public void handleEvent(final T channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamSinkChannel channel) { latch.countDown(); } }); final ByteBuffer buffer = ByteBuffer.allocate(100); try { buffer.put("This Is A Test Gumma\r\n".getBytes("UTF-8")).flip(); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } channel.getWriteSetter().set(new ChannelListener() { public void handleEvent(final StreamSinkChannel channel) { try { int c; while ((c = channel.write(buffer)) > 0) { if (rightChannelSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final StreamSinkChannel channel) { try { IoUtils.safeClose(channel); } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } buffer.rewind(); } } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }); channel.resumeWrites(); } }); assertEquals(rightChannelSent.get(), leftChannelReceived.get()); leftChannelOK.set(true); rightChannelOK.set(true); } @Test public void leftSourceChannelNastyClose() throws Exception { log.info("Test: leftSourceChannelNastyClose"); final CountDownLatch latch = new CountDownLatch(2); doConnectionTest(new LatchAwaiter(latch), new ChannelListener() { public void handleEvent(final S channel) { try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamSourceChannel channel) { latch.countDown(); } }); channel.setOption(Options.CLOSE_ABORT, Boolean.TRUE); channel.close(); leftChannelOK.set(true); } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); latch.countDown(); throw new RuntimeException(t); } } }, new ChannelListener() { public void handleEvent(final T channel) { try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamSinkChannel channel) { latch.countDown(); } }); channel.getWriteSetter().set(new ChannelListener() { public void handleEvent(final StreamSinkChannel channel) { try { channel.write(ByteBuffer.allocate(100)); } catch (IOException e) { // broken pipe IoUtils.safeClose(channel); rightChannelOK.set(true); return; } } }); channel.resumeWrites(); } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); latch.countDown(); throw new RuntimeException(t); } } }); } @Test public void rightSinkChannelNastyClose() throws Exception { log.info("Test: rightSinkChannelNastyClose"); final CountDownLatch latch = new CountDownLatch(2); final CountDownLatch rightChannelLatch = new CountDownLatch(1); doConnectionTest(new LatchAwaiter(latch), new ChannelListener() { public void handleEvent(final S channel) { try { log.info("Left channel opened"); channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamSourceChannel channel) { latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final StreamSourceChannel channel) { int res; try { res = channel.read(ByteBuffer.allocate(100)); } catch (IOException e) { IoUtils.safeClose(channel); return; } if (res == -1) { leftChannelOK.set(true); IoUtils.safeClose(channel); } } }); channel.resumeReads(); rightChannelLatch.countDown(); } catch (Throwable t) { log.error("Error occurred on client", t); try { channel.close(); } catch (Throwable t2) { log.error("Error occurred on client (close)", t2); latch.countDown(); throw new RuntimeException(t); } throw new RuntimeException(t); } } }, new ChannelListener() { public void handleEvent(final T channel) { try { log.info("Right channel opened"); channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamSinkChannel channel) { latch.countDown(); } }); channel.getWriteSetter().set(new ChannelListener() { public void handleEvent(final StreamSinkChannel channel) { try { if (channel.write(ByteBuffer.allocate(1)) > 0) { IoUtils.safeClose(channel); rightChannelOK.set(true); } } catch (IOException e) { IoUtils.safeClose(channel); } } }); channel.resumeWrites(); } catch (Throwable t) { log.error("Error occurred on server", t); latch.countDown(); throw new RuntimeException(t); } } }); } private static class ChannelListenerInvoker implements Runnable { private final ChannelListener channelListener; private final T channel; public ChannelListenerInvoker(ChannelListener l, T c) { channelListener = l; channel = c; } public void run() { ChannelListeners.invokeChannelListener(channel, channelListener); } } protected static class LatchAwaiter implements Runnable { private final CountDownLatch latch; public LatchAwaiter(CountDownLatch l) { latch = l; } public void run() { try { assertTrue(latch.await(500L, TimeUnit.DAYS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/AbstractNioStreamChannelTest.java000066400000000000000000000263311257016060700316410ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.util.concurrent.TimeUnit; import org.junit.Ignore; import org.junit.Test; import org.xnio.Buffers; import org.xnio.OptionMap; import org.xnio.XnioWorker; import org.xnio.channels.StreamChannel; /** * Tests a pair of connected stream channels. * * @author Flavia Rainone */ public abstract class AbstractNioStreamChannelTest extends AbstractStreamSinkSourceChannelTest { private StreamChannel channel1 = null; private StreamChannel channel2 = null; @Override protected void initChannels(XnioWorker worker, OptionMap optionMap) throws IOException { super.initChannels(worker, optionMap); // for a matter of code readability, it is better to name those channels sink/source in the super class // and create new fields in this subclass so we can use a more appropriate name here channel1 = super.sinkChannel; channel2 = super.sourceChannel; } @Test public void readWrite() throws IOException{ initChannels(); final ByteBuffer writeBuffer = ByteBuffer.allocate(15); final ByteBuffer readBuffer = ByteBuffer.allocate(15); writeBuffer.put("read and write".getBytes()).flip(); assertEquals(0, channel1.read(readBuffer)); assertEquals(14, channel1.write(writeBuffer)); assertEquals(14, channel2.read(readBuffer)); assertEquals(0, channel2.write(writeBuffer)); assertEquals(0, channel2.read(readBuffer)); readBuffer.flip(); assertEquals("read and write", Buffers.getModifiedUtf8(readBuffer)); channel1.close(); assertEquals(-1, channel1.read(readBuffer)); writeBuffer.flip(); ClosedChannelException expected = null; try { channel1.write(writeBuffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); } @Test public void readWriteMultipleBuffers() throws IOException{ initChannels(); final ByteBuffer[] writeBuffers = new ByteBuffer[] {ByteBuffer.allocate(3), ByteBuffer.allocate(9), ByteBuffer.allocate(13), Buffers.EMPTY_BYTE_BUFFER}; final ByteBuffer[] readBuffers = new ByteBuffer[] {ByteBuffer.allocate(1), ByteBuffer.allocate(5), ByteBuffer.allocate(10), ByteBuffer.allocate(15), ByteBuffer.allocate(20)}; writeBuffers[0].put("> 1".getBytes()).flip(); writeBuffers[1].put("multiple".getBytes()).flip(); writeBuffers[2].put("more than one".getBytes()).flip(); assertEquals(0, channel1.read(readBuffers)); assertEquals(0, channel1.write(writeBuffers, 3, 1)); assertEquals(13, channel1.write(writeBuffers, 2, 2)); assertEquals(0, channel1.write(writeBuffers, 2, 2)); assertEquals(1, channel2.read(readBuffers, 0, 1)); assertEquals('m', readBuffers[0].get(0)); assertEquals(12, channel2.read(readBuffers)); assertEquals(0, channel2.read(readBuffers, 1, 2)); assertEquals(11, channel2.write(writeBuffers)); assertEquals(11, channel1.read(readBuffers, 3, 2)); readBuffers[1].flip(); readBuffers[2].flip(); readBuffers[3].flip(); readBuffers[4].flip(); assertEquals("ore t", Buffers.getModifiedUtf8(readBuffers[1])); assertEquals("han one", Buffers.getModifiedUtf8(readBuffers[2])); assertEquals("> 1multiple", Buffers.getModifiedUtf8(readBuffers[3])); assertEquals(0, readBuffers[4].remaining()); channel1.close(); assertEquals(-1, channel1.read(readBuffers)); writeBuffers[0].flip(); ClosedChannelException expected = null; try { channel1.write(writeBuffers); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); } @Test @Ignore("Does not follow thread model") public void suspendResumeReadsAndWrites() throws IOException, InterruptedException { initChannels(); assertFalse(channel1.isReadResumed()); assertFalse(channel1.isWriteResumed()); final TestChannelListener readListener = new TestChannelListener(); final TestChannelListener writeListener = new TestChannelListener(); channel1.getReadSetter().set(readListener); assertFalse(readListener.isInvokedYet()); channel1.getWriteSetter().set(writeListener); assertFalse(writeListener.isInvokedYet()); channel1.awaitWritable(); channel1.resumeReads(); int count = 0; while(!channel1.isReadResumed()) { Thread.sleep(50); if (++ count == 10) { fail("Read is not resumed"); } } assertTrue(channel1.isReadResumed()); assertFalse(channel1.isWriteResumed()); channel1.resumeWrites(); count = 0; assertTrue(writeListener.isInvoked()); assertTrue(channel1.isWriteResumed()); writeListener.clear(); assertTrue(channel1.isReadResumed()); channel1.suspendReads(); assertFalse(channel1.isReadResumed()); assertTrue(channel1.isWriteResumed()); channel1.suspendWrites(); assertFalse(channel1.isReadResumed()); assertFalse(channel1.isWriteResumed()); channel1.wakeupWrites(); assertTrue(writeListener.isInvoked()); assertFalse(readListener.isInvokedYet()); assertSame(channel1, writeListener.getChannel()); channel1.wakeupReads(); assertTrue(readListener.isInvoked()); assertSame(channel1, readListener.getChannel()); channel1.shutdownReads(); channel1.shutdownWrites(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } assertFalse(channel1.isOpen()); // idempotent operations channel1.shutdownReads(); channel1.shutdownWrites(); assertFalse(channel1.isOpen()); } @SuppressWarnings("deprecation") @Test public void awaitReadableAndWritable() throws IOException, InterruptedException { initChannels(); final TestChannelListener readListener1 = new TestChannelListener(); final TestChannelListener writeListener1 = new TestChannelListener(); final TestChannelListener readListener2 = new TestChannelListener(); final TestChannelListener writeListener2 = new TestChannelListener(); channel1.getReadSetter().set(readListener1); channel1.getWriteSetter().set(writeListener1); channel2.getReadSetter().set(readListener2); channel2.getWriteSetter().set(writeListener2); channel1.awaitWritable(); channel1.awaitWritable(1, TimeUnit.HOURS); channel2.awaitWritable(); channel2.awaitWritable(1, TimeUnit.HOURS); final ReadableAwaiter readableAwaiter1 = new ReadableAwaiter(channel1); final ReadableAwaiter readableAwaiter2 = new ReadableAwaiter(channel1, 10, TimeUnit.MICROSECONDS); final ReadableAwaiter readableAwaiter3 = new ReadableAwaiter(channel1, 10, TimeUnit.MINUTES); final WritableAwaiter writableAwaiter1 = new WritableAwaiter(channel1); final WritableAwaiter writableAwaiter2 = new WritableAwaiter(channel1, 5, TimeUnit.NANOSECONDS); final WritableAwaiter writableAwaiter3 = new WritableAwaiter(channel1, 2222222, TimeUnit.SECONDS); final Thread readableAwaiterThread1 = new Thread(readableAwaiter1); final Thread readableAwaiterThread2 = new Thread(readableAwaiter2); final Thread readableAwaiterThread3 = new Thread(readableAwaiter3); final Thread writableAwaiterThread1 = new Thread(writableAwaiter1); final Thread writableAwaiterThread2 = new Thread(writableAwaiter2); final Thread writableAwaiterThread3 = new Thread(writableAwaiter3); readableAwaiterThread1.start(); readableAwaiterThread2.start(); readableAwaiterThread3.start(); readableAwaiterThread1.join(50); readableAwaiterThread2.join(); readableAwaiterThread3.join(50); assertTrue(readableAwaiterThread1.isAlive()); assertTrue(readableAwaiterThread3.isAlive()); channel1.shutdownWrites(); writableAwaiterThread1.start(); writableAwaiterThread2.start(); writableAwaiterThread3.start(); writableAwaiterThread1.join(); writableAwaiterThread2.join(); writableAwaiterThread3.join(); final ByteBuffer buffer = ByteBuffer.allocate(5); buffer.put("12345".getBytes()).flip(); assertEquals(5, channel2.write(buffer)); readableAwaiterThread1.join(); readableAwaiterThread3.join(); channel1.resumeWrites(); writableAwaiterThread1.join(); writableAwaiterThread3.join(); assertNotNull(channel1.getWriteThread()); assertNotNull(channel1.getIoThread()); assertNotNull(channel2.getWriteThread()); assertNotNull(channel2.getIoThread()); } @Test public void awaitWritable() throws IOException, InterruptedException { initChannels(); final TestChannelListener readListener1 = new TestChannelListener(); final TestChannelListener writeListener1 = new TestChannelListener(); final TestChannelListener readListener2 = new TestChannelListener(); final TestChannelListener writeListener2 = new TestChannelListener(); channel1.getReadSetter().set(readListener1); channel1.getWriteSetter().set(writeListener1); channel2.getReadSetter().set(readListener2); channel2.getWriteSetter().set(writeListener2); channel1.shutdownWrites(); do { channel1.awaitWritable(); } while (! channel1.flush()); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/AbstractNioTcpTest.java000066400000000000000000001056071257016060700276470ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.Inet4Address; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.List; import java.util.concurrent.CopyOnWriteArrayList; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import org.jboss.logging.Logger; import org.junit.After; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; import org.xnio.ChannelListener; import org.xnio.ChannelListeners; import org.xnio.IoFuture; import org.xnio.IoUtils; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.Xnio; import org.xnio.XnioWorker; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.BoundChannel; import org.xnio.channels.ConnectedChannel; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; /** * Abstract test for TCP connected channels. * * @author David M. Lloyd * @author Flavia Rainone */ public abstract class AbstractNioTcpTest { protected static final Logger log = Logger.getLogger("TEST"); private final List problems = new CopyOnWriteArrayList(); protected static final int SERVER_PORT = 12345; private OptionMap serverOptionMap = OptionMap.create(Options.REUSE_ADDRESSES, Boolean.TRUE); // any random map private OptionMap clientOptionMap = OptionMap.EMPTY; private int threads = 1; protected abstract AcceptingChannel createServer(XnioWorker worker, InetSocketAddress address, ChannelListener> openListener, OptionMap optionMap) throws IOException; protected abstract IoFuture connect(XnioWorker worker, InetSocketAddress address, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap); protected abstract void setReadListener(T channel, ChannelListener readListener); protected abstract void setWriteListener(T channel, ChannelListener writeListener); protected abstract void resumeReads(T channel); protected abstract void resumeWrites(T channel); protected void doConnectionTest(final Runnable body, final ChannelListener clientHandler, final ChannelListener serverHandler) throws Exception { final Xnio xnio = Xnio.getInstance("nio", AbstractNioTcpTest.class.getClassLoader()); final XnioWorker worker; if (threads == 1) { worker = xnio.createWorker(OptionMap.create(Options.READ_TIMEOUT, 10000, Options.WRITE_TIMEOUT, 10000)); } else { worker = xnio.createWorker(OptionMap.create(Options.WORKER_IO_THREADS, threads)); } try { final AcceptingChannel server = createServer(worker, new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), SERVER_PORT), ChannelListeners.openListenerAdapter(new CatchingChannelListener( serverHandler, problems )), serverOptionMap); server.resumeAccepts(); try { final IoFuture ioFuture = connect(worker, new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), SERVER_PORT), new CatchingChannelListener(clientHandler, problems), null, clientOptionMap); final T channel = ioFuture.get(); try { body.run(); channel.close(); server.close(); } catch (Exception e) { log.errorf(e, "Error running body"); throw e; } catch (Error e) { log.errorf(e, "Error running body"); throw e; } finally { IoUtils.safeClose(channel); } } finally { IoUtils.safeClose(server); } } finally { worker.shutdown(); worker.awaitTermination(1L, TimeUnit.MINUTES); } } /** * Set the number of threads that will be used by this test. * * @param threads the number of threads. */ protected void setNumberOfThreads(int threads) { this.threads = threads; } /** * Set the option map used to create the server. * * @param serverOptionMap the option map that must be used to create server */ protected void setServerOptionMap(OptionMap serverOptionMap) { this.serverOptionMap = serverOptionMap; } /** * Set the option map used to connect to the server * * @param clientOptionMap the option map that must be used to connect to the server */ protected void setClientOptionMap(OptionMap clientOptionMap) { this.clientOptionMap = clientOptionMap; } @Before public void clearProblems() { problems.clear(); } @After public void checkProblems() { for (Throwable problem : problems) { log.error("Test exception", problem); } assertTrue(problems.isEmpty()); } @Test public void connect() throws Exception { log.info("Test: tcpConnect"); doConnectionTest(new Runnable() { public void run() { } }, null, ChannelListeners.closingChannelListener()); } @Test public void clientClose() throws Exception { log.info("Test: clientClose"); final CountDownLatch latch = new CountDownLatch(4); final AtomicBoolean clientOK = new AtomicBoolean(false); final AtomicBoolean serverOK = new AtomicBoolean(false); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final T channel) { log.info("In client open"); try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedChannel channel) { log.info("In client close"); latch.countDown(); } }); channel.close(); clientOK.set(true); latch.countDown(); } catch (Throwable t) { log.error("In client", t); latch.countDown(); throw new RuntimeException(t); } } }, new ChannelListener() { public void handleEvent(final T channel) { log.info("In server opened"); channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedChannel channel) { log.info("In server close"); latch.countDown(); } }); setReadListener(channel, new ChannelListener() { public void handleEvent(final R sourceChannel) { log.info("In server readable"); try { final int c = sourceChannel.read(ByteBuffer.allocate(100)); if (c == -1) { serverOK.set(true); } channel.close(); } catch (IOException e) { throw new RuntimeException(e); } latch.countDown(); } }); resumeReads(channel); } }); assertTrue(serverOK.get()); assertTrue(clientOK.get()); } @Test public void serverClose() throws Exception { log.info("Test: serverClose"); final CountDownLatch latch = new CountDownLatch(2); final AtomicBoolean clientOK = new AtomicBoolean(false); final AtomicBoolean serverOK = new AtomicBoolean(false); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final T channel) { try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedChannel channel) { latch.countDown(); } }); setReadListener(channel, new ChannelListener() { public void handleEvent(final R sourceChannel) { try { final int c = sourceChannel.read(ByteBuffer.allocate(100)); if (c == -1) { clientOK.set(true); channel.close(); return; } // retry return; } catch (IOException e) { throw new RuntimeException(e); } } }); resumeReads(channel); } catch (Throwable t) { try { channel.close(); } catch (Throwable t2) { log.errorf(t2, "Failed to close channel (propagating as RT exception)"); latch.countDown(); throw new RuntimeException(t); } throw new RuntimeException(t); } } }, new ChannelListener() { public void handleEvent(final T channel) { try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedChannel channel) { serverOK.set(true); latch.countDown(); } }); channel.close(); } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); latch.countDown(); throw new RuntimeException(t); } } }); assertTrue(serverOK.get()); assertTrue(clientOK.get()); } @Test public void oneWayTransfer1() throws Exception { log.info("Test: oneWayTransfer1"); final CountDownLatch latch = new CountDownLatch(2); final AtomicInteger clientSent = new AtomicInteger(0); final AtomicInteger serverReceived = new AtomicInteger(0); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final T channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedChannel channel) { latch.countDown(); } }); final ByteBuffer buffer = ByteBuffer.allocate(100); try { buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } setWriteListener(channel, new ChannelListener() { public void handleEvent(final W sinkChannel) { try { int c; while ((c = sinkChannel.write(buffer)) > 0) { if (clientSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final StreamSinkChannel sinkChannel) { try { sinkChannel.shutdownWrites(); channel.close(); } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }; sinkChannel.getWriteSetter().set(listener); listener.handleEvent(sinkChannel); return; } buffer.rewind(); } } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }); resumeWrites(channel); } }, new ChannelListener() { public void handleEvent(final T channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedChannel channel) { latch.countDown(); } }); setReadListener(channel, new ChannelListener() { public void handleEvent(final R sourceChannel) { try { int c; while ((c = sourceChannel.read(ByteBuffer.allocate(100))) > 0) { serverReceived.addAndGet(c); } if (c == -1) { sourceChannel.shutdownReads(); channel.close(); } } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }); resumeReads(channel); } }); assertEquals(clientSent.get(), serverReceived.get()); } @Test public void oneWayTransfer2() throws Exception { log.info("Test: oneWayTransfer2"); final CountDownLatch latch = new CountDownLatch(2); final AtomicInteger clientReceived = new AtomicInteger(0); final AtomicInteger serverSent = new AtomicInteger(0); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final T channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedChannel channel) { latch.countDown(); } }); setReadListener(channel, new ChannelListener() { public void handleEvent(final R sourceChannel) { try { int c; while ((c = sourceChannel.read(ByteBuffer.allocate(100))) > 0) { clientReceived.addAndGet(c); } if (c == -1) { sourceChannel.shutdownReads(); channel.close(); } } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }); resumeReads(channel); } }, new ChannelListener() { public void handleEvent(final T channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedChannel channel) { latch.countDown(); } }); final ByteBuffer buffer = ByteBuffer.allocate(100); try { buffer.put("This Is A Test Gumma\r\n".getBytes("UTF-8")).flip(); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } setWriteListener(channel, new ChannelListener() { public void handleEvent(final W sinkChannel) { try { int c; while ((c = sinkChannel.write(buffer)) > 0) { if (serverSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final StreamSinkChannel sinkChannel) { try { sinkChannel.shutdownWrites(); channel.close(); } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }; sinkChannel.getWriteSetter().set(listener); listener.handleEvent(sinkChannel); return; } buffer.rewind(); } } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }); resumeWrites(channel);; } }); assertEquals(serverSent.get(), clientReceived.get()); } @Test @Ignore("Does not follow thread model") public void twoWayTransfer() throws Exception { log.info("Test: twoWayTransfer"); final CountDownLatch latch = new CountDownLatch(2); final AtomicInteger clientSent = new AtomicInteger(0); final AtomicInteger clientReceived = new AtomicInteger(0); final AtomicInteger serverSent = new AtomicInteger(0); final AtomicInteger serverReceived = new AtomicInteger(0); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final T channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedChannel channel) { latch.countDown(); } }); setReadListener(channel, new ChannelListener() { public void handleEvent(final R sourceChannel) { try { int c; while ((c = sourceChannel.read(ByteBuffer.allocate(100))) > 0) { clientReceived.addAndGet(c); } if (c == -1) { sourceChannel.shutdownReads(); } } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }); final ByteBuffer buffer = ByteBuffer.allocate(100); try { buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } setWriteListener(channel, new ChannelListener() { public void handleEvent(final W sinkChannel) { try { int c; while ((c = sinkChannel.write(buffer)) > 0) { if (clientSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final StreamSinkChannel sinkChannel) { try { sinkChannel.shutdownWrites(); } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }; sinkChannel.getWriteSetter().set(listener); listener.handleEvent(sinkChannel); return; } buffer.rewind(); } } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }); resumeReads(channel); resumeWrites(channel); } }, new ChannelListener() { public void handleEvent(final T channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedChannel channel) { latch.countDown(); } }); setReadListener(channel, new ChannelListener() { public void handleEvent(final R sourceChannel) { try { int c; while ((c = sourceChannel.read(ByteBuffer.allocate(100))) > 0) { serverReceived.addAndGet(c); } if (c == -1) { sourceChannel.shutdownReads(); } } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }); final ByteBuffer buffer = ByteBuffer.allocate(100); try { buffer.put("This Is A Test Gumma\r\n".getBytes("UTF-8")).flip(); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } setWriteListener(channel, new ChannelListener() { public void handleEvent(final W sinkChannel) { try { int c; while ((c = sinkChannel.write(buffer)) > 0) { if (serverSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final StreamSinkChannel channel) { try { channel.shutdownWrites(); } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }; sinkChannel.getWriteSetter().set(listener); listener.handleEvent(sinkChannel); return; } buffer.rewind(); } } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }); resumeReads(channel); resumeWrites(channel);; } }); assertEquals(serverSent.get(), clientReceived.get()); assertEquals(clientSent.get(), serverReceived.get()); } @Test public void clientNastyClose() throws Exception { log.info("Test: clientNastyClose"); final CountDownLatch latch = new CountDownLatch(2); final AtomicBoolean clientOK = new AtomicBoolean(false); final AtomicBoolean serverOK = new AtomicBoolean(false); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final T channel) { try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedChannel channel) { latch.countDown(); } }); channel.setOption(Options.CLOSE_ABORT, Boolean.TRUE); channel.close(); clientOK.set(true); } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); latch.countDown(); throw new RuntimeException(t); } } }, new ChannelListener() { public void handleEvent(final T channel) { try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedChannel channel) { latch.countDown(); } }); setReadListener(channel, new ChannelListener() { public void handleEvent(final R sourceChannel) { int res; try { res = sourceChannel.read(ByteBuffer.allocate(100)); } catch (IOException e) { serverOK.set(true); IoUtils.safeClose(channel); return; } if (res > 0) IoUtils.safeClose(channel); } }); resumeReads(channel); } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); latch.countDown(); throw new RuntimeException(t); } } }); assertTrue(serverOK.get()); assertTrue(clientOK.get()); } @Test public void serverNastyClose() throws Exception { log.info("Test: serverNastyClose"); final CountDownLatch latch = new CountDownLatch(2); final AtomicBoolean clientOK = new AtomicBoolean(false); final AtomicBoolean serverOK = new AtomicBoolean(false); final CountDownLatch serverLatch = new CountDownLatch(1); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final T channel) { try { log.info("Client opened"); channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedChannel channel) { latch.countDown(); } }); setReadListener(channel, new ChannelListener() { public void handleEvent(final R sourceChannel) { int res; try { res = sourceChannel.read(ByteBuffer.allocate(100)); } catch (IOException e) { clientOK.set(true); IoUtils.safeClose(channel); return; } if (res > 0) IoUtils.safeClose(channel); } }); setWriteListener(channel, new ChannelListener() { public void handleEvent(final W sinkChannel) { try { if (sinkChannel.write(ByteBuffer.wrap(new byte[] { 1 })) > 0) { sinkChannel.suspendWrites(); } } catch (IOException e) { IoUtils.safeClose(channel); } } }); resumeReads(channel); resumeWrites(channel); serverLatch.countDown(); } catch (Throwable t) { log.error("Error occurred on client", t); try { channel.close(); } catch (Throwable t2) { log.error("Error occurred on client (close)", t2); latch.countDown(); throw new RuntimeException(t); } throw new RuntimeException(t); } } }, new ChannelListener() { public void handleEvent(final T channel) { try { log.info("Server opened"); channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedChannel channel) { latch.countDown(); } }); setReadListener(channel, new ChannelListener() { public void handleEvent(final R sourceChannel) { try { if (sourceChannel.read(ByteBuffer.allocate(1)) > 0) { log.info("Closing connection..."); channel.setOption(Options.CLOSE_ABORT, Boolean.TRUE); channel.close(); serverOK.set(true); } } catch (IOException e) { IoUtils.safeClose(channel); } } }); resumeReads(channel); } catch (Throwable t) { log.error("Error occurred on server", t); latch.countDown(); throw new RuntimeException(t); } } }); assertTrue(serverOK.get()); assertTrue(clientOK.get()); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/AbstractStreamSinkSourceChannelTest.java000066400000000000000000000502231257016060700331760ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; import java.util.concurrent.TimeUnit; import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.xnio.Buffers; import org.xnio.ChannelPipe; import org.xnio.IoUtils; import org.xnio.OptionMap; import org.xnio.Xnio; import org.xnio.XnioWorker; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; /** * Tests a pair of connected source/sink channels. * * @author Flavia Rainone * * @param the sink channel type * @param the source channel type */ public abstract class AbstractStreamSinkSourceChannelTest { protected static XnioWorker worker; protected static Xnio xnio; /** Sink channel targeted by this test. It must be connected to {@code sourceChanel}. */ protected S sinkChannel = null; /** Source channel targeted by this test. It must be connected to {@code sinkChanel}. */ protected T sourceChannel = null; /** * Creates the pair of sink/source channels that should be tested. * * @param xnioWorker the worker * @param optionMap contains channels options * @param sinkChannelListener handles sink channel creation * @param sourceChannelListener handles source channel creation */ protected abstract void initChannels(XnioWorker xnioWorker, OptionMap optionMap, TestChannelListener sinkChannelListener, TestChannelListener sourceChannelListener) throws IOException; @BeforeClass public static void createWorker() throws IOException { xnio = Xnio.getInstance("nio", AbstractStreamSinkSourceChannelTest.class.getClassLoader()); worker = xnio.createWorker(OptionMap.EMPTY); } @AfterClass public static void shutdownWorker() throws IOException { worker.shutdownNow(); } /** * Creates the channels and sets their values to the fields {@link sinkChannel} and {@link sourceChannel}. *

This method must be invoked by the subclasses in order to enable automatic channel closing after the test. * * @param worker the worker * @param optionMap contains channels options */ protected void initChannels(XnioWorker worker, OptionMap optionMap) throws IOException { if (sinkChannel != null) { closeChannels(); } final TestChannelListener sinkChannelListener = new TestChannelListener(); final TestChannelListener sourceChannelListener = new TestChannelListener(); initChannels(worker, optionMap, sinkChannelListener, sourceChannelListener); assertTrue("Subclass must invoke the channel listeners to setup sink and source channels", sinkChannelListener.isInvokedYet()); assertTrue("Subclass must invoke the channel listeners to setup sink and source channels", sourceChannelListener.isInvokedYet()); sinkChannel = sinkChannelListener.getChannel(); assertNotNull(sinkChannel); assertTrue(sinkChannel.isOpen()); sourceChannel = sourceChannelListener.getChannel(); assertNotNull(sourceChannel); assertTrue(sourceChannel.isOpen()); } /** * Creates the channels and sets their values to the fields {@link sinkChannel} and {@link sourceChannel}. *

This method must be invoked by the subclasses in order to enable automatic channel closing after the test. */ protected void initChannels() throws IOException { initChannels(worker, OptionMap.EMPTY); } @After public void closeChannels() throws IOException { if (sinkChannel != null) { sinkChannel.close(); assertFalse(sinkChannel.isOpen()); sourceChannel.close(); assertFalse(sourceChannel.isOpen()); } } @Test public void writeToSinkAndReadFromSource() throws IOException{ initChannels(); final ByteBuffer writeBuffer = ByteBuffer.allocate(35); final ByteBuffer readBuffer = ByteBuffer.allocate(35); writeBuffer.put("write to sink and read from source".getBytes()).flip(); assertEquals(0, sourceChannel.read(readBuffer)); assertEquals(34, sinkChannel.write(writeBuffer)); assertEquals(34, sourceChannel.read(readBuffer)); assertEquals(0, sinkChannel.write(writeBuffer)); assertEquals(0, sourceChannel.read(readBuffer)); readBuffer.flip(); assertEquals("write to sink and read from source", Buffers.getModifiedUtf8(readBuffer)); sinkChannel.close(); assertEquals(0, sourceChannel.read(readBuffer)); writeBuffer.flip(); ClosedChannelException expected = null; try { sinkChannel.write(writeBuffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); } @Test public void writeToSinkAndReadFromSourceWithMultipleBuffers() throws IOException{ initChannels(); final ByteBuffer[] writeBuffers = new ByteBuffer[] {ByteBuffer.allocate(4), ByteBuffer.allocate(9), ByteBuffer.allocate(13), Buffers.EMPTY_BYTE_BUFFER}; final ByteBuffer[] readBuffers = new ByteBuffer[] {ByteBuffer.allocate(1), ByteBuffer.allocate(5), ByteBuffer.allocate(10), ByteBuffer.allocate(15), ByteBuffer.allocate(20)}; writeBuffers[0].put(">= 2".getBytes()).flip(); writeBuffers[1].put("several".getBytes()).flip(); writeBuffers[2].put("+ than 1".getBytes()).flip(); assertEquals(0, sourceChannel.read(readBuffers)); assertEquals(0, sinkChannel.write(writeBuffers, 3, 1)); assertEquals(8, sinkChannel.write(writeBuffers, 2, 2)); assertEquals(0, sinkChannel.write(writeBuffers, 2, 2)); assertEquals(1, sourceChannel.read(readBuffers, 0, 1)); assertEquals('+', readBuffers[0].get(0)); assertEquals(7, sourceChannel.read(readBuffers)); assertEquals(0, sourceChannel.read(readBuffers, 1, 2)); assertEquals(11, sinkChannel.write(writeBuffers)); assertEquals(11, sourceChannel.read(readBuffers, 3, 2)); readBuffers[1].flip(); readBuffers[2].flip(); readBuffers[3].flip(); readBuffers[4].flip(); assertEquals(" than", Buffers.getModifiedUtf8(readBuffers[1])); assertEquals(" 1", Buffers.getModifiedUtf8(readBuffers[2])); assertEquals(">= 2several", Buffers.getModifiedUtf8(readBuffers[3])); assertEquals(0, readBuffers[4].remaining()); sinkChannel.close(); assertEquals(0, sourceChannel.read(readBuffers)); writeBuffers[0].flip(); ClosedChannelException expected = null; try { sinkChannel.write(writeBuffers); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); } @Test public void transferTo() throws IOException { initChannels(); final ByteBuffer buffer = ByteBuffer.allocate(20); final ByteBuffer transferedMessage1 = ByteBuffer.allocate(6); final ByteBuffer transferedMessage2 = ByteBuffer.allocate(16); buffer.put("transfered message".getBytes()).flip(); final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); final FileChannel fileChannel = randomAccessFile.getChannel(); try { assertEquals (0, sourceChannel.transferTo(0, 6, fileChannel)); sinkChannel.write(buffer); assertEquals (8, sourceChannel.transferTo(0, 8, fileChannel)); assertEquals (10, sourceChannel.transferTo(8, 11, fileChannel)); fileChannel.position(0); assertEquals(6, fileChannel.read(transferedMessage1)); assertEquals(12, fileChannel.read(transferedMessage2)); transferedMessage1.flip(); transferedMessage2.flip(); assertEquals("transf", Buffers.getModifiedUtf8(transferedMessage1)); assertEquals("ered message", Buffers.getModifiedUtf8(transferedMessage2)); assertEquals (0, sourceChannel.transferTo(0, 6, fileChannel)); sourceChannel.close(); long transferred = 0; ClosedChannelException expected = null; try { transferred = sourceChannel.transferTo(0, 6, fileChannel); } catch (ClosedChannelException e) { expected = e; } assertTrue(expected != null || transferred == 0); } finally { fileChannel.close(); randomAccessFile.close(); } } @Test public void transferFrom() throws IOException { initChannels(); final ByteBuffer buffer = ByteBuffer.allocate(20); final ByteBuffer transferedMessage1 = ByteBuffer.allocate(6); final ByteBuffer transferedMessage2 = ByteBuffer.allocate(16); buffer.put("transferred message".getBytes()).flip(); final File file = File.createTempFile("test", ".txt"); file.deleteOnExit(); final RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); final FileChannel fileChannel = randomAccessFile.getChannel(); try { assertEquals (0, sinkChannel.transferFrom(fileChannel, 0, 6)); fileChannel.write(buffer); assertEquals (8, sinkChannel.transferFrom(fileChannel, 0, 8)); assertEquals (11, sinkChannel.transferFrom(fileChannel, 8, 11)); assertEquals(6, sourceChannel.read(transferedMessage1)); assertEquals(13, sourceChannel.read(transferedMessage2)); transferedMessage1.flip(); transferedMessage2.flip(); assertEquals("transf", Buffers.getModifiedUtf8(transferedMessage1)); assertEquals("erred message", Buffers.getModifiedUtf8(transferedMessage2)); assertEquals (0, sinkChannel.transferFrom(fileChannel, 19, 6)); sinkChannel.close(); IOException expected = null; try { sinkChannel.transferFrom(fileChannel, 0, 6); } catch (IOException e) { expected = e; } assertNotNull(expected); } finally { fileChannel.close(); randomAccessFile.close(); } } @Test public void transferThroughBuffer() throws IOException { initChannels(); final ChannelPipe channelPipe = worker.createHalfDuplexPipe(); final StreamSourceChannel leftChannel = channelPipe.getLeftSide(); final StreamSinkChannel rightChannel = channelPipe.getRightSide(); try { final ByteBuffer readBuffer = ByteBuffer.allocate(50); final ByteBuffer writeBuffer = ByteBuffer.allocate(50); final ByteBuffer throughBuffer = ByteBuffer.allocate(10); // Step 1: write to sink channel and transfer from source channel to left channel; read from right channel writeBuffer.put("looooooooooooooooooooooooooong daaaaaaaaaaaata".getBytes()).flip(); assertEquals(46, sinkChannel.write(writeBuffer)); assertEquals(46, sourceChannel.transferTo(50, throughBuffer, rightChannel)); readBuffer.clear(); assertEquals(46, leftChannel.read(readBuffer)); readBuffer.flip(); assertEquals("looooooooooooooooooooooooooong daaaaaaaaaaaata", Buffers.getModifiedUtf8(readBuffer)); // Step 2: write to sink channel, transfer from source channel to left channel, then transfer from left channel to sink again // finally, read from source channel throughBuffer.clear(); writeBuffer.flip(); assertEquals(46, sinkChannel.write(writeBuffer)); assertEquals(46, sourceChannel.transferTo(50, throughBuffer, rightChannel)); assertEquals(46, sinkChannel.transferFrom(leftChannel, 50, throughBuffer)); readBuffer.clear(); assertEquals(46, sourceChannel.read(readBuffer)); readBuffer.flip(); assertEquals("looooooooooooooooooooooooooong daaaaaaaaaaaata", Buffers.getModifiedUtf8(readBuffer)); } finally { IoUtils.safeClose(leftChannel); IoUtils.safeClose(rightChannel); } } @Test @Ignore("Does not follow thread model") public void suspendResumeReadsAndWrites() throws IOException, InterruptedException { initChannels(); assertFalse(sourceChannel.isReadResumed()); assertFalse(sinkChannel.isWriteResumed()); final TestChannelListener readListener = new TestChannelListener(); final TestChannelListener writeListener = new TestChannelListener(); sourceChannel.getReadSetter().set(readListener); assertFalse(readListener.isInvokedYet()); sinkChannel.getWriteSetter().set(writeListener); assertFalse(writeListener.isInvokedYet()); sinkChannel.awaitWritable(); sourceChannel.resumeReads(); int count = 0; while(!sourceChannel.isReadResumed()) { Thread.sleep(50); if (++ count == 10) { fail("Read is not resumed"); } } assertTrue(sourceChannel.isReadResumed()); assertFalse(sinkChannel.isWriteResumed()); sinkChannel.resumeWrites(); count = 0; assertTrue(writeListener.isInvoked()); assertTrue(sinkChannel.isWriteResumed()); writeListener.clear(); assertTrue(sourceChannel.isReadResumed()); sourceChannel.suspendReads(); assertFalse(sourceChannel.isReadResumed()); assertTrue(sinkChannel.isWriteResumed()); sinkChannel.suspendWrites(); assertFalse(sourceChannel.isReadResumed()); assertFalse(sinkChannel.isWriteResumed()); sinkChannel.wakeupWrites(); assertTrue(writeListener.isInvoked()); assertFalse(readListener.isInvokedYet()); assertSame(sinkChannel, writeListener.getChannel()); sourceChannel.wakeupReads(); assertTrue(readListener.isInvoked()); assertSame(sourceChannel, readListener.getChannel()); sourceChannel.shutdownReads(); sinkChannel.shutdownWrites(); try { Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } assertFalse(sourceChannel.isOpen()); assertFalse(sinkChannel.isOpen()); } @SuppressWarnings("deprecation") @Test public void awaitReadableAndWritable() throws IOException, InterruptedException { initChannels(); final TestChannelListener readListener = new TestChannelListener(); final TestChannelListener writeListener = new TestChannelListener(); sourceChannel.getReadSetter().set(readListener); sinkChannel.getWriteSetter().set(writeListener); sinkChannel.awaitWritable(); sinkChannel.awaitWritable(1, TimeUnit.HOURS); final ReadableAwaiter readableAwaiter1 = new ReadableAwaiter(sourceChannel); final ReadableAwaiter readableAwaiter2 = new ReadableAwaiter(sourceChannel, 10, TimeUnit.MICROSECONDS); final ReadableAwaiter readableAwaiter3 = new ReadableAwaiter(sourceChannel, 10, TimeUnit.MINUTES); final WritableAwaiter writableAwaiter1 = new WritableAwaiter(sinkChannel); final WritableAwaiter writableAwaiter2 = new WritableAwaiter(sinkChannel, 5, TimeUnit.NANOSECONDS); final WritableAwaiter writableAwaiter3 = new WritableAwaiter(sinkChannel, 2222222, TimeUnit.SECONDS); final Thread readableAwaiterThread1 = new Thread(readableAwaiter1); final Thread readableAwaiterThread2 = new Thread(readableAwaiter2); final Thread readableAwaiterThread3 = new Thread(readableAwaiter3); final Thread writableAwaiterThread1 = new Thread(writableAwaiter1); final Thread writableAwaiterThread2 = new Thread(writableAwaiter2); final Thread writableAwaiterThread3 = new Thread(writableAwaiter3); readableAwaiterThread1.start(); readableAwaiterThread2.start(); readableAwaiterThread3.start(); readableAwaiterThread1.join(50); readableAwaiterThread2.join(); readableAwaiterThread3.join(50); assertTrue(readableAwaiterThread1.isAlive()); assertTrue(readableAwaiterThread3.isAlive()); sinkChannel.shutdownWrites(); writableAwaiterThread1.start(); writableAwaiterThread2.start(); writableAwaiterThread3.start(); writableAwaiterThread1.join(); writableAwaiterThread2.join(); writableAwaiterThread3.join(); final ByteBuffer buffer = ByteBuffer.allocate(5); buffer.put("12345".getBytes()).flip(); ClosedChannelException expected = null; try { sinkChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); readableAwaiterThread1.join(); readableAwaiterThread3.join(); sinkChannel.resumeWrites(); writableAwaiterThread1.join(); writableAwaiterThread3.join(); assertNotNull(sinkChannel.getWriteThread()); assertNotNull(sinkChannel.getIoThread()); } protected static class ReadableAwaiter implements Runnable { private final T channel; private final long timeout; private final TimeUnit timeoutUnit; public ReadableAwaiter(T c) { this(c, -1, null); } public ReadableAwaiter(T c, long t, TimeUnit tu) { channel = c; timeout = t; timeoutUnit = tu; } public void run() { try { if (timeout == -1) { channel.awaitReadable(); } else { channel.awaitReadable(timeout, timeoutUnit); } } catch (IOException e) { throw new RuntimeException(e); } } } protected static class WritableAwaiter implements Runnable { private final S channel; private final long timeout; private final TimeUnit timeoutUnit; public WritableAwaiter(S c) { this(c, -1, null); } public WritableAwaiter(S c, long t, TimeUnit tu) { channel = c; timeout = t; timeoutUnit = tu; } public void run() { try { if (timeout == -1) { channel.awaitWritable(); } else { channel.awaitWritable(timeout, timeoutUnit); } } catch (IOException e) { throw new RuntimeException(e); } } } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/CatchingChannelListener.java000066400000000000000000000027421257016060700306420ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio.test; import java.util.List; import org.xnio.ChannelListener; import java.nio.channels.Channel; final class CatchingChannelListener implements ChannelListener { private final ChannelListener delegate; private final List problems; CatchingChannelListener(final ChannelListener delegate, final List problems) { this.delegate = delegate; this.problems = problems; } public void handleEvent(final T channel) { try { if (delegate != null) delegate.handleEvent(channel); } catch (RuntimeException t) { problems.add(t); throw t; } catch (Error t) { problems.add(t); throw t; } } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/ConnectionOptionSetupTestCase.java000066400000000000000000000650351257016060700320740ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import javax.net.ssl.KeyManager; import javax.net.ssl.TrustManager; import org.junit.Test; import org.xnio.FileAccess; import org.xnio.Option; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.Property; import org.xnio.Sequence; import org.xnio.SslClientAuthMode; import org.xnio.XnioWorker; import org.xnio.sasl.SaslQop; import org.xnio.sasl.SaslStrength; /** * Test for setting connection options at the TCP server. * * @author Flavia Rainone */ @SuppressWarnings("deprecation") public class ConnectionOptionSetupTestCase extends TcpServerTest { @Test public void defaultOptionValues() throws IOException { createServer(OptionMap.EMPTY); assertNotNull(server); assertTrue(server.getOption(Options.REUSE_ADDRESSES)); assertTrue((int) server.getOption(Options.RECEIVE_BUFFER) > 0); assertEquals(null, server.getOption(Options.SEND_BUFFER)); assertFalse(server.getOption(Options.KEEP_ALIVE)); assertFalse(server.getOption(Options.TCP_OOB_INLINE)); assertFalse(server.getOption(Options.TCP_NODELAY)); assertEquals(0, (int) server.getOption(Options.READ_TIMEOUT)); assertEquals(0, (int) server.getOption(Options.WRITE_TIMEOUT)); assertTrue(server.getOption(Options.CONNECTION_LOW_WATER) > 0); assertTrue(server.getOption(Options.CONNECTION_HIGH_WATER) > 0); assertTrue((int) server.getOption(Options.CONNECTION_LOW_WATER) <= server.getOption(Options.CONNECTION_HIGH_WATER)); server.close(); } @Test public void optionSetupOnServerCreation() throws IOException { final OptionMap.Builder optionMapBuilder = OptionMap.builder(); optionMapBuilder.set(Options.WORKER_ESTABLISH_WRITING, true); optionMapBuilder.set(Options.REUSE_ADDRESSES, true); optionMapBuilder.set(Options.RECEIVE_BUFFER, 50000); optionMapBuilder.set(Options.SEND_BUFFER, 49999); optionMapBuilder.set(Options.KEEP_ALIVE, true); optionMapBuilder.set(Options.TCP_OOB_INLINE, true); optionMapBuilder.set(Options.TCP_NODELAY, true); optionMapBuilder.set(Options.READ_TIMEOUT, 300000); optionMapBuilder.set(Options.WRITE_TIMEOUT, 250000); optionMapBuilder.set(Options.CONNECTION_LOW_WATER, 12345); optionMapBuilder.set(Options.CONNECTION_HIGH_WATER, 23456); createServer(optionMapBuilder.getMap()); assertTrue(server.getOption(Options.REUSE_ADDRESSES)); assertEquals(50000, (int) server.getOption(Options.RECEIVE_BUFFER)); assertEquals(49999, (int) server.getOption(Options.SEND_BUFFER)); assertTrue(server.getOption(Options.KEEP_ALIVE)); assertTrue(server.getOption(Options.TCP_OOB_INLINE)); assertTrue(server.getOption(Options.TCP_NODELAY)); assertEquals(300000, (int) server.getOption(Options.READ_TIMEOUT)); assertEquals(250000, (int) server.getOption(Options.WRITE_TIMEOUT)); assertEquals(12345, (int) server.getOption(Options.CONNECTION_LOW_WATER)); assertEquals(23456, (int) server.getOption(Options.CONNECTION_HIGH_WATER)); server.close(); } @Test public void resetOptions() throws IOException { final OptionMap.Builder optionMapBuilder = OptionMap.builder(); optionMapBuilder.set(Options.WORKER_ESTABLISH_WRITING, true); optionMapBuilder.set(Options.REUSE_ADDRESSES, true); optionMapBuilder.set(Options.RECEIVE_BUFFER, 10); optionMapBuilder.set(Options.SEND_BUFFER, 1000000); optionMapBuilder.set(Options.KEEP_ALIVE, true); optionMapBuilder.set(Options.TCP_OOB_INLINE, true); optionMapBuilder.set(Options.TCP_NODELAY, true); optionMapBuilder.set(Options.READ_TIMEOUT, 1000000); optionMapBuilder.set(Options.WRITE_TIMEOUT, 1000000); optionMapBuilder.set(Options.CONNECTION_HIGH_WATER, 1000000); optionMapBuilder.set(Options.CONNECTION_LOW_WATER, 1000000); createServer(optionMapBuilder.getMap()); assertTrue(server.getOption(Options.REUSE_ADDRESSES)); assertTrue(server.getOption(Options.RECEIVE_BUFFER) > 0); assertEquals(1000000, (int) server.getOption(Options.SEND_BUFFER)); assertTrue(server.getOption(Options.KEEP_ALIVE)); assertTrue(server.getOption(Options.TCP_OOB_INLINE)); assertTrue(server.getOption(Options.TCP_NODELAY)); assertEquals(1000000, (int) server.getOption(Options.READ_TIMEOUT)); assertEquals(1000000, (int) server.getOption(Options.WRITE_TIMEOUT)); assertEquals(1000000, (int) server.getOption(Options.CONNECTION_HIGH_WATER)); assertEquals(1000000, (int) server.getOption(Options.CONNECTION_LOW_WATER)); assertTrue(server.setOption(Options.REUSE_ADDRESSES, false)); assertTrue(server.setOption(Options.RECEIVE_BUFFER, 20000) > 0); assertEquals(1000000, (int) server.setOption(Options.SEND_BUFFER, 2000000)); assertTrue(server.setOption(Options.KEEP_ALIVE, false)); assertTrue(server.setOption(Options.TCP_OOB_INLINE, false)); assertTrue(server.setOption(Options.TCP_NODELAY, false)); assertEquals(1000000, (int) server.setOption(Options.READ_TIMEOUT, 2000000)); assertEquals(1000000, (int) server.setOption(Options.WRITE_TIMEOUT, 2000000)); assertEquals(1000000, (int) server.setOption(Options.CONNECTION_HIGH_WATER, 200000)); // this will automatically update low water assertEquals(200000, (int) server.setOption(Options.CONNECTION_LOW_WATER, 20000)); assertFalse(server.getOption(Options.REUSE_ADDRESSES)); assertEquals(20000, (int) server.getOption(Options.RECEIVE_BUFFER)); assertEquals(2000000, (int) server.getOption(Options.SEND_BUFFER)); assertFalse(server.getOption(Options.KEEP_ALIVE)); assertFalse(server.getOption(Options.TCP_OOB_INLINE)); assertFalse(server.getOption(Options.TCP_NODELAY)); assertEquals(2000000, (int) server.getOption(Options.READ_TIMEOUT)); assertEquals(2000000, (int) server.getOption(Options.WRITE_TIMEOUT)); assertEquals(200000, (int) server.getOption(Options.CONNECTION_HIGH_WATER)); assertEquals(20000, (int) server.getOption(Options.CONNECTION_LOW_WATER)); assertFalse(server.setOption(Options.REUSE_ADDRESSES, true)); assertEquals(20000, (int) server.setOption(Options.RECEIVE_BUFFER, 2000)); assertEquals(2000000, (int) server.setOption(Options.SEND_BUFFER, 2200)); assertFalse(server.setOption(Options.KEEP_ALIVE, true)); assertFalse(server.setOption(Options.TCP_OOB_INLINE, true)); assertFalse(server.setOption(Options.TCP_NODELAY, true)); assertEquals(2000000, (int) server.setOption(Options.READ_TIMEOUT, 2220000)); assertEquals(2000000, (int) server.setOption(Options.WRITE_TIMEOUT, 2222000)); assertEquals(200000, (int) server.setOption(Options.CONNECTION_HIGH_WATER, 222220)); // this will automatically update low water assertEquals(20000, (int) server.setOption(Options.CONNECTION_LOW_WATER, 22222)); assertTrue(server.getOption(Options.REUSE_ADDRESSES)); assertEquals(2000, (int) server.getOption(Options.RECEIVE_BUFFER)); assertEquals(2200, (int) server.getOption(Options.SEND_BUFFER)); assertTrue(server.getOption(Options.KEEP_ALIVE)); assertTrue(server.getOption(Options.TCP_OOB_INLINE)); assertTrue(server.getOption(Options.TCP_NODELAY)); assertEquals(2220000, (int) server.getOption(Options.READ_TIMEOUT)); assertEquals(2222000, (int) server.getOption(Options.WRITE_TIMEOUT)); assertEquals(222220, (int) server.getOption(Options.CONNECTION_HIGH_WATER)); assertEquals(22222, (int) server.getOption(Options.CONNECTION_LOW_WATER)); // clear all options assertTrue(server.setOption(Options.REUSE_ADDRESSES, null)); assertEquals(2000, (int) server.setOption(Options.RECEIVE_BUFFER, null)); assertEquals(2200, (int) server.setOption(Options.SEND_BUFFER, null)); assertTrue(server.setOption(Options.KEEP_ALIVE, null)); assertTrue(server.setOption(Options.TCP_OOB_INLINE, null)); assertTrue(server.setOption(Options.TCP_NODELAY, null)); assertEquals(2220000, (int) server.setOption(Options.READ_TIMEOUT, null)); assertEquals(2222000, (int) server.setOption(Options.WRITE_TIMEOUT, null)); assertEquals(222220, (int) server.setOption(Options.CONNECTION_HIGH_WATER, null)); // this will automatically update low water assertEquals(22222, (int) server.setOption(Options.CONNECTION_LOW_WATER, null)); // check all default values have been set assertFalse(server.getOption(Options.REUSE_ADDRESSES)); assertEquals(0x10000, (int) server.getOption(Options.RECEIVE_BUFFER)); assertEquals(0x10000, (int) server.getOption(Options.SEND_BUFFER)); assertFalse(server.getOption(Options.KEEP_ALIVE)); assertFalse(server.getOption(Options.TCP_OOB_INLINE)); assertFalse(server.getOption(Options.TCP_NODELAY)); assertEquals(0, (int) server.getOption(Options.READ_TIMEOUT)); assertEquals(0, (int) server.getOption(Options.WRITE_TIMEOUT)); assertTrue((int) server.getOption(Options.CONNECTION_LOW_WATER) > 0); assertTrue((int) server.getOption(Options.CONNECTION_HIGH_WATER) > 0); assertTrue(server.getOption(Options.CONNECTION_LOW_WATER) <= server.getOption(Options.CONNECTION_HIGH_WATER)); assertFalse(server.setOption(Options.REUSE_ADDRESSES, null)); // FIXME XNIO-171 assertEquals(0x10000, (int) server.setOption(Options.RECEIVE_BUFFER, null)); assertEquals(0x10000, (int) server.setOption(Options.SEND_BUFFER, null)); assertFalse(server.setOption(Options.KEEP_ALIVE, null)); assertFalse(server.setOption(Options.TCP_OOB_INLINE, null)); assertFalse(server.setOption(Options.TCP_NODELAY, null)); assertEquals(0, (int) server.setOption(Options.READ_TIMEOUT, null)); assertEquals(0, (int) server.setOption(Options.WRITE_TIMEOUT, null)); assertTrue((int) server.setOption(Options.CONNECTION_LOW_WATER, null) > 0); assertTrue((int) server.setOption(Options.CONNECTION_HIGH_WATER, null) > 0); server.close(); } @Test public void resetAllOptions() throws IOException { final Option[] unsupportedOptions = OptionHelper.getNotSupportedOptions(Options.WORKER_ACCEPT_THREADS, Options.WORKER_ESTABLISH_WRITING, Options.REUSE_ADDRESSES, Options.RECEIVE_BUFFER, Options.SEND_BUFFER, Options.KEEP_ALIVE, Options.TCP_OOB_INLINE, Options.TCP_NODELAY, Options.READ_TIMEOUT, Options.WRITE_TIMEOUT, Options.CONNECTION_HIGH_WATER, Options.CONNECTION_LOW_WATER); // supported options final OptionMap.Builder optionMapBuilder = OptionMap.builder(); optionMapBuilder.set(Options.WORKER_ACCEPT_THREADS, getWorkerReadThreads() == 1? 1: getWorkerReadThreads() - 1); optionMapBuilder.set(Options.WORKER_ESTABLISH_WRITING, false); optionMapBuilder.set(Options.REUSE_ADDRESSES, true); optionMapBuilder.set(Options.RECEIVE_BUFFER, 30000); optionMapBuilder.set(Options.SEND_BUFFER, 29000); optionMapBuilder.set(Options.KEEP_ALIVE, false); optionMapBuilder.set(Options.TCP_OOB_INLINE, false); optionMapBuilder.set(Options.TCP_NODELAY, false); optionMapBuilder.set(Options.READ_TIMEOUT, 28); optionMapBuilder.set(Options.WRITE_TIMEOUT, 27); optionMapBuilder.set(Options.CONNECTION_HIGH_WATER, 26); optionMapBuilder.set(Options.CONNECTION_LOW_WATER, 25); // unsupported options optionMapBuilder.set(Options.ALLOW_BLOCKING, true); optionMapBuilder.set(Options.BACKLOG, 10000); optionMapBuilder.set(Options.BROADCAST, false); optionMapBuilder.set(Options.CLOSE_ABORT, true); optionMapBuilder.set(Options.CORK, false); optionMapBuilder.set(Options.FILE_ACCESS, FileAccess.READ_ONLY); optionMapBuilder.set(Options.IP_TRAFFIC_CLASS, 20000); optionMapBuilder.set(Options.MAX_INBOUND_MESSAGE_SIZE, 30000); optionMapBuilder.set(Options.MAX_OUTBOUND_MESSAGE_SIZE, 40000); optionMapBuilder.set(Options.MULTICAST, true); optionMapBuilder.set(Options.MULTICAST_TTL, 50000); optionMapBuilder.set(Options.SASL_DISALLOWED_MECHANISMS, Sequence.empty()); optionMapBuilder.set(Options.SASL_MECHANISMS, Sequence.of("mech1")); optionMapBuilder.set(Options.SASL_POLICY_FORWARD_SECRECY, true); optionMapBuilder.set(Options.SASL_POLICY_NOACTIVE, false); optionMapBuilder.set(Options.SASL_POLICY_NOANONYMOUS, true); optionMapBuilder.set(Options.SASL_POLICY_NODICTIONARY, false); optionMapBuilder.set(Options.SASL_POLICY_NOPLAINTEXT, true); optionMapBuilder.set(Options.SASL_POLICY_PASS_CREDENTIALS, false); optionMapBuilder.set(Options.SASL_PROPERTIES, Sequence.empty()); optionMapBuilder.set(Options.SASL_QOP, Sequence.of(SaslQop.AUTH_CONF)); optionMapBuilder.set(Options.SASL_REUSE, true); optionMapBuilder.set(Options.SASL_SERVER_AUTH, false); optionMapBuilder.set(Options.SASL_STRENGTH, SaslStrength.MEDIUM); optionMapBuilder.set(Options.SECURE, true); optionMapBuilder.set(Options.SSL_APPLICATION_BUFFER_REGION_SIZE, 60000); optionMapBuilder.set(Options.SSL_APPLICATION_BUFFER_SIZE, 70000); optionMapBuilder.set(Options.SSL_CLIENT_AUTH_MODE, SslClientAuthMode.NOT_REQUESTED); optionMapBuilder.set(Options.SSL_CLIENT_SESSION_CACHE_SIZE, 80000); optionMapBuilder.set(Options.SSL_CLIENT_SESSION_TIMEOUT, 90000); optionMapBuilder.set(Options.SSL_ENABLE_SESSION_CREATION, false); optionMapBuilder.set(Options.SSL_ENABLED, true); optionMapBuilder.set(Options.SSL_ENABLED_CIPHER_SUITES, Sequence.of("cipher foo")); optionMapBuilder.set(Options.SSL_ENABLED_PROTOCOLS, Sequence.of("foo", "dummy")); optionMapBuilder.set(Options.SSL_JSSE_KEY_MANAGER_CLASSES, Sequence.>empty()); optionMapBuilder.set(Options.SSL_JSSE_TRUST_MANAGER_CLASSES, Sequence.>empty()); optionMapBuilder.set(Options.SSL_PACKET_BUFFER_REGION_SIZE, 100000); optionMapBuilder.set(Options.SSL_PACKET_BUFFER_SIZE, 110000); optionMapBuilder.set(Options.SSL_PEER_HOST_NAME, "none"); optionMapBuilder.set(Options.SSL_PEER_PORT, 0); optionMapBuilder.set(Options.SSL_PROTOCOL, "any"); optionMapBuilder.set(Options.SSL_PROVIDER, "-"); optionMapBuilder.set(Options.SSL_RNG_OPTIONS, OptionMap.EMPTY); optionMapBuilder.set(Options.SSL_SERVER_SESSION_CACHE_SIZE, 120000); optionMapBuilder.set(Options.SSL_SERVER_SESSION_TIMEOUT, 130000); optionMapBuilder.set(Options.SSL_STARTTLS, false); optionMapBuilder.set(Options.SSL_SUPPORTED_CIPHER_SUITES, Sequence.empty()); optionMapBuilder.set(Options.SSL_SUPPORTED_PROTOCOLS, Sequence.empty()); optionMapBuilder.set(Options.SSL_USE_CLIENT_MODE, true); optionMapBuilder.set(Options.STACK_SIZE, 140000); optionMapBuilder.set(Options.THREAD_DAEMON, false); optionMapBuilder.set(Options.THREAD_PRIORITY, 15); optionMapBuilder.set(Options.USE_DIRECT_BUFFERS, true); optionMapBuilder.set(Options.WORKER_NAME, "worker"); optionMapBuilder.set(Options.WORKER_READ_THREADS, 16); optionMapBuilder.set(Options.WORKER_TASK_CORE_THREADS, 17); optionMapBuilder.set(Options.WORKER_TASK_KEEPALIVE, 18); optionMapBuilder.set(Options.WORKER_TASK_LIMIT, 19); optionMapBuilder.set(Options.WORKER_TASK_MAX_THREADS, 20); optionMapBuilder.set(Options.WORKER_WRITE_THREADS, 21); createServer(optionMapBuilder.getMap()); assertTrue(server.getOption(Options.REUSE_ADDRESSES)); assertEquals(30000, (int) server.getOption(Options.RECEIVE_BUFFER)); assertEquals(29000, (int) server.getOption(Options.SEND_BUFFER)); assertFalse(server.getOption(Options.KEEP_ALIVE)); assertFalse(server.getOption(Options.TCP_OOB_INLINE)); assertFalse(server.getOption(Options.TCP_NODELAY)); assertEquals(28, (int) server.getOption(Options.READ_TIMEOUT)); assertEquals(27, (int) server.getOption(Options.WRITE_TIMEOUT)); assertEquals(26, (int) server.getOption(Options.CONNECTION_HIGH_WATER)); assertEquals(25, (int) server.getOption(Options.CONNECTION_LOW_WATER)); for (Option option: unsupportedOptions) { assertNull("Non null value for option " + option + ": " + server.getOption(option), server.getOption(option)); assertFalse(server.supportsOption(option)); } assertTrue(server.supportsOption(Options.REUSE_ADDRESSES)); assertTrue(server.supportsOption(Options.RECEIVE_BUFFER)); assertTrue(server.supportsOption(Options.SEND_BUFFER)); assertTrue(server.supportsOption(Options.KEEP_ALIVE)); assertTrue(server.supportsOption(Options.TCP_NODELAY)); assertTrue(server.supportsOption(Options.TCP_OOB_INLINE)); assertTrue(server.supportsOption(Options.READ_TIMEOUT)); assertTrue(server.supportsOption(Options.WRITE_TIMEOUT)); assertTrue(server.supportsOption(Options.CONNECTION_LOW_WATER)); assertTrue(server.supportsOption(Options.CONNECTION_HIGH_WATER)); assertTrue(server.setOption(Options.REUSE_ADDRESSES, false)); assertEquals(30000, (int) server.setOption(Options.RECEIVE_BUFFER, 24000)); assertEquals(29000, (int) server.setOption(Options.SEND_BUFFER, 23000)); assertFalse(server.setOption(Options.KEEP_ALIVE, true)); assertFalse(server.setOption(Options.TCP_OOB_INLINE, true)); assertFalse(server.setOption(Options.TCP_NODELAY, true)); assertEquals(28, (int) server.setOption(Options.READ_TIMEOUT, 22000)); assertEquals(27, (int) server.setOption(Options.WRITE_TIMEOUT, 21000000)); assertEquals(25, (int) server.setOption(Options.CONNECTION_LOW_WATER, 190)); assertEquals(190, (int) server.setOption(Options.CONNECTION_HIGH_WATER, 200)); // unsupported options assertNull(server.setOption(Options.ALLOW_BLOCKING, true)); assertNull(server.setOption(Options.BACKLOG, 10000)); assertNull(server.setOption(Options.BROADCAST, false)); assertNull(server.setOption(Options.CLOSE_ABORT, true)); assertNull(server.setOption(Options.CORK, false)); assertNull(server.setOption(Options.FILE_ACCESS, FileAccess.READ_ONLY)); assertNull(server.setOption(Options.IP_TRAFFIC_CLASS, 20000)); assertNull(server.setOption(Options.MAX_INBOUND_MESSAGE_SIZE, 30000)); assertNull(server.setOption(Options.MAX_OUTBOUND_MESSAGE_SIZE, 40000)); assertNull(server.setOption(Options.MULTICAST, true)); assertNull(server.setOption(Options.MULTICAST_TTL, 50000)); assertNull(server.setOption(Options.SASL_DISALLOWED_MECHANISMS, Sequence.empty())); assertNull(server.setOption(Options.SASL_MECHANISMS, Sequence.of("mech1"))); assertNull(server.setOption(Options.SASL_POLICY_FORWARD_SECRECY, true)); assertNull(server.setOption(Options.SASL_POLICY_NOACTIVE, false)); assertNull(server.setOption(Options.SASL_POLICY_NOANONYMOUS, true)); assertNull(server.setOption(Options.SASL_POLICY_NODICTIONARY, false)); assertNull(server.setOption(Options.SASL_POLICY_NOPLAINTEXT, true)); assertNull(server.setOption(Options.SASL_POLICY_PASS_CREDENTIALS, false)); assertNull(server.setOption(Options.SASL_PROPERTIES, Sequence.empty())); assertNull(server.setOption(Options.SASL_QOP, Sequence.of(SaslQop.AUTH_CONF))); assertNull(server.setOption(Options.SASL_REUSE, true)); assertNull(server.setOption(Options.SASL_SERVER_AUTH, false)); assertNull(server.setOption(Options.SASL_STRENGTH, SaslStrength.MEDIUM)); assertNull(server.setOption(Options.SECURE, true)); assertNull(server.setOption(Options.SSL_APPLICATION_BUFFER_REGION_SIZE, 60000)); assertNull(server.setOption(Options.SSL_APPLICATION_BUFFER_SIZE, 70000)); assertNull(server.setOption(Options.SSL_CLIENT_AUTH_MODE, SslClientAuthMode.NOT_REQUESTED)); assertNull(server.setOption(Options.SSL_CLIENT_SESSION_CACHE_SIZE, 80000)); assertNull(server.setOption(Options.SSL_CLIENT_SESSION_TIMEOUT, 90000)); assertNull(server.setOption(Options.SSL_ENABLE_SESSION_CREATION, false)); assertNull(server.setOption(Options.SSL_ENABLED, true)); assertNull(server.setOption(Options.SSL_ENABLED_CIPHER_SUITES, Sequence.of("cipher foo"))); assertNull(server.setOption(Options.SSL_ENABLED_PROTOCOLS, Sequence.of("foo", "dummy"))); assertNull(server.setOption(Options.SSL_JSSE_KEY_MANAGER_CLASSES, Sequence.>empty())); assertNull(server.setOption(Options.SSL_JSSE_TRUST_MANAGER_CLASSES, Sequence.>empty())); assertNull(server.setOption(Options.SSL_PACKET_BUFFER_REGION_SIZE, 100000)); assertNull(server.setOption(Options.SSL_PACKET_BUFFER_SIZE, 110000)); assertNull(server.setOption(Options.SSL_PEER_HOST_NAME, "none")); assertNull(server.setOption(Options.SSL_PEER_PORT, 0)); assertNull(server.setOption(Options.SSL_PROTOCOL, "any")); assertNull(server.setOption(Options.SSL_PROVIDER, "-")); assertNull(server.setOption(Options.SSL_RNG_OPTIONS, OptionMap.EMPTY)); assertNull(server.setOption(Options.SSL_SERVER_SESSION_CACHE_SIZE, 120000)); assertNull(server.setOption(Options.SSL_SERVER_SESSION_TIMEOUT, 130000)); assertNull(server.setOption(Options.SSL_STARTTLS, false)); assertNull(server.setOption(Options.SSL_SUPPORTED_CIPHER_SUITES, Sequence.empty())); assertNull(server.setOption(Options.SSL_SUPPORTED_PROTOCOLS, Sequence.empty())); assertNull(server.setOption(Options.SSL_USE_CLIENT_MODE, true)); assertNull(server.setOption(Options.STACK_SIZE, 140000l)); assertNull(server.setOption(Options.THREAD_DAEMON, false)); assertNull(server.setOption(Options.THREAD_PRIORITY, 15)); assertNull(server.setOption(Options.USE_DIRECT_BUFFERS, true)); assertNull(server.setOption(Options.WORKER_NAME, "worker")); assertNull(server.setOption(Options.WORKER_READ_THREADS, 16)); assertNull(server.setOption(Options.WORKER_TASK_CORE_THREADS, 17)); assertNull(server.setOption(Options.WORKER_TASK_KEEPALIVE, 18)); assertNull(server.setOption(Options.WORKER_TASK_LIMIT, 19)); assertNull(server.setOption(Options.WORKER_TASK_MAX_THREADS, 20)); assertNull(server.setOption(Options.WORKER_WRITE_THREADS, 21)); assertFalse(server.getOption(Options.REUSE_ADDRESSES)); assertEquals(24000, (int) server.getOption(Options.RECEIVE_BUFFER)); assertEquals(23000, (int) server.getOption(Options.SEND_BUFFER)); assertTrue(server.getOption(Options.KEEP_ALIVE)); assertTrue(server.getOption(Options.TCP_OOB_INLINE)); assertTrue(server.getOption(Options.TCP_NODELAY)); assertEquals(22000, (int) server.getOption(Options.READ_TIMEOUT)); assertEquals(21000000, (int) server.getOption(Options.WRITE_TIMEOUT)); assertEquals(200, (int) server.getOption(Options.CONNECTION_HIGH_WATER)); assertEquals(190, (int) server.getOption(Options.CONNECTION_LOW_WATER)); for (Option option: unsupportedOptions) { assertNull("Non null value for option " + option + ": " + server.getOption(option), server.getOption(option)); assertFalse(server.supportsOption(option)); } server.close(); } @Test public void largeNumberOfThreads() throws IllegalArgumentException, IOException { final XnioWorker worker1 = xnio.createWorker(OptionMap.create(Options.WORKER_WRITE_THREADS, 30, Options.WORKER_READ_THREADS, 50)); //make sure that a bigger number of threads is handled without any errors createServer(worker1, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, true, Options.WORKER_ACCEPT_THREADS, 12)); createServer(worker1, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, false, Options.WORKER_ACCEPT_THREADS, 40)); createServer(worker1, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, false, Options.WORKER_ACCEPT_THREADS, 20)); createServer(worker1, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, false, Options.WORKER_ACCEPT_THREADS, 10)); // huge number of threads final XnioWorker worker2 = xnio.createWorker(OptionMap.create(Options.WORKER_WRITE_THREADS, 100, Options.WORKER_READ_THREADS, 70)); //make sure that a bigger number of threads is handled without any errors createServer(worker2, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, true, Options.WORKER_ACCEPT_THREADS, 12)); createServer(worker2, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, true, Options.WORKER_ACCEPT_THREADS, 80)); createServer(worker2, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, true, Options.WORKER_ACCEPT_THREADS, 100)); createServer(worker2, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, false, Options.WORKER_ACCEPT_THREADS, 10)); createServer(worker2, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, false, Options.WORKER_ACCEPT_THREADS, 50)); createServer(worker2, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, false, Options.WORKER_ACCEPT_THREADS, 69)); server.close(); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/FileSystemWatcherTestCase.java000066400000000000000000000160451257016060700311620ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.nio.test; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.BeforeClass; import org.junit.Test; import org.xnio.FileChangeCallback; import org.xnio.FileChangeEvent; import org.xnio.FileSystemWatcher; import org.xnio.IoUtils; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.Xnio; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.ConnectedStreamChannel; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.util.Collection; import java.util.concurrent.BlockingDeque; import java.util.concurrent.LinkedBlockingDeque; import java.util.concurrent.TimeUnit; import static org.xnio.FileChangeEvent.Type.MODIFIED; import static org.xnio.FileChangeEvent.Type.REMOVED; /** * Test file system watcher, non poll based * * @author Stuart Douglas */ public class FileSystemWatcherTestCase { public static final String DIR_NAME = "/fileSystemWatcherTest"; public static final String EXISTING_FILE_NAME = "a.txt"; public static final String EXISTING_DIR = "existingDir"; private final BlockingDeque> results = new LinkedBlockingDeque>(); private final BlockingDeque> secondResults = new LinkedBlockingDeque>(); File rootDir; File existingSubDir; protected AcceptingChannel server; private Xnio createXnio() { return Xnio.getInstance("nio", FileSystemWatcherTestCase.class.getClassLoader()); } @Before public void setup() throws Exception { rootDir = new File(System.getProperty("java.io.tmpdir") + DIR_NAME); deleteRecursive(rootDir); rootDir.mkdirs(); File existing = new File(rootDir, EXISTING_FILE_NAME); touchFile(existing); existingSubDir = new File(rootDir, EXISTING_DIR); existingSubDir.mkdir(); existing = new File(existingSubDir, EXISTING_FILE_NAME); touchFile(existing); } private static void touchFile(File existing) throws IOException { FileOutputStream out = new FileOutputStream(existing); try { out.write(("data" + System.currentTimeMillis()).getBytes()); out.flush(); } finally { IoUtils.safeClose(out); } } @After public void after() { deleteRecursive(rootDir); } @Test public void testFileSystemWatcher() throws Exception { FileSystemWatcher watcher = createXnio().createFileSystemWatcher("testWatcher", OptionMap.create(Options.WATCHER_POLL_INTERVAL, 10)); try { watcher.watchPath(rootDir, new FileChangeCallback() { @Override public void handleChanges(Collection changes) { results.add(changes); } }); watcher.watchPath(rootDir, new FileChangeCallback() { @Override public void handleChanges(Collection changes) { secondResults.add(changes); } }); //first add a file File added = new File(rootDir, "newlyAddedFile.txt").getAbsoluteFile(); touchFile(added); checkResult(added, FileChangeEvent.Type.ADDED); added.setLastModified(500); checkResult(added, MODIFIED); added.delete(); Thread.sleep(1); checkResult(added, REMOVED); added = new File(existingSubDir, "newSubDirFile.txt"); touchFile(added); checkResult(added, FileChangeEvent.Type.ADDED); added.setLastModified(500); checkResult(added, MODIFIED); added.delete(); Thread.sleep(1); checkResult(added, REMOVED); File existing = new File(rootDir, EXISTING_FILE_NAME); existing.delete(); Thread.sleep(1); checkResult(existing, REMOVED); File newDir = new File(rootDir, "newlyCreatedDirectory"); newDir.mkdir(); checkResult(newDir, FileChangeEvent.Type.ADDED); added = new File(newDir, "newlyAddedFileInNewlyAddedDirectory.txt").getAbsoluteFile(); touchFile(added); checkResult(added, FileChangeEvent.Type.ADDED); added.setLastModified(500); checkResult(added, MODIFIED); added.delete(); Thread.sleep(1); checkResult(added, REMOVED); } finally { watcher.close(); } } private void checkResult(File file, FileChangeEvent.Type type) throws InterruptedException { Collection results = this.results.poll(10, TimeUnit.SECONDS); Collection secondResults = this.secondResults.poll(10, TimeUnit.SECONDS); Assert.assertNotNull(results); Assert.assertEquals(1, results.size()); Assert.assertEquals(1, secondResults.size()); FileChangeEvent res = results.iterator().next(); FileChangeEvent res2 = secondResults.iterator().next(); long endTime = System.currentTimeMillis() + 10000; while (type == REMOVED && (res.getType() == MODIFIED || res2.getType() == MODIFIED) && System.currentTimeMillis() < endTime) { //sometime OS's will give a MODIFIED event before the REMOVED one results = this.results.poll(1, TimeUnit.SECONDS); secondResults = this.secondResults.poll(1, TimeUnit.SECONDS); Assert.assertNotNull(results); Assert.assertNotNull(secondResults); Assert.assertEquals(1, results.size()); Assert.assertEquals(1, secondResults.size()); res = results.iterator().next(); res2 = secondResults.iterator().next(); } Assert.assertEquals(file, res.getFile()); Assert.assertEquals(type, res.getType()); Assert.assertEquals(file, res2.getFile()); Assert.assertEquals(type, res2.getType()); } public static void deleteRecursive(final File file) { File[] files = file.listFiles(); if (files != null) { for (File f : files) { deleteRecursive(f); } } file.delete(); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/FullDuplexChannelPipeTestCase.java000066400000000000000000000550641257016060700317570ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; import org.xnio.Buffers; import org.xnio.ChannelPipe; import org.xnio.Option; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.XnioWorker; import org.xnio.channels.StreamChannel; /** * Tests a full duplex channel pipe. * * @author Flavia Rainone * */ public class FullDuplexChannelPipeTestCase extends AbstractNioStreamChannelTest { // for a matter of code readability, it is better to name those channels channel1/channel2 in the super class // and create new fields in this subclass so we can use a more appropriate name here private StreamChannel leftChannel; private StreamChannel rightChannel; @Before public void initChannels() throws IOException { super.initChannels(); } @Override protected void initChannels(XnioWorker xnioWorker, OptionMap optionMap, TestChannelListener leftChannelListener, TestChannelListener rightChannelListener) throws IOException { if (leftChannel != null) { closeChannels(); } final ChannelPipe pipeChannel = xnioWorker.createFullDuplexPipe(); assertNotNull(pipeChannel); assertNotNull(pipeChannel.toString()); leftChannel = pipeChannel.getLeftSide(); rightChannel = pipeChannel.getRightSide(); assertNotNull(leftChannel); assertNotNull(leftChannel.toString()); assertNotNull(rightChannel); assertNotNull(rightChannel.toString()); leftChannelListener.handleEvent(leftChannel); rightChannelListener.handleEvent(rightChannel); } @Test public void writeAndReadBufferAndClose() throws IOException { final TestChannelListener leftWriteListener = new TestChannelListener(); final TestChannelListener rightWriteListener = new TestChannelListener(); leftChannel.getWriteSetter().set(leftWriteListener); rightChannel.getWriteSetter().set(rightWriteListener); // Step 1: communicate several times using a ByteBuffer final ByteBuffer buffer = ByteBuffer.allocate(5); buffer.put("12345".getBytes()).flip(); assertEquals(5, leftChannel.write(buffer)); buffer.clear(); assertEquals(5, rightChannel.read(buffer)); buffer.flip(); assertEquals("12345", Buffers.getModifiedUtf8(buffer)); buffer.clear(); buffer.put("67890".getBytes()).flip(); assertEquals(5, rightChannel.write(buffer)); buffer.clear(); assertEquals(5, leftChannel.read(buffer)); buffer.flip(); assertEquals("67890", Buffers.getModifiedUtf8(buffer)); assertFalse(leftChannel.isWriteResumed()); leftChannel.resumeWrites(); assertFalse(rightChannel.isWriteResumed()); rightChannel.resumeWrites(); assertFalse(leftChannel.isReadResumed()); leftChannel.resumeReads(); assertFalse(rightChannel.isReadResumed()); rightChannel.resumeReads(); assertTrue(leftWriteListener.isInvoked()); assertTrue(rightWriteListener.isInvoked()); // Step 2: close leftChannel leftChannel.close(); assertFalse(leftChannel.isWriteResumed()); assertFalse(leftChannel.isReadResumed()); Exception expected = null; try { leftChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); assertEquals(0, rightChannel.write(buffer)); buffer.flip(); expected = null; try { rightChannel.write(buffer); } catch(IOException e) { // broken pipe expected = e; } assertNotNull(expected); buffer.clear(); assertEquals(-1, leftChannel.read(buffer)); assertEquals(-1, rightChannel.read(buffer)); // Step 3: close rightChannel assertFalse(leftChannel.isOpen()); assertTrue(rightChannel.isOpen()); rightChannel.close(); assertFalse(leftChannel.isOpen()); assertFalse(rightChannel.isOpen()); assertFalse(rightChannel.isWriteResumed()); assertFalse(rightChannel.isReadResumed()); expected = null; try { leftChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { rightChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); buffer.clear(); assertEquals(-1, leftChannel.read(buffer)); assertEquals(-1, rightChannel.read(buffer)); // Step 4: idempotent close assertFalse(leftChannel.isOpen()); assertFalse(rightChannel.isOpen()); rightChannel.close(); leftChannel.close(); assertFalse(leftChannel.isOpen()); assertFalse(rightChannel.isOpen()); expected = null; try { leftChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { rightChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); buffer.clear(); assertEquals(-1, leftChannel.read(buffer)); assertEquals(-1, rightChannel.read(buffer)); // Step 5: shutdown read and write, should be idempotent leftChannel.shutdownReads(); leftChannel.shutdownWrites(); rightChannel.shutdownReads(); rightChannel.shutdownWrites(); assertFalse(leftChannel.isOpen()); assertFalse(rightChannel.isOpen()); expected = null; try { leftChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { rightChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); buffer.clear(); assertEquals(-1, leftChannel.read(buffer)); assertEquals(-1, rightChannel.read(buffer)); } @Test public void writeAndReadMultipleBuffersAndShutdown() throws IOException { final TestChannelListener leftWriteListener = new TestChannelListener(); final TestChannelListener rightWriteListener = new TestChannelListener(); final TestChannelListener leftReadListener = new TestChannelListener(); final TestChannelListener rightReadListener = new TestChannelListener(); leftChannel.getWriteSetter().set(leftWriteListener); rightChannel.getWriteSetter().set(rightWriteListener); leftChannel.getReadSetter().set(leftReadListener); rightChannel.getReadSetter().set(rightReadListener); // Step 1: communicate several times using a ByteBuffer[] final ByteBuffer[] buffers = new ByteBuffer[] {ByteBuffer.allocate(5), ByteBuffer.allocate(1), ByteBuffer.allocate(2)}; buffers[0].put("12345".getBytes()).flip(); buffers[1].put("6".getBytes()).flip(); buffers[2].put("78".getBytes()).flip(); assertEquals(8, leftChannel.write(buffers)); buffers[0].clear(); buffers[1].clear(); buffers[2].clear(); assertEquals(8, rightChannel.read(buffers)); buffers[0].flip(); assertEquals("12345", Buffers.getModifiedUtf8(buffers[0])); buffers[1].flip(); assertEquals('6', buffers[1].get(0)); buffers[2].flip(); assertEquals("78", Buffers.getModifiedUtf8(buffers[2])); buffers[0].clear(); buffers[0].put("09876".getBytes()).flip(); buffers[1].clear(); buffers[1].put("5".getBytes()).flip(); buffers[2].clear(); buffers[2].put("43".getBytes()).flip(); assertEquals(8, rightChannel.write(buffers)); buffers[0].clear(); buffers[1].clear(); buffers[2].clear(); assertEquals(8, leftChannel.read(buffers)); buffers[0].flip(); assertEquals("09876", Buffers.getModifiedUtf8(buffers[0])); buffers[1].flip(); assertEquals('5', buffers[1].get(0)); buffers[2].flip(); assertEquals("43", Buffers.getModifiedUtf8(buffers[2])); assertFalse(leftChannel.isWriteResumed()); leftChannel.resumeWrites(); assertFalse(rightChannel.isWriteResumed()); rightChannel.resumeWrites(); assertFalse(leftChannel.isReadResumed()); leftChannel.resumeReads(); assertFalse(rightChannel.isReadResumed()); rightChannel.resumeReads(); assertTrue(leftWriteListener.isInvoked()); assertTrue(rightWriteListener.isInvoked()); // Step 2: shutdownReads on rightChannel rightChannel.shutdownReads(); assertFalse(rightChannel.isReadResumed()); assertTrue(rightChannel.isWriteResumed()); assertTrue(leftChannel.isOpen()); assertTrue(rightChannel.isOpen()); rightChannel.awaitReadable(); rightChannel.awaitReadable(30, TimeUnit.SECONDS); assertEquals(1, rightChannel.write(buffers)); assertEquals(-1, rightChannel.read(buffers)); buffers[0].flip(); buffers[1].flip(); buffers[2].flip(); Exception expected = null; try { assertEquals(1, leftChannel.write(buffers)); } catch (IOException e) { // broken pipe expected = e; } assertNotNull(expected); buffers[0].clear(); buffers[1].clear(); buffers[2].clear(); assertEquals(1, leftChannel.read(buffers)); buffers[0].flip(); assertEquals('5', buffers[0].get(0)); // Step 3: shutdownWrites on leftChannel leftChannel.shutdownWrites(); assertTrue(leftChannel.isReadResumed()); assertFalse(leftChannel.isWriteResumed()); assertTrue(leftChannel.isOpen()); leftChannel.awaitWritable(); leftChannel.awaitWritable(1, TimeUnit.DAYS); expected = null; try { leftChannel.write(buffers); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); assertEquals(4, rightChannel.write(buffers)); buffers[0].clear(); buffers[1].clear(); buffers[2].clear(); assertEquals(4, leftChannel.read(buffers)); buffers[0].flip(); assertEquals("5543", Buffers.getModifiedUtf8(buffers[0])); buffers[1].flip(); assertFalse(buffers[1].hasRemaining()); buffers[2].flip(); assertFalse(buffers[2].hasRemaining()); assertEquals(-1, rightChannel.read(ByteBuffer.allocate(5))); // Step 4: shutdownWrites on rightChannel rightChannel.shutdownWrites(); assertFalse(rightChannel.isOpen()); assertFalse(rightChannel.isReadResumed()); assertFalse(rightChannel.isWriteResumed()); rightChannel.awaitWritable(); rightChannel.awaitWritable(1, TimeUnit.DAYS); buffers[0].flip(); expected = null; try { rightChannel.write(buffers); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { leftChannel.write(buffers); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); buffers[0].clear(); assertEquals(-1, rightChannel.read(buffers)); assertEquals(-1, leftChannel.read(buffers)); // Step 5: shutdownReads on leftChannel assertTrue(leftChannel.isOpen()); leftChannel.shutdownReads(); assertFalse(leftChannel.isOpen()); assertFalse(leftChannel.isReadResumed()); assertFalse(leftChannel.isWriteResumed()); leftChannel.awaitReadable(); leftChannel.awaitReadable(30, TimeUnit.SECONDS); expected = null; try { leftChannel.write(buffers); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { rightChannel.write(buffers); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); assertEquals(-1, leftChannel.read(buffers)); assertEquals(-1, rightChannel.read(buffers)); // Step 6: idempotent shutdown operations leftChannel.shutdownReads(); leftChannel.shutdownWrites(); rightChannel.shutdownReads(); rightChannel.shutdownWrites(); assertFalse(leftChannel.isOpen()); assertFalse(rightChannel.isOpen()); expected = null; try { rightChannel.write(buffers); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { leftChannel.write(buffers); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); assertEquals(-1, rightChannel.read(buffers)); assertEquals(-1, leftChannel.read(buffers)); // Step 7: close channels, should be idempotent leftChannel.close(); rightChannel.close(); assertFalse(leftChannel.isOpen()); assertFalse(rightChannel.isOpen()); expected = null; try { rightChannel.write(buffers); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { leftChannel.write(buffers); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); assertEquals(-1, rightChannel.read(buffers)); assertEquals(-1, leftChannel.read(buffers)); } @Test public void closePartiallyShutdownChannel() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(3); final TestChannelListener leftWriteListener = new TestChannelListener(); final TestChannelListener rightWriteListener = new TestChannelListener(); final TestChannelListener leftReadListener = new TestChannelListener(); final TestChannelListener rightReadListener = new TestChannelListener(); leftChannel.getWriteSetter().set(leftWriteListener); rightChannel.getWriteSetter().set(rightWriteListener); leftChannel.getReadSetter().set(leftReadListener); rightChannel.getReadSetter().set(rightReadListener); assertFalse(leftChannel.isWriteResumed()); leftChannel.resumeWrites(); assertFalse(rightChannel.isWriteResumed()); rightChannel.resumeWrites(); assertFalse(leftChannel.isReadResumed()); leftChannel.resumeReads(); assertFalse(rightChannel.isReadResumed()); rightChannel.resumeReads(); assertTrue(leftWriteListener.isInvoked()); assertTrue(rightWriteListener.isInvoked()); // Step 1: shutdownReads on leftChannel leftChannel.shutdownReads(); assertFalse(leftChannel.isReadResumed()); leftChannel.awaitReadable(); leftChannel.awaitReadable(10, TimeUnit.SECONDS); assertTrue(leftChannel.isWriteResumed()); assertTrue(leftChannel.isOpen()); assertTrue(rightChannel.isOpen()); assertEquals(3, leftChannel.write(buffer)); buffer.flip(); assertEquals(3, rightChannel.read(buffer)); buffer.flip(); Exception expected = null; try { rightChannel.write(buffer); } catch (IOException e) { // broken pipe expected = e; } assertNotNull(expected); buffer.clear(); assertEquals(-1, leftChannel.read(buffer)); // Step 2: shutdownWrites on rightChannel rightChannel.shutdownWrites(); assertTrue(rightChannel.isReadResumed()); assertFalse(rightChannel.isWriteResumed()); assertTrue(rightChannel.isOpen()); rightChannel.awaitWritable(); rightChannel.awaitWritable(1, TimeUnit.MINUTES); expected = null; try { rightChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); assertEquals(3, leftChannel.write(buffer)); buffer.clear(); assertEquals(3, rightChannel.read(buffer)); assertEquals(-1, leftChannel.read(ByteBuffer.allocate(5))); // Step 3: close leftChannel leftChannel.close(); assertFalse(leftChannel.isOpen()); assertFalse(leftChannel.isReadResumed()); assertFalse(leftChannel.isWriteResumed()); leftChannel.awaitReadable(); leftChannel.awaitReadable(10, TimeUnit.SECONDS); leftChannel.awaitWritable(); leftChannel.awaitWritable(1, TimeUnit.MINUTES); buffer.flip(); expected = null; try { leftChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { rightChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); assertEquals(-1, rightChannel.read(buffer)); assertEquals(-1, leftChannel.read(buffer)); // Step 4: close rightChannel assertTrue(rightChannel.isOpen()); rightChannel.close(); assertFalse(rightChannel.isOpen()); assertFalse(rightChannel.isReadResumed()); assertFalse(rightChannel.isWriteResumed()); rightChannel.awaitReadable(); rightChannel.awaitReadable(10, TimeUnit.SECONDS); rightChannel.awaitWritable(); rightChannel.awaitWritable(1, TimeUnit.MINUTES); expected = null; try { leftChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { rightChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); assertEquals(-1, leftChannel.read(buffer)); assertEquals(-1, rightChannel.read(buffer)); // Step 5: idempotent shutdown and close operations leftChannel.shutdownReads(); leftChannel.shutdownWrites(); rightChannel.shutdownReads(); rightChannel.shutdownWrites(); leftChannel.close(); rightChannel.close(); assertFalse(leftChannel.isOpen()); assertFalse(rightChannel.isOpen()); expected = null; try { rightChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { leftChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); assertEquals(-1, rightChannel.read(buffer)); assertEquals(-1, leftChannel.read(buffer)); } @Test public void optionSetup() throws IOException { initChannels(); final Option[] unsupportedOptions = OptionHelper.getNotSupportedOptions(Options.READ_TIMEOUT, Options.WRITE_TIMEOUT); for (Option option: unsupportedOptions) { assertFalse("Channel supports " + option, leftChannel.supportsOption(option)); assertNull("Expected null value for option " + option + " but got " + leftChannel.getOption(option) + " instead", leftChannel.getOption(option)); } assertTrue(leftChannel.supportsOption(Options.READ_TIMEOUT)); assertTrue(leftChannel.supportsOption(Options.WRITE_TIMEOUT)); leftChannel.setOption(Options.READ_TIMEOUT, 39710); leftChannel.setOption(Options.WRITE_TIMEOUT, 1301093); assertNull("Unexpected option value: " + leftChannel.getOption(Options.MAX_INBOUND_MESSAGE_SIZE), leftChannel.setOption(Options.MAX_INBOUND_MESSAGE_SIZE, 50000));// unsupported assertEquals(39710, (int) leftChannel.getOption(Options.READ_TIMEOUT)); assertEquals(1301093, (int) leftChannel.getOption(Options.WRITE_TIMEOUT)); assertNull(leftChannel.getOption(Options.MAX_INBOUND_MESSAGE_SIZE));// unsupported assertEquals(39710, (int) leftChannel.setOption(Options.READ_TIMEOUT, 70977010)); assertEquals(1301093, (int) leftChannel.setOption(Options.WRITE_TIMEOUT, 293265)); assertEquals(293265, (int) leftChannel.getOption(Options.WRITE_TIMEOUT)); assertEquals(70977010, (int) leftChannel.getOption(Options.READ_TIMEOUT)); // XNIO-171 test setOption(*, null)? } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/HalfDuplexChannelPipeTestCase.java000066400000000000000000000371031257016060700317210ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.util.concurrent.TimeUnit; import org.junit.Before; import org.junit.Test; import org.xnio.Buffers; import org.xnio.ChannelPipe; import org.xnio.Option; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.XnioWorker; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; /** * Tests a half duplex channel pipe. * * @author Flavia Rainone * */ public class HalfDuplexChannelPipeTestCase extends AbstractStreamSinkSourceChannelTest { @Override protected void initChannels(XnioWorker xnioWorker, OptionMap optionMap, TestChannelListener sinkChannelListener, TestChannelListener sourceChannelListener) throws IOException { final ChannelPipe pipeChannel = xnioWorker.createHalfDuplexPipe(); sinkChannelListener.handleEvent(pipeChannel.getRightSide()); sourceChannelListener.handleEvent(pipeChannel.getLeftSide()); } @Before public void initChannels() throws IOException { super.initChannels(); } @Test public void writeAndReadBufferAndClose() throws IOException { final TestChannelListener writeListener = new TestChannelListener(); sinkChannel.getWriteSetter().set(writeListener); // Step 1: communicate several times using a ByteBuffer final ByteBuffer buffer = ByteBuffer.allocate(5); buffer.put("12345".getBytes()).flip(); assertEquals(5, sinkChannel.write(buffer)); buffer.clear(); assertEquals(5, sourceChannel.read(buffer)); buffer.flip(); assertEquals("12345", Buffers.getModifiedUtf8(buffer)); buffer.clear(); buffer.put("67890".getBytes()).flip(); assertEquals(5, sinkChannel.write(buffer)); buffer.clear(); assertEquals(5, sourceChannel.read(buffer)); buffer.flip(); assertEquals("67890", Buffers.getModifiedUtf8(buffer)); assertFalse(sinkChannel.isWriteResumed()); sinkChannel.resumeWrites(); assertTrue(writeListener.isInvoked()); // Step 2: close sinkChannel sinkChannel.close(); assertFalse(sinkChannel.isWriteResumed()); Exception expected = null; try { sinkChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); buffer.clear(); assertEquals(-1, sourceChannel.read(buffer)); // Step 3: close sourceChannel assertFalse(sinkChannel.isOpen()); assertTrue(sourceChannel.isOpen()); sourceChannel.close(); assertFalse(sinkChannel.isOpen()); assertFalse(sourceChannel.isOpen()); assertFalse(sourceChannel.isReadResumed()); expected = null; try { sinkChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); buffer.clear(); assertEquals(-1, sourceChannel.read(buffer)); // Step 4: idempotent close assertFalse(sinkChannel.isOpen()); assertFalse(sourceChannel.isOpen()); sourceChannel.close(); sinkChannel.close(); assertFalse(sinkChannel.isOpen()); assertFalse(sourceChannel.isOpen()); expected = null; try { sinkChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); buffer.clear(); assertEquals(-1, sourceChannel.read(buffer)); // Step 5: shutdown read and write, should be idempotent sourceChannel.shutdownReads(); sinkChannel.shutdownWrites(); assertFalse(sinkChannel.isOpen()); assertFalse(sourceChannel.isOpen()); expected = null; try { sinkChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); buffer.clear(); assertEquals(-1, sourceChannel.read(buffer)); } @Test public void writeAndReadMultipleBuffersAndShutdown() throws IOException { final TestChannelListener writeListener = new TestChannelListener(); final TestChannelListener readListener = new TestChannelListener(); sinkChannel.getWriteSetter().set(writeListener); sourceChannel.getReadSetter().set(readListener); // Step 1: communicate several times using a ByteBuffer[] final ByteBuffer[] buffers = new ByteBuffer[] {ByteBuffer.allocate(5), ByteBuffer.allocate(1), ByteBuffer.allocate(2)}; buffers[0].put("12345".getBytes()).flip(); buffers[1].put("6".getBytes()).flip(); buffers[2].put("78".getBytes()).flip(); assertEquals(8, sinkChannel.write(buffers)); buffers[0].clear(); buffers[1].clear(); buffers[2].clear(); assertEquals(8, sourceChannel.read(buffers)); buffers[0].flip(); assertEquals("12345", Buffers.getModifiedUtf8(buffers[0])); buffers[1].flip(); assertEquals('6', buffers[1].get(0)); buffers[2].flip(); assertEquals("78", Buffers.getModifiedUtf8(buffers[2])); buffers[0].clear(); buffers[0].put("09876".getBytes()).flip(); buffers[1].clear(); buffers[1].put("5".getBytes()).flip(); buffers[2].clear(); buffers[2].put("43".getBytes()).flip(); assertEquals(8, sinkChannel.write(buffers)); buffers[0].clear(); buffers[1].clear(); buffers[2].clear(); assertEquals(8, sourceChannel.read(buffers)); buffers[0].flip(); assertEquals("09876", Buffers.getModifiedUtf8(buffers[0])); buffers[1].flip(); assertEquals('5', buffers[1].get(0)); buffers[2].flip(); assertEquals("43", Buffers.getModifiedUtf8(buffers[2])); assertTrue(sinkChannel.flush()); assertFalse(sinkChannel.isWriteResumed()); sinkChannel.resumeWrites(); assertFalse(sourceChannel.isReadResumed()); sourceChannel.resumeReads(); assertTrue(writeListener.isInvoked()); // Step 2: shutdownReads on sourceChannel sourceChannel.shutdownReads(); assertFalse(sourceChannel.isReadResumed()); assertFalse(sourceChannel.isOpen()); sourceChannel.awaitReadable(); sourceChannel.awaitReadable(30, TimeUnit.SECONDS); IOException expected = null; try { sinkChannel.write(buffers); } catch (IOException e) { // broken pipe expected = e; } assertNotNull(expected); assertEquals(-1, sourceChannel.read(buffers)); // Step 3: shutdownWrites on sinkChannel sinkChannel.shutdownWrites(); assertFalse(sinkChannel.isWriteResumed()); assertFalse(sinkChannel.isOpen()); sinkChannel.awaitWritable(); sinkChannel.awaitWritable(1, TimeUnit.DAYS); expected = null; try { sinkChannel.write(buffers); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); assertEquals(-1, sourceChannel.read(ByteBuffer.allocate(5))); // Step 4: idempotent shutdown operations sourceChannel.shutdownReads(); sinkChannel.shutdownWrites(); assertFalse(sinkChannel.isOpen()); assertFalse(sourceChannel.isOpen()); expected = null; try { sinkChannel.write(buffers); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); assertEquals(-1, sourceChannel.read(buffers)); // Step 5: close channels, should be idempotent sinkChannel.close(); sinkChannel.close(); assertFalse(sinkChannel.isOpen()); assertFalse(sourceChannel.isOpen()); expected = null; try { sinkChannel.write(buffers); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); assertEquals(-1, sourceChannel.read(buffers)); } @Test public void closeShutdownChannel() throws IOException { final ByteBuffer buffer = ByteBuffer.allocate(3); final TestChannelListener writeListener = new TestChannelListener(); final TestChannelListener readListener = new TestChannelListener(); sinkChannel.getWriteSetter().set(writeListener); sourceChannel.getReadSetter().set(readListener); assertFalse(sinkChannel.isWriteResumed()); sinkChannel.resumeWrites(); assertFalse(sourceChannel.isReadResumed()); sourceChannel.resumeReads(); assertTrue(writeListener.isInvoked()); // Step 1: shutdownReads on sourceChannel sourceChannel.shutdownReads(); assertFalse(sourceChannel.isReadResumed()); sourceChannel.awaitReadable(); sourceChannel.awaitReadable(10, TimeUnit.SECONDS); assertFalse(sourceChannel.isOpen()); assertTrue(sinkChannel.isOpen()); IOException expected = null; try { sinkChannel.write(buffer); } catch (IOException e) { // broken pipe expected = e; } assertNotNull(expected); buffer.flip(); assertEquals(-1, sourceChannel.read(buffer)); // Step 2: shutdownWrites on sinkChannel sinkChannel.shutdownWrites(); assertFalse(sinkChannel.isWriteResumed()); assertFalse(sinkChannel.isOpen()); sinkChannel.awaitWritable(); sinkChannel.awaitWritable(1, TimeUnit.MINUTES); expected = null; try { sinkChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); assertEquals(-1, sourceChannel.read(ByteBuffer.allocate(5))); // Step 3: close sinkChannel (idempotent) sinkChannel.close(); assertFalse(sinkChannel.isOpen()); assertFalse(sinkChannel.isWriteResumed()); sinkChannel.awaitWritable(); sinkChannel.awaitWritable(1, TimeUnit.MINUTES); buffer.flip(); expected = null; try { sinkChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); assertEquals(-1, sourceChannel.read(buffer)); // Step 4: close sourceChannel (idempotent) assertFalse(sourceChannel.isOpen()); sourceChannel.close(); assertFalse(sourceChannel.isOpen()); assertFalse(sourceChannel.isReadResumed()); sourceChannel.awaitReadable(); sourceChannel.awaitReadable(10, TimeUnit.SECONDS); expected = null; try { sinkChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); assertEquals(-1, sourceChannel.read(buffer)); // Step 5: idempotent shutdown and close operations sinkChannel.shutdownWrites(); sourceChannel.shutdownReads(); sinkChannel.close(); sourceChannel.close(); assertFalse(sinkChannel.isOpen()); assertFalse(sourceChannel.isOpen()); expected = null; try { sinkChannel.write(buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); assertEquals(-1, sourceChannel.read(buffer)); } @Test public void sinkChannelOptionSetup() throws IOException { initChannels(); final Option[] unsupportedOptions = OptionHelper.getNotSupportedOptions(Options.WRITE_TIMEOUT); for (Option option: unsupportedOptions) { assertFalse("Channel supports " + option, sinkChannel.supportsOption(option)); assertNull("Expected null value for option " + option + " but got " + sinkChannel.getOption(option) + " instead", sinkChannel.getOption(option)); } assertTrue(sinkChannel.supportsOption(Options.WRITE_TIMEOUT)); sinkChannel.setOption(Options.WRITE_TIMEOUT, 1301093); assertNull("Unexpected option value: " + sinkChannel.getOption(Options.MAX_INBOUND_MESSAGE_SIZE), sinkChannel.setOption(Options.MAX_INBOUND_MESSAGE_SIZE, 50000));// unsupported assertEquals(1301093, (int) sinkChannel.getOption(Options.WRITE_TIMEOUT)); assertNull(sinkChannel.getOption(Options.MAX_INBOUND_MESSAGE_SIZE));// unsupported assertEquals(1301093, (int) sinkChannel.setOption(Options.WRITE_TIMEOUT, 293265)); assertEquals(293265, (int) sinkChannel.getOption(Options.WRITE_TIMEOUT)); // TODO XNIO-171 test setOption(*, null)? } @Test public void sourceChannelOptionSetup() throws IOException { initChannels(); final Option[] unsupportedOptions = OptionHelper.getNotSupportedOptions(Options.READ_TIMEOUT); for (Option option: unsupportedOptions) { assertFalse("Channel supports " + option, sourceChannel.supportsOption(option)); assertNull("Expected null value for option " + option + " but got " + sourceChannel.getOption(option) + " instead", sourceChannel.getOption(option)); } assertTrue(sourceChannel.supportsOption(Options.READ_TIMEOUT)); sourceChannel.setOption(Options.READ_TIMEOUT, 293265); assertNull("Unexpected option value: " + sourceChannel.getOption(Options.MAX_INBOUND_MESSAGE_SIZE), sourceChannel.setOption(Options.MAX_OUTBOUND_MESSAGE_SIZE, 50000));// unsupported assertEquals(293265, (int) sourceChannel.getOption(Options.READ_TIMEOUT)); assertNull(sourceChannel.getOption(Options.MAX_OUTBOUND_MESSAGE_SIZE));// unsupported assertEquals(293265, (int) sourceChannel.setOption(Options.READ_TIMEOUT, 1301093)); assertEquals(1301093, (int) sourceChannel.getOption(Options.READ_TIMEOUT)); // TODO XNIO-171 test setOption(*, null)? } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/IllegalConnectionTestCase.java000066400000000000000000000217521257016060700311520ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertNotNull; import java.io.IOException; import java.net.Inet4Address; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.concurrent.TimeUnit; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.StreamConnection; import org.xnio.Xnio; import org.xnio.XnioWorker; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.ConnectedStreamChannel; /** * Test case for scenarios where an attempt to perform an illegal connection is made. * * @author Flavia Rainone * */ @SuppressWarnings("deprecation") public class IllegalConnectionTestCase { private static SocketAddress bindAddress; private static XnioWorker worker; @BeforeClass public static void createWorker() throws IOException { final Xnio xnio = Xnio.getInstance("nio", IllegalConnectionTestCase.class.getClassLoader()); worker = xnio.createWorker(OptionMap.create(Options.WORKER_WRITE_THREADS, 3, Options.WORKER_READ_THREADS, 4)); bindAddress = new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), 12345); } @AfterClass public static void destroyWorker() throws InterruptedException { worker.shutdown(); worker.awaitTermination(1L, TimeUnit.MINUTES); } @Test public void illegalAcceptThreads() throws IOException { IllegalArgumentException expected; final Xnio xnio = Xnio.getInstance("nio", getClass().getClassLoader()); final XnioWorker zeroThreadWorker = xnio.createWorker(OptionMap.create(Options.WORKER_IO_THREADS, 0)); expected = null; try { zeroThreadWorker.createStreamConnectionServer(bindAddress, null, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, true)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { zeroThreadWorker.createStreamConnectionServer(bindAddress, null, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, false)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { zeroThreadWorker.createStreamServer(bindAddress, null, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, true)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { zeroThreadWorker.createStreamServer(bindAddress, null, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, false)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void illegalReceiveBufferSize() throws IOException { IllegalArgumentException expected = null; try { worker.createStreamConnectionServer(bindAddress, null, OptionMap.create(Options.RECEIVE_BUFFER, 0)); } catch (IllegalArgumentException e) { e.printStackTrace(); expected = e; } assertNotNull(expected); expected = null; try { worker.createStreamConnectionServer(bindAddress, null, OptionMap.create(Options.RECEIVE_BUFFER, -1)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { worker.createStreamServer(bindAddress, null, OptionMap.create(Options.RECEIVE_BUFFER, 0)); } catch (IllegalArgumentException e) { e.printStackTrace(); expected = e; } assertNotNull(expected); expected = null; try { worker.createStreamServer(bindAddress, null, OptionMap.create(Options.RECEIVE_BUFFER, -1)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void illegalLowWaterMark() throws IOException { IllegalArgumentException expected = null; try { worker.createStreamConnectionServer(bindAddress, null, OptionMap.create(Options.CONNECTION_HIGH_WATER, 2, Options.CONNECTION_LOW_WATER, 3)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { worker.createStreamConnectionServer(bindAddress, null, OptionMap.create(Options.CONNECTION_LOW_WATER, -1)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { worker.createStreamServer(bindAddress, null, OptionMap.create(Options.CONNECTION_HIGH_WATER, 2, Options.CONNECTION_LOW_WATER, 3)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { worker.createStreamServer(bindAddress, null, OptionMap.create(Options.CONNECTION_LOW_WATER, -1)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void illegalHighWaterMark() throws IOException { IllegalArgumentException expected = null; try { worker.createStreamConnectionServer(bindAddress, null, OptionMap.create(Options.CONNECTION_HIGH_WATER, -1)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { worker.createStreamServer(bindAddress, null, OptionMap.create(Options.CONNECTION_HIGH_WATER, -1)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void illegalSendBufferSize() throws IOException { IllegalArgumentException expected = null; try { worker.createStreamConnectionServer(bindAddress, null, OptionMap.create(Options.SEND_BUFFER, 0)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { worker.createStreamConnectionServer(bindAddress, null, OptionMap.create(Options.SEND_BUFFER, -2)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); final AcceptingChannel server = worker.createStreamConnectionServer(bindAddress, null, OptionMap.EMPTY); expected = null; try { server.setOption(Options.SEND_BUFFER, 0); } catch (IllegalArgumentException e) { expected = e; } server.close(); assertNotNull(expected); expected = null; try { server.setOption(Options.SEND_BUFFER, -5); } catch (IllegalArgumentException e) { expected = e; } server.close(); assertNotNull(expected); expected = null; try { worker.createStreamServer(bindAddress, null, OptionMap.create(Options.SEND_BUFFER, 0)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { worker.createStreamServer(bindAddress, null, OptionMap.create(Options.SEND_BUFFER, -2)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); final AcceptingChannel serverChannel = worker.createStreamServer(bindAddress, null, OptionMap.EMPTY); expected = null; try { serverChannel.setOption(Options.SEND_BUFFER, 0); } catch (IllegalArgumentException e) { expected = e; } serverChannel.close(); assertNotNull(expected); expected = null; try { serverChannel.setOption(Options.SEND_BUFFER, -5); } catch (IllegalArgumentException e) { expected = e; } serverChannel.close(); assertNotNull(expected); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/MultiThreadedNioSslTcpChannelTestCase.java000066400000000000000000000020061257016060700333730ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio.test; import org.junit.Before; /** * Runs NioSslTcpChannelTestCase with 5 I/O threads. * * @author Flavia Rainone * */ public class MultiThreadedNioSslTcpChannelTestCase extends NioSslTcpChannelTestCase { @Before public void setThreads() { super.setNumberOfThreads(5); } } MultiThreadedNioSslTcpConnectionTestCase.java000066400000000000000000000020171257016060700340450ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio.test; import org.junit.Before; /** * Runs NioSslTcpConnectionTestCase with 3 I/O threads. * * @author Flavia Rainone * */ public class MultiThreadedNioSslTcpConnectionTestCase extends NioSslTcpConnectionTestCase { @Before public void setThreads() { super.setNumberOfThreads(3); } } MultiThreadedNioStartTLSTcpChannelTestCase.java000066400000000000000000000020251257016060700342340ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio.test; import org.junit.Before; /** * Runs NioStartTLSTcpChannelTestCase with 4 I/O threads. * * @author Flavia Rainone * */ public class MultiThreadedNioStartTLSTcpChannelTestCase extends NioStartTLSTcpChannelTestCase { @Before public void setThreads() { super.setNumberOfThreads(4); } } MultiThreadedNioStartTLSTcpConnectionTestCase.java000066400000000000000000000020361257016060700347650ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio.test; import org.junit.Before; /** * Runs NioStartTLSTcpConnectionTestCase with 6 I/O threads. * * @author Flavia Rainone * */ public class MultiThreadedNioStartTLSTcpConnectionTestCase extends NioStartTLSTcpConnectionTestCase { @Before public void setThreads() { super.setNumberOfThreads(6); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/MultiThreadedNioTcpChannelTestCase.java000066400000000000000000000017751257016060700327250ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio.test; import org.junit.Before; /** * Runs NioTcpChannelTestCase with 5 I/O threads. * * @author Flavia Rainone * */ public class MultiThreadedNioTcpChannelTestCase extends NioTcpChannelTestCase { @Before public void setThreads() { super.setNumberOfThreads(5); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/MultiThreadedNioTcpConnectionTestCase.java000066400000000000000000000020061257016060700334400ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio.test; import org.junit.Before; /** * Runs NioTcpConnectionTestCase with 3 I/O threads. * * @author Flavia Rainone * */ public class MultiThreadedNioTcpConnectionTestCase extends NioTcpConnectionTestCase { @Before public void setThreads() { super.setNumberOfThreads(3); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/NioFullDuplexChannelPipeTestCase.java000066400000000000000000000503041257016060700324150ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertEquals; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.atomic.AtomicInteger; import org.jboss.logging.Logger; import org.junit.Test; import org.xnio.ChannelListener; import org.xnio.ChannelPipe; import org.xnio.IoUtils; import org.xnio.Options; import org.xnio.XnioWorker; import org.xnio.channels.StreamChannel; /** * Test for full duplex channel pipe usage. * * @author Flavia Rainone */ public final class NioFullDuplexChannelPipeTestCase extends AbstractNioChannelPipeTest { private static final Logger log = Logger.getLogger("TEST"); @Override protected ChannelPipe createPipeChannel(XnioWorker worker) throws IOException { return worker.createFullDuplexPipe(); } @Test public void leftChannelClose() throws Exception { log.info("Test: leftChannelClose"); final CountDownLatch latch = new CountDownLatch(4); doConnectionTest(new LatchAwaiter(latch), new ChannelListener() { public void handleEvent(final StreamChannel channel) { log.info("In pipe creation, leftChannel setup"); try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { log.info("In left channel close"); latch.countDown(); } }); channel.close(); leftChannelOK.set(true); latch.countDown(); } catch (Throwable t) { log.error("In left channel", t); latch.countDown(); throw new RuntimeException(t); } } }, new ChannelListener() { public void handleEvent(final StreamChannel channel) { log.info("In pipe creation, rightChannel setup"); channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { log.info("In right channel close"); latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { log.info("In right channel readable"); try { final int c = channel.read(ByteBuffer.allocate(100)); if (c == -1) { rightChannelOK.set(true); } channel.close(); } catch (IOException e) { throw new RuntimeException(e); } latch.countDown(); } }); channel.resumeReads(); } }); } @Test public void rightChannelClose() throws Exception { log.info("Test: rightChannelClose"); final CountDownLatch latch = new CountDownLatch(2); doConnectionTest(new LatchAwaiter(latch), new ChannelListener() { public void handleEvent(final StreamChannel channel) { try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { try { final int c = channel.read(ByteBuffer.allocate(100)); if (c == -1) { leftChannelOK.set(true); channel.close(); return; } // retry return; } catch (IOException e) { throw new RuntimeException(e); } } }); channel.resumeReads(); } catch (Throwable t) { try { channel.close(); } catch (Throwable t2) { log.errorf(t2, "Failed to close channel (propagating as RT exception)"); latch.countDown(); throw new RuntimeException(t); } throw new RuntimeException(t); } } }, new ChannelListener() { public void handleEvent(final StreamChannel channel) { try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { rightChannelOK.set(true); latch.countDown(); } }); channel.close(); } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); latch.countDown(); throw new RuntimeException(t); } } }); } @Test public void twoWayTransfer() throws Exception { log.info("Test: twoWayTransfer"); final CountDownLatch latch = new CountDownLatch(2); final AtomicInteger leftChannelSent = new AtomicInteger(0); final AtomicInteger leftChannelReceived = new AtomicInteger(0); final AtomicInteger rightChannelSent = new AtomicInteger(0); final AtomicInteger rightChannelReceived = new AtomicInteger(0); doConnectionTest(new LatchAwaiter(latch), new ChannelListener() { public void handleEvent(final StreamChannel channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { try { int c; while ((c = channel.read(ByteBuffer.allocate(100))) > 0) { leftChannelReceived.addAndGet(c); } if (c == -1) { channel.shutdownReads(); } } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }); final ByteBuffer buffer = ByteBuffer.allocate(100); try { buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } channel.getWriteSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { try { int c; while ((c = channel.write(buffer)) > 0) { if (leftChannelSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final StreamChannel channel) { try { channel.shutdownWrites(); } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } buffer.rewind(); } } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }); channel.resumeReads(); channel.resumeWrites(); } }, new ChannelListener() { public void handleEvent(final StreamChannel channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { try { int c; while ((c = channel.read(ByteBuffer.allocate(100))) > 0) { rightChannelReceived.addAndGet(c); } if (c == -1) { channel.shutdownReads(); } } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }); final ByteBuffer buffer = ByteBuffer.allocate(100); try { buffer.put("This Is A Test Gumma\r\n".getBytes("UTF-8")).flip(); } catch (UnsupportedEncodingException e) { throw new RuntimeException(e); } channel.getWriteSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { try { int c; while ((c = channel.write(buffer)) > 0) { if (rightChannelSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final StreamChannel channel) { try { channel.shutdownWrites(); } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } buffer.rewind(); } } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); throw new RuntimeException(t); } } }); channel.resumeReads(); channel.resumeWrites(); } }); assertEquals(rightChannelSent.get(), leftChannelReceived.get()); assertEquals(leftChannelSent.get(), rightChannelReceived.get()); leftChannelOK.set(true); rightChannelOK.set(true); } @Test public void leftChannelNastyClose() throws Exception { log.info("Test: leftChannelNastyClose"); final CountDownLatch latch = new CountDownLatch(2); doConnectionTest(new LatchAwaiter(latch), new ChannelListener() { public void handleEvent(final StreamChannel channel) { try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { latch.countDown(); } }); channel.setOption(Options.CLOSE_ABORT, Boolean.TRUE); channel.close(); leftChannelOK.set(true); } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); latch.countDown(); throw new RuntimeException(t); } } }, new ChannelListener() { public void handleEvent(final StreamChannel channel) { try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { int res; try { res = channel.read(ByteBuffer.allocate(100)); } catch (IOException e) { IoUtils.safeClose(channel); return; } if (res == -1) { rightChannelOK.set(true); IoUtils.safeClose(channel); } } }); channel.resumeReads(); } catch (Throwable t) { log.errorf(t, "Failed to close channel (propagating as RT exception)"); latch.countDown(); throw new RuntimeException(t); } } }); } @Test public void rightChannelNastyClose() throws Exception { log.info("Test: rightChannelNastyClose"); final CountDownLatch latch = new CountDownLatch(2); final CountDownLatch rightChannelLatch = new CountDownLatch(1); doConnectionTest(new LatchAwaiter(latch), new ChannelListener() { public void handleEvent(final StreamChannel channel) { try { log.info("Left channel opened"); channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { int res; try { res = channel.read(ByteBuffer.allocate(100)); } catch (IOException e) { IoUtils.safeClose(channel); return; } if (res == -1) { leftChannelOK.set(true); IoUtils.safeClose(channel); } } }); channel.getWriteSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { try { if (channel.write(ByteBuffer.wrap(new byte[] { 1 })) > 0) { channel.suspendWrites(); } } catch (IOException e) { IoUtils.safeClose(channel); } } }); channel.resumeReads(); channel.resumeWrites(); rightChannelLatch.countDown(); } catch (Throwable t) { log.error("Error occurred on client", t); try { channel.close(); } catch (Throwable t2) { log.error("Error occurred on client (close)", t2); latch.countDown(); throw new RuntimeException(t); } throw new RuntimeException(t); } } }, new ChannelListener() { public void handleEvent(final StreamChannel channel) { try { log.info("Right channel opened"); channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final StreamChannel channel) { try { if (channel.read(ByteBuffer.allocate(1)) > 0) { log.info("Closing connection..."); channel.setOption(Options.CLOSE_ABORT, Boolean.TRUE); channel.close(); rightChannelOK.set(true); } } catch (IOException e) { IoUtils.safeClose(channel); } } }); channel.resumeReads(); } catch (Throwable t) { log.error("Error occurred on server", t); latch.countDown(); throw new RuntimeException(t); } } }); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/NioHalfDuplexChannelPipeTestCase.java000066400000000000000000000032251257016060700323650ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xnio.nio.test; import java.io.IOException; import org.xnio.ChannelPipe; import org.xnio.XnioWorker; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; /** * Test for half duplex channel pipe usage. * * @author Flavia Rainone */ public class NioHalfDuplexChannelPipeTestCase extends AbstractNioChannelPipeTest { @Override protected ChannelPipe createPipeChannel(XnioWorker worker) throws IOException { return worker.createHalfDuplexPipe(); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/NioSslTcpChannelTestCase.java000066400000000000000000000747771257016060700307470ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.InetSocketAddress; import java.net.URL; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import org.junit.BeforeClass; import org.xnio.ChannelListener; import org.xnio.IoFuture; import org.xnio.OptionMap; import org.xnio.Xnio; import org.xnio.XnioWorker; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.BoundChannel; import org.xnio.channels.Channels; import org.xnio.channels.ConnectedSslStreamChannel; import org.xnio.channels.ConnectedStreamChannel; import org.xnio.ssl.XnioSsl; /** * Test for {@code XnioSsl} channels. * * @author Flavia Rainone * */ public class NioSslTcpChannelTestCase extends AbstractNioTcpTest { private XnioSsl xnioSsl; private static final String KEY_STORE_PROPERTY = "javax.net.ssl.keyStore"; private static final String KEY_STORE_PASSWORD_PROPERTY = "javax.net.ssl.keyStorePassword"; private static final String TRUST_STORE_PROPERTY = "javax.net.ssl.trustStore"; private static final String TRUST_STORE_PASSWORD_PROPERTY = "javax.net.ssl.trustStorePassword"; private static final String DEFAULT_KEY_STORE = "keystore.jks"; private static final String DEFAULT_KEY_STORE_PASSWORD = "jboss-remoting-test"; @BeforeClass public static void setKeyStoreAndTrustStore() { final URL storePath = NioSslTcpChannelTestCase.class.getClassLoader().getResource(DEFAULT_KEY_STORE); if (System.getProperty(KEY_STORE_PROPERTY) == null) { System.setProperty(KEY_STORE_PROPERTY, storePath.getFile()); } if (System.getProperty(KEY_STORE_PASSWORD_PROPERTY) == null) { System.setProperty(KEY_STORE_PASSWORD_PROPERTY, DEFAULT_KEY_STORE_PASSWORD); } if (System.getProperty(TRUST_STORE_PROPERTY) == null) { System.setProperty(TRUST_STORE_PROPERTY, storePath.getFile()); } if (System.getProperty(TRUST_STORE_PASSWORD_PROPERTY) == null) { System.setProperty(TRUST_STORE_PASSWORD_PROPERTY, DEFAULT_KEY_STORE_PASSWORD); } } @SuppressWarnings("deprecation") @Override protected AcceptingChannel createServer(XnioWorker worker, InetSocketAddress address, ChannelListener> openListener, OptionMap optionMap) throws IOException { return xnioSsl.createSslTcpServer(worker, address, openListener, optionMap); } @SuppressWarnings("deprecation") @Override protected IoFuture connect(XnioWorker worker, InetSocketAddress address, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { return xnioSsl.connectSsl(worker, address, openListener, bindListener, optionMap); } @Override protected void setReadListener(ConnectedSslStreamChannel channel, ChannelListener readListener) { channel.getReadSetter().set(readListener); } @Override protected void setWriteListener(ConnectedSslStreamChannel channel, ChannelListener writeListener) { channel.getWriteSetter().set(writeListener); } @Override protected void resumeReads(ConnectedSslStreamChannel channel) { channel.resumeReads(); } @Override protected void resumeWrites(ConnectedSslStreamChannel channel) { channel.resumeWrites(); } @Override protected void doConnectionTest(final Runnable body, final ChannelListener clientHandler, final ChannelListener serverHandler) throws Exception { xnioSsl = Xnio.getInstance("nio", NioSslTcpChannelTestCase.class.getClassLoader()).getSslProvider(OptionMap.EMPTY); super.doConnectionTest(body, clientHandler, serverHandler); } @Override public void clientClose() throws Exception { log.info("Test: clientClose"); final CountDownLatch latch = new CountDownLatch(4); final AtomicBoolean clientOK = new AtomicBoolean(false); final AtomicBoolean serverOK = new AtomicBoolean(false); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { log.info("In client open"); try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { log.info("In client close"); latch.countDown(); } }); Channels.shutdownWritesBlocking(channel); int c = Channels.readBlocking(channel, ByteBuffer.allocate(100)); channel.close(); if (c == -1) { clientOK.set(true); } latch.countDown(); } catch (Throwable t) { log.error("In client", t); latch.countDown(); throw new RuntimeException(t); } } }, new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { log.info("In server opened"); channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { log.info("In server close"); latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { log.info("In server readable"); try { Channels.shutdownWritesBlocking(channel); int c = Channels.readBlocking(channel, ByteBuffer.allocate(100)); channel.close(); if (c == -1) { serverOK.set(true); } } catch (IOException e) { throw new RuntimeException(e); } latch.countDown(); } }); channel.resumeReads(); } }); assertTrue(serverOK.get()); assertTrue(clientOK.get()); } @Override public void oneWayTransfer1() throws Exception { log.info("Test: oneWayTransfer"); final CountDownLatch latch = new CountDownLatch(2); final AtomicInteger clientSent = new AtomicInteger(0); final AtomicInteger serverReceived = new AtomicInteger(0); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500000L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { latch.countDown(); } }); channel.getWriteSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); int c; try { while ((c = channel.write(buffer)) > 0) { if (clientSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { if (channel.flush()) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { // really lame, but due to the way SSL shuts down... if (serverReceived.get() == clientSent.get()) { try { channel.shutdownWrites(); channel.close(); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } buffer.rewind(); } } catch (ClosedChannelException e) { channel.shutdownWrites(); throw e; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); channel.resumeWrites(); } }, new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { int c; while ((c = channel.read(ByteBuffer.allocate(100))) > 0) { serverReceived.addAndGet(c); } if (c == -1) { channel.shutdownReads(); channel.close(); } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); channel.resumeReads(); } }); assertEquals(clientSent.get(), serverReceived.get()); } @Override public void oneWayTransfer2() throws Exception { log.info("Test: oneWayTransfer2"); final CountDownLatch latch = new CountDownLatch(2); final AtomicInteger clientReceived = new AtomicInteger(0); final AtomicInteger serverSent = new AtomicInteger(0); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500000L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { int c; while ((c = channel.read(ByteBuffer.allocate(100))) > 0) { clientReceived.addAndGet(c); } if (c == -1) { channel.shutdownReads(); channel.close(); } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); channel.resumeReads(); } }, new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { latch.countDown(); } }); channel.getWriteSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); int c; try { while ((c = channel.write(buffer)) > 0) { if (serverSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { if (channel.flush()) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { // really lame, but due to the way SSL shuts down... if (clientReceived.get() == serverSent.get()) { try { channel.shutdownWrites(); channel.close(); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } buffer.rewind(); } } catch (ClosedChannelException e) { channel.shutdownWrites(); throw e; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); channel.resumeWrites(); } }); assertEquals(serverSent.get(), clientReceived.get()); } @Override public void twoWayTransfer() throws Exception { log.info("Test: twoWayTransfer"); final CountDownLatch latch = new CountDownLatch(2); final AtomicInteger clientSent = new AtomicInteger(0); final AtomicInteger clientReceived = new AtomicInteger(0); final AtomicInteger serverSent = new AtomicInteger(0); final AtomicInteger serverReceived = new AtomicInteger(0); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500000L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { int c; while ((c = channel.read(ByteBuffer.allocate(100))) > 0) { clientReceived.addAndGet(c); } if (c == -1) { channel.shutdownReads(); } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); channel.getWriteSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); int c; try { while ((c = channel.write(buffer)) > 0) { if (clientSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { if (channel.flush()) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { // really lame, but due to the way SSL shuts down... if (clientReceived.get() == serverSent.get() && serverReceived.get() == clientSent.get() && serverSent.get() > 1000) { try { channel.close(); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } buffer.rewind(); } } catch (ClosedChannelException e) { channel.shutdownWrites(); throw e; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); channel.resumeReads(); channel.resumeWrites(); } }, new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { int c; while ((c = channel.read(ByteBuffer.allocate(100))) > 0) { serverReceived.addAndGet(c); } if (c == -1) { channel.shutdownReads(); } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); channel.getWriteSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); int c; try { while ((c = channel.write(buffer)) > 0) { if (serverSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { if (channel.flush()) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { // really lame, but due to the way SSL shuts down... if (clientReceived.get() == serverSent.get() && serverReceived.get() == clientSent.get() && clientSent.get() > 1000) { try { channel.close(); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } buffer.rewind(); } } catch (ClosedChannelException e) { channel.shutdownWrites(); throw e; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); channel.resumeReads(); channel.resumeWrites(); } }); assertEquals(serverSent.get(), clientReceived.get()); assertEquals(clientSent.get(), serverReceived.get()); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/NioSslTcpConnectionTestCase.java000066400000000000000000001007761257016060700314630ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source * * Copyright 2013 Red Hat, Inc. and/or its affiliates. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.InetSocketAddress; import java.net.URL; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import org.junit.BeforeClass; import org.xnio.ChannelListener; import org.xnio.IoFuture; import org.xnio.OptionMap; import org.xnio.StreamConnection; import org.xnio.Xnio; import org.xnio.XnioWorker; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.BoundChannel; import org.xnio.channels.Channels; import org.xnio.ssl.SslConnection; import org.xnio.conduits.ConduitStreamSinkChannel; import org.xnio.conduits.ConduitStreamSourceChannel; import org.xnio.ssl.XnioSsl; /** * Test for {@code XnioSsl} connections. * * @author Flavia Rainone * */ public class NioSslTcpConnectionTestCase extends AbstractNioTcpTest{ private XnioSsl xnioSsl; private static final String KEY_STORE_PROPERTY = "javax.net.ssl.keyStore"; private static final String KEY_STORE_PASSWORD_PROPERTY = "javax.net.ssl.keyStorePassword"; private static final String TRUST_STORE_PROPERTY = "javax.net.ssl.trustStore"; private static final String TRUST_STORE_PASSWORD_PROPERTY = "javax.net.ssl.trustStorePassword"; private static final String DEFAULT_KEY_STORE = "keystore.jks"; private static final String DEFAULT_KEY_STORE_PASSWORD = "jboss-remoting-test"; @BeforeClass public static void setKeyStoreAndTrustStore() { final URL storePath = NioSslTcpChannelTestCase.class.getClassLoader().getResource(DEFAULT_KEY_STORE); if (System.getProperty(KEY_STORE_PROPERTY) == null) { System.setProperty(KEY_STORE_PROPERTY, storePath.getFile()); } if (System.getProperty(KEY_STORE_PASSWORD_PROPERTY) == null) { System.setProperty(KEY_STORE_PASSWORD_PROPERTY, DEFAULT_KEY_STORE_PASSWORD); } if (System.getProperty(TRUST_STORE_PROPERTY) == null) { System.setProperty(TRUST_STORE_PROPERTY, storePath.getFile()); } if (System.getProperty(TRUST_STORE_PASSWORD_PROPERTY) == null) { System.setProperty(TRUST_STORE_PASSWORD_PROPERTY, DEFAULT_KEY_STORE_PASSWORD); } } @Override protected AcceptingChannel createServer(XnioWorker worker, InetSocketAddress address, ChannelListener> openListener, OptionMap optionMap) throws IOException { return xnioSsl.createSslConnectionServer(worker, address, openListener, optionMap); } @Override protected IoFuture connect(XnioWorker worker, InetSocketAddress address, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { return xnioSsl.openSslConnection(worker, address, openListener, bindListener, optionMap); } @Override protected void setReadListener(SslConnection connection, ChannelListener readListener) { connection.getSourceChannel().setReadListener(readListener); } @Override protected void setWriteListener(SslConnection connection, ChannelListener writeListener) { connection.getSinkChannel().setWriteListener(writeListener); } @Override protected void resumeReads(SslConnection connection) { connection.getSourceChannel().resumeReads(); } @Override protected void resumeWrites(SslConnection connection) { connection.getSinkChannel().resumeWrites(); } @Override protected void doConnectionTest(final Runnable body, final ChannelListener clientHandler, final ChannelListener serverHandler) throws Exception { xnioSsl = Xnio.getInstance("nio", NioSslTcpChannelTestCase.class.getClassLoader()).getSslProvider(OptionMap.EMPTY); super.doConnectionTest(body, clientHandler, serverHandler); } @Override public void clientClose() throws Exception { log.info("Test: clientClose"); final CountDownLatch latch = new CountDownLatch(4); final AtomicBoolean clientOK = new AtomicBoolean(false); final AtomicBoolean serverOK = new AtomicBoolean(false); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final SslConnection connection) { log.info("In client open"); try { connection.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamConnection connection) { log.info("In client close"); latch.countDown(); } }); Channels.shutdownWritesBlocking(connection.getSinkChannel()); int c = Channels.readBlocking(connection.getSourceChannel(), ByteBuffer.allocate(100)); connection.close(); if (c == -1) { clientOK.set(true); } latch.countDown(); } catch (Throwable t) { log.error("In client", t); latch.countDown(); throw new RuntimeException(t); } } }, new ChannelListener() { public void handleEvent(final SslConnection connection) { log.info("In server opened"); connection.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamConnection connection) { log.info("In server close"); latch.countDown(); } }); final ConduitStreamSourceChannel sourceChannel = connection.getSourceChannel(); sourceChannel.setReadListener(new ChannelListener() { public void handleEvent(final ConduitStreamSourceChannel sourceChannel) { log.info("In server readable"); try { Channels.shutdownWritesBlocking(connection.getSinkChannel()); int c = Channels.readBlocking(sourceChannel, ByteBuffer.allocate(100)); connection.close(); if (c == -1) { serverOK.set(true); } } catch (IOException e) { throw new RuntimeException(e); } latch.countDown(); } }); sourceChannel.resumeReads(); } }); assertTrue(serverOK.get()); assertTrue(clientOK.get()); } @Override public void oneWayTransfer1() throws Exception { log.info("Test: oneWayTransfer1"); final CountDownLatch latch = new CountDownLatch(2); final AtomicInteger clientSent = new AtomicInteger(0); final AtomicInteger serverReceived = new AtomicInteger(0); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final SslConnection connection) { connection.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamConnection connection) { latch.countDown(); } }); final ConduitStreamSinkChannel sinkChannel = connection.getSinkChannel(); sinkChannel.setWriteListener(new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel sinkChannel) { try { final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); int c; try { while ((c = sinkChannel.write(buffer)) > 0) { if (clientSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel sinkChannel) { try { if (sinkChannel.flush()) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel sinkChannel) { // really lame, but due to the way SSL shuts down... if (serverReceived.get() == clientSent.get()) { try { sinkChannel.shutdownWrites(); connection.close(); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } } }; sinkChannel.setWriteListener(listener); listener.handleEvent(sinkChannel); return; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }; sinkChannel.setWriteListener(listener); listener.handleEvent(sinkChannel); return; } buffer.rewind(); } } catch (ClosedChannelException e) { sinkChannel.shutdownWrites(); throw e; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); sinkChannel.resumeWrites(); } }, new ChannelListener() { public void handleEvent(final SslConnection connection) { connection.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamConnection connection) { latch.countDown(); } }); final ConduitStreamSourceChannel sourceChannel = connection.getSourceChannel(); sourceChannel.setReadListener(new ChannelListener() { public void handleEvent(final ConduitStreamSourceChannel sourceChannel) { try { int c; while ((c = sourceChannel.read(ByteBuffer.allocate(100))) > 0) { serverReceived.addAndGet(c); } if (c == -1) { sourceChannel.shutdownReads(); connection.close(); } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); sourceChannel.resumeReads(); } }); assertEquals(clientSent.get(), serverReceived.get()); } @Override public void oneWayTransfer2() throws Exception { log.info("Test: oneWayTransfer2"); final CountDownLatch latch = new CountDownLatch(2); final AtomicInteger clientReceived = new AtomicInteger(0); final AtomicInteger serverSent = new AtomicInteger(0); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final SslConnection connection) { connection.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamConnection connection) { latch.countDown(); } }); final ConduitStreamSourceChannel sourceChannel = connection.getSourceChannel(); sourceChannel.getReadSetter().set(new ChannelListener() { public void handleEvent(final ConduitStreamSourceChannel sourceChannel) { try { int c; while ((c = sourceChannel.read(ByteBuffer.allocate(100))) > 0) { clientReceived.addAndGet(c); } if (c == -1) { sourceChannel.shutdownReads(); connection.close(); } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); sourceChannel.resumeReads(); } }, new ChannelListener() { public void handleEvent(final SslConnection connection) { connection.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamConnection connection) { latch.countDown(); } }); final ConduitStreamSinkChannel sinkChannel = connection.getSinkChannel(); sinkChannel.setWriteListener(new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel sinkChannel) { try { final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); int c; try { while ((c = sinkChannel.write(buffer)) > 0) { if (serverSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel sinkChannel) { try { if (sinkChannel.flush()) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel sinkChannel) { // really lame, but due to the way SSL shuts down... if (clientReceived.get() == serverSent.get()) { try { sinkChannel.shutdownWrites(); connection.close(); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } } }; sinkChannel.setWriteListener(listener); listener.handleEvent(sinkChannel); return; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }; sinkChannel.setWriteListener(listener); listener.handleEvent(sinkChannel); return; } buffer.rewind(); } } catch (ClosedChannelException e) { sinkChannel.shutdownWrites(); throw e; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); sinkChannel.resumeWrites(); } }); assertEquals(serverSent.get(), clientReceived.get()); } @Override public void twoWayTransfer() throws Exception { log.info("Test: twoWayTransfer"); final CountDownLatch latch = new CountDownLatch(2); final AtomicInteger clientSent = new AtomicInteger(0); final AtomicInteger clientReceived = new AtomicInteger(0); final AtomicInteger serverSent = new AtomicInteger(0); final AtomicInteger serverReceived = new AtomicInteger(0); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final SslConnection connection) { connection.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamConnection connection) { latch.countDown(); } }); final ConduitStreamSourceChannel sourceChannel = connection.getSourceChannel(); sourceChannel.getReadSetter().set(new ChannelListener() { public void handleEvent(final ConduitStreamSourceChannel sourceChannel) { try { //log.info("client handle readable"); int c; while ((c = sourceChannel.read(ByteBuffer.allocate(100))) > 0) { clientReceived.addAndGet(c); //log.info("client received: " + clientReceived.get()); } if (c == -1) { //log.info("client shutdown reads"); sourceChannel.shutdownReads(); } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); final ConduitStreamSinkChannel sinkChannel = connection.getSinkChannel(); sinkChannel.setWriteListener(new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel sinkChannel) { //log.info("client handle writable"); try { final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); int c; try { while ((c = sinkChannel.write(buffer)) > 0) { //log.info("client sent: " + (clientSent.get() + c)); if (clientSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel sinkChannel) { try { if (sinkChannel.flush()) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel sinkChannel) { // really lame, but due to the way SSL shuts down... if (clientReceived.get() == serverSent.get() && serverReceived.get() == clientSent.get() && serverSent.get() > 1000) { try { //log.info("client closing connection"); connection.close(); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } } }; sinkChannel.setWriteListener(listener); listener.handleEvent(sinkChannel); return; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }; sinkChannel.setWriteListener(listener); listener.handleEvent(sinkChannel); return; } buffer.rewind(); } } catch (ClosedChannelException e) { sinkChannel.shutdownWrites(); throw e; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); sourceChannel.resumeReads(); sinkChannel.resumeWrites(); } }, new ChannelListener() { public void handleEvent(final SslConnection connection) { connection.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamConnection connection) { latch.countDown(); } }); final ConduitStreamSourceChannel sourceChannel = connection.getSourceChannel(); sourceChannel.setReadListener(new ChannelListener() { public void handleEvent(final ConduitStreamSourceChannel sourceChannel) { //log.info("server handle readable"); try { int c; while ((c = sourceChannel.read(ByteBuffer.allocate(100))) > 0) { serverReceived.addAndGet(c); //log.info("server received: " + serverReceived.get()); } if (c == -1) { //log.info("server shutingdown reads"); sourceChannel.shutdownReads(); } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); final ConduitStreamSinkChannel sinkChannel = connection.getSinkChannel(); sinkChannel.setWriteListener(new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel sinkChannel) { //log.info("server handle writable"); try { final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); int c; try { while ((c = sinkChannel.write(buffer)) > 0) { //log.info("server sent: " + (serverSent.get() + c)); if (serverSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel sinkChannel) { try { if (sinkChannel.flush()) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel sinkChannel) { // really lame, but due to the way SSL shuts down... if (clientReceived.get() == serverSent.get() && serverReceived.get() == clientSent.get() && clientSent.get() > 1000) { try { //log.info("server closing connection"); connection.close(); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } } }; sinkChannel.setWriteListener(listener); listener.handleEvent(sinkChannel); return; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }; sinkChannel.setWriteListener(listener); listener.handleEvent(sinkChannel); return; } buffer.rewind(); } } catch (ClosedChannelException e) { sinkChannel.shutdownWrites(); throw e; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); sourceChannel.resumeReads(); sinkChannel.resumeWrites(); } }); assertEquals(serverSent.get(), clientReceived.get()); assertEquals(clientSent.get(), serverReceived.get()); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/NioStartTLSTcpChannelTestCase.java000066400000000000000000000777651257016060700316660ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Before; import org.xnio.ChannelListener; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.channels.ConnectedChannel; import org.xnio.channels.ConnectedSslStreamChannel; import org.xnio.channels.ConnectedStreamChannel; /** * Test for {@code XnioSsl} channels with the start TLS option enabled. * * @author Flavia Rainone * */ public class NioStartTLSTcpChannelTestCase extends NioSslTcpChannelTestCase { @Before public void setStartTLSOption() { final OptionMap optionMap = OptionMap.create(Options.SSL_STARTTLS, true); super.setServerOptionMap(optionMap); super.setClientOptionMap(optionMap); } @Override public void clientClose() throws Exception { log.info("Test: clientClose"); final CountDownLatch latch = new CountDownLatch(4); final AtomicBoolean clientOK = new AtomicBoolean(false); final AtomicBoolean serverOK = new AtomicBoolean(false); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final ConnectedSslStreamChannel channel) { log.info("In client open"); try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedChannel channel) { log.info("In client close"); latch.countDown(); } }); channel.close(); clientOK.set(true); latch.countDown(); } catch (Throwable t) { log.error("In client", t); latch.countDown(); throw new RuntimeException(t); } } }, new ChannelListener() { public void handleEvent(final ConnectedSslStreamChannel channel) { log.info("In server opened"); channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedChannel channel) { log.info("In server close"); latch.countDown(); } }); setReadListener(channel, new ChannelListener() { public void handleEvent(final ConnectedSslStreamChannel sourceChannel) { log.info("In server readable"); try { final int c = sourceChannel.read(ByteBuffer.allocate(100)); if (c == -1) { serverOK.set(true); } channel.close(); } catch (IOException e) { throw new RuntimeException(e); } latch.countDown(); } }); resumeReads(channel); } }); assertTrue(serverOK.get()); assertTrue(clientOK.get()); } @Override public void oneWayTransfer1() throws Exception { log.info("Test: oneWayTransfer1"); final CountDownLatch latch = new CountDownLatch(2); final AtomicInteger clientSent = new AtomicInteger(0); final AtomicInteger serverReceived = new AtomicInteger(0); final AtomicBoolean clientHandshakeStarted = new AtomicBoolean(false); final AtomicBoolean serverHandshakeStarted = new AtomicBoolean(false); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500000L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { latch.countDown(); } }); channel.getWriteSetter().set(new ChannelListener() { private boolean continueWriting(ConnectedStreamChannel channel) throws IOException { if (!clientHandshakeStarted.get() && clientSent.get() > 100) { if (serverReceived.get() == clientSent.get()) { ((ConnectedSslStreamChannel) channel).startHandshake(); clientHandshakeStarted.set(true); return true; } return false; } return true; } public void handleEvent(final ConnectedStreamChannel channel) { try { final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); int c; try { while (continueWriting(channel) && (c = channel.write(buffer)) > 0) { if (clientSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { if (channel.flush()) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { // really lame, but due to the way SSL shuts down... if (serverReceived.get() == clientSent.get()) { try { channel.shutdownWrites(); channel.close(); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } } buffer.rewind(); } catch (ClosedChannelException e) { try { channel.shutdownWrites(); } catch (Exception exception) {} throw e; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); channel.resumeWrites(); } }, new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { int c; while ((c = channel.read(ByteBuffer.allocate(100))) > 0) { if (serverReceived.addAndGet(c) > 100 && !serverHandshakeStarted.get()) { ((ConnectedSslStreamChannel) channel).startHandshake(); serverHandshakeStarted.set(true); } } if (c == -1) { channel.shutdownReads(); channel.close(); } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); channel.resumeReads(); } }); assertEquals(clientSent.get(), serverReceived.get()); } @Override public void oneWayTransfer2() throws Exception { log.info("Test: oneWayTransfer2"); final CountDownLatch latch = new CountDownLatch(2); final AtomicInteger clientReceived = new AtomicInteger(0); final AtomicInteger serverSent = new AtomicInteger(0); final AtomicBoolean serverHandshakeStarted = new AtomicBoolean(false); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500000L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { int c; while ((c = channel.read(ByteBuffer.allocate(100))) > 0) { if (clientReceived.addAndGet(c) > 100) { ((ConnectedSslStreamChannel) channel).startHandshake(); } } if (c == -1) { channel.shutdownReads(); channel.close(); } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); channel.resumeReads(); } }, new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { latch.countDown(); } }); channel.getWriteSetter().set(new ChannelListener() { private boolean continueWriting(ConnectedStreamChannel channel) throws IOException { if (!serverHandshakeStarted.get() && serverSent.get() > 100) { if (clientReceived.get() == serverSent.get()) { ((ConnectedSslStreamChannel) channel).startHandshake(); serverHandshakeStarted.set(true); return true; } return false; } return true; } public void handleEvent(final ConnectedStreamChannel channel) { try { final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); int c; try { while (continueWriting(channel) && (c = channel.write(buffer)) > 0) { if (serverSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { if (channel.flush()) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { // really lame, but due to the way SSL shuts down... if (clientReceived.get() == serverSent.get()) { try { channel.shutdownWrites(); channel.close(); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } } buffer.rewind(); } catch (ClosedChannelException e) { channel.shutdownWrites(); throw e; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); channel.resumeWrites(); } }); assertEquals(serverSent.get(), clientReceived.get()); } @Override public void twoWayTransfer() throws Exception { log.info("Test: twoWayTransfer"); final CountDownLatch latch = new CountDownLatch(2); final AtomicInteger clientSent = new AtomicInteger(0); final AtomicInteger clientReceived = new AtomicInteger(0); final AtomicInteger serverSent = new AtomicInteger(0); final AtomicInteger serverReceived = new AtomicInteger(0); final AtomicBoolean clientHandshakeStarted = new AtomicBoolean(false); final AtomicBoolean serverHandshakeStarted = new AtomicBoolean(false); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500000L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { private boolean continueReading() throws IOException { return clientHandshakeStarted.get() || clientReceived.get() < 101; } public void handleEvent(final ConnectedStreamChannel channel) { //log.info("client handle read events"); try { int c = 0; while (continueReading() && (c = channel.read(ByteBuffer.allocate(100))) > 0) { //log.info("client received: "+ (clientReceived.get() + c)); clientReceived.addAndGet(c); } if (c == -1) { //log.info("client shutdown reads"); channel.shutdownReads(); } } catch (Throwable t) { t.printStackTrace(); } } }); channel.getWriteSetter().set(new ChannelListener() { private boolean continueWriting(ConnectedStreamChannel channel) throws IOException { if (!clientHandshakeStarted.get() && clientSent.get() > 100) { if (serverReceived.get() == clientSent.get() && serverSent.get() > 100 && clientReceived.get() == serverSent.get() ) { ((ConnectedSslStreamChannel) channel).startHandshake(); //log.info("client starting handshake"); clientHandshakeStarted.set(true); return true; } return false; } return true; } public void handleEvent(final ConnectedStreamChannel channel) { try { final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); int c = 0; try { while (continueWriting(channel) && (clientSent.get() > 1000 || (c = channel.write(buffer)) > 0)) { //log.info("clientSent: " + (clientSent.get() + c)); if (clientSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { if (channel.flush()) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { // really lame, but due to the way SSL shuts down... if (clientReceived.get() == serverSent.get() && serverReceived.get() == clientSent.get() && serverSent.get() > 1000) { try { //log.info("client closing channel"); channel.close(); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } buffer.rewind(); } } catch (ClosedChannelException e) { try { channel.shutdownWrites(); } catch (Exception cce) {/* do nothing */} throw e; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); channel.resumeReads(); channel.resumeWrites(); } }, new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { latch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { private boolean continueReading() throws IOException { return serverHandshakeStarted.get() || serverReceived.get() < 101; } public void handleEvent(final ConnectedStreamChannel channel) { try { int c = 0; while (continueReading() && (c = channel.read(ByteBuffer.allocate(100))) > 0) { //log.info("server received: "+ (serverReceived.get() + c)); serverReceived.addAndGet(c); } if (c == -1) { //log.info("server shutdown reads"); channel.shutdownReads(); } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); channel.getWriteSetter().set(new ChannelListener() { private boolean continueWriting(ConnectedStreamChannel channel) throws IOException { if (!serverHandshakeStarted.get() && serverSent.get() > 100) { if (clientReceived.get() == serverSent.get() && clientSent.get() > 100 && serverReceived.get() == clientSent.get() ) { //log.info("server starting handshake"); ((ConnectedSslStreamChannel) channel).startHandshake(); serverHandshakeStarted.set(true); return true; } return false; } return true; } public void handleEvent(final ConnectedStreamChannel channel) { try { final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); int c; try { while (continueWriting(channel) && (c = channel.write(buffer)) > 0) { //log.info("server sent: "+ (serverSent.get() + c)); if (serverSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { if (channel.flush()) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { // really lame, but due to the way SSL shuts down... if (clientReceived.get() == serverSent.get() && serverReceived.get() == clientSent.get() && clientSent.get() > 1000) { try { //log.info("server closing channel"); channel.close(); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } } buffer.rewind(); } catch (ClosedChannelException e) { channel.shutdownWrites(); throw e; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); channel.resumeReads(); channel.resumeWrites(); } }); assertEquals(serverSent.get(), clientReceived.get()); assertEquals(clientSent.get(), serverReceived.get()); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/NioStartTLSTcpConnectionTestCase.java000066400000000000000000001004171257016060700323720ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import org.junit.Before; import org.xnio.ChannelListener; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.channels.ConnectedChannel; import org.xnio.ssl.SslConnection; import org.xnio.conduits.ConduitStreamSinkChannel; import org.xnio.conduits.ConduitStreamSourceChannel; /** * Test for {@code XnioSsl} connections with the start TLS option enabled. * * @author Flavia Rainone * */ public class NioStartTLSTcpConnectionTestCase extends NioSslTcpConnectionTestCase { @Before public void setStartTLSOption() { final OptionMap optionMap = OptionMap.create(Options.SSL_STARTTLS, true); super.setServerOptionMap(optionMap); super.setClientOptionMap(optionMap); } @Override public void clientClose() throws Exception { log.info("Test: clientClose"); final CountDownLatch latch = new CountDownLatch(4); final AtomicBoolean clientOK = new AtomicBoolean(false); final AtomicBoolean serverOK = new AtomicBoolean(false); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final SslConnection channel) { log.info("In client open"); try { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final SslConnection channel) { log.info("In client close"); latch.countDown(); } }); channel.close(); clientOK.set(true); latch.countDown(); } catch (Throwable t) { log.error("In client", t); latch.countDown(); throw new RuntimeException(t); } } }, new ChannelListener() { public void handleEvent(final SslConnection channel) { log.info("In server opened"); channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedChannel channel) { log.info("In server close"); latch.countDown(); } }); setReadListener(channel, new ChannelListener() { public void handleEvent(final ConduitStreamSourceChannel sourceChannel) { log.info("In server readable"); try { final int c = sourceChannel.read(ByteBuffer.allocate(100)); if (c == -1) { serverOK.set(true); } channel.close(); } catch (IOException e) { throw new RuntimeException(e); } latch.countDown(); } }); resumeReads(channel); } }); assertTrue(serverOK.get()); assertTrue(clientOK.get()); } @Override public void oneWayTransfer1() throws Exception { log.info("Test: oneWayTransfer"); final CountDownLatch latch = new CountDownLatch(2); final AtomicInteger clientSent = new AtomicInteger(0); final AtomicInteger serverReceived = new AtomicInteger(0); final AtomicBoolean clientHandshakeStarted = new AtomicBoolean(false); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500000L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final SslConnection connection) { connection.getCloseSetter().set(new ChannelListener() { public void handleEvent(final SslConnection channel) { latch.countDown(); } }); connection.getSinkChannel().setWriteListener(new ChannelListener() { private boolean continueWriting() throws IOException { if (!clientHandshakeStarted.get() && clientSent.get() > 100) { if (serverReceived.get() == clientSent.get()) { connection.startHandshake(); //log.info("client starting handshake"); clientHandshakeStarted.set(true); return true; } return false; } return true; } public void handleEvent(final ConduitStreamSinkChannel channel) { try { final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); int c; try { while (continueWriting() && (c = channel.write(buffer)) > 0) { if (clientSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel channel) { try { if (channel.flush()) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel channel) { // really lame, but due to the way SSL shuts down... if (serverReceived.get() == clientSent.get()) { try { channel.shutdownWrites(); connection.close(); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }; channel.setWriteListener(listener); listener.handleEvent(channel); return; } } buffer.rewind(); } catch (ClosedChannelException e) { try { channel.shutdownWrites(); } catch (Exception exception) {} throw e; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); connection.getSinkChannel().resumeWrites(); } }, new ChannelListener() { public void handleEvent(final SslConnection connection) { connection.getCloseSetter().set(new ChannelListener() { public void handleEvent(final SslConnection channel) { latch.countDown(); } }); connection.getSourceChannel().setReadListener(new ChannelListener() { public void handleEvent(final ConduitStreamSourceChannel channel) { try { int c; while ((c = channel.read(ByteBuffer.allocate(100))) > 0) { if (serverReceived.addAndGet(c) > 100) { connection.startHandshake(); } } if (c == -1) { channel.shutdownReads(); connection.close(); } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); connection.getSourceChannel().resumeReads(); } }); assertEquals(clientSent.get(), serverReceived.get()); } @Override public void oneWayTransfer2() throws Exception { log.info("Test: oneWayTransfer2"); final CountDownLatch latch = new CountDownLatch(2); final AtomicInteger clientReceived = new AtomicInteger(0); final AtomicInteger serverSent = new AtomicInteger(0); final AtomicBoolean serverHandshakeStarted = new AtomicBoolean(false); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500000L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final SslConnection connection) { connection.getCloseSetter().set(new ChannelListener() { public void handleEvent(final SslConnection connection) { latch.countDown(); } }); connection.getSourceChannel().setReadListener(new ChannelListener() { public void handleEvent(final ConduitStreamSourceChannel channel) { try { int c; while ((c = channel.read(ByteBuffer.allocate(100))) > 0) { if (clientReceived.addAndGet(c) > 100) { connection.startHandshake(); } } if (c == -1) { channel.shutdownReads(); connection.close(); } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); connection.getSourceChannel().resumeReads(); } }, new ChannelListener() { public void handleEvent(final SslConnection connection) { connection.getCloseSetter().set(new ChannelListener() { public void handleEvent(final SslConnection connection) { latch.countDown(); } }); connection.getSinkChannel().setWriteListener(new ChannelListener() { private boolean continueWriting() throws IOException { if (!serverHandshakeStarted.get() && serverSent.get() > 100) { if (clientReceived.get() == serverSent.get()) { connection.startHandshake(); //log.info("client starting handshake"); serverHandshakeStarted.set(true); return true; } return false; } return true; } public void handleEvent(final ConduitStreamSinkChannel channel) { try { final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); int c; try { while (continueWriting() && (c = channel.write(buffer)) > 0) { if (serverSent.addAndGet(c) > 100) { connection.startHandshake(); if (serverSent.get() > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel channel) { try { if (channel.flush()) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel channel) { // really lame, but due to the way SSL shuts down... if (clientReceived.get() == serverSent.get()) { try { channel.shutdownWrites(); connection.close(); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } } }; channel.setWriteListener(listener); listener.handleEvent(channel); return; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } } buffer.rewind(); } } catch (ClosedChannelException e) { channel.shutdownWrites(); throw e; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); connection.getSinkChannel().resumeWrites(); } }); assertEquals(serverSent.get(), clientReceived.get()); } @Override public void twoWayTransfer() throws Exception { log.info("Test: twoWayTransfer"); final CountDownLatch latch = new CountDownLatch(2); final AtomicInteger clientSent = new AtomicInteger(0); final AtomicInteger clientReceived = new AtomicInteger(0); final AtomicInteger serverSent = new AtomicInteger(0); final AtomicInteger serverReceived = new AtomicInteger(0); final AtomicBoolean clientHandshakeStarted = new AtomicBoolean(false); final AtomicBoolean serverHandshakeStarted = new AtomicBoolean(false); doConnectionTest(new Runnable() { public void run() { try { assertTrue(latch.await(500000L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }, new ChannelListener() { public void handleEvent(final SslConnection connection) { connection.getCloseSetter().set(new ChannelListener() { public void handleEvent(final SslConnection channel) { latch.countDown(); } }); connection.getSourceChannel().setReadListener(new ChannelListener() { private boolean continueReading() throws IOException { return clientHandshakeStarted.get() || clientReceived.get() < 101; } public void handleEvent(final ConduitStreamSourceChannel channel) { //log.info("client handle read events"); try { int c = 0; while (continueReading() && (c = channel.read(ByteBuffer.allocate(100))) > 0) { //log.info("client received: "+ (clientReceived.get() + c)); clientReceived.addAndGet(c); } if (c == -1) { //log.info("client shutdown reads"); channel.shutdownReads(); } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); connection.getSinkChannel().setWriteListener(new ChannelListener() { private boolean continueWriting(ConduitStreamSinkChannel channel) throws IOException { if (!clientHandshakeStarted.get() && clientSent.get() > 100) { if (serverReceived.get() == clientSent.get() && serverSent.get() > 100 && clientReceived.get() == serverSent.get() ) { connection.startHandshake(); //log.info("client starting handshake"); clientHandshakeStarted.set(true); return true; } return false; } return true; } public void handleEvent(final ConduitStreamSinkChannel channel) { try { final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); int c = 0; try { while (continueWriting(channel) && (clientSent.get() > 1000 || (c = channel.write(buffer)) > 0)) { //log.info("clientSent: " + (clientSent.get() + c)); if (clientSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel channel) { try { if (channel.flush()) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel channel) { // really lame, but due to the way SSL shuts down... if (clientReceived.get() == serverSent.get() && serverReceived.get() == clientSent.get() && serverSent.get() > 1000) { try { //log.info("client closing channel"); connection.close(); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } } }; channel.setWriteListener(listener); listener.handleEvent(channel); return; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } } buffer.rewind(); } catch (ClosedChannelException e) { try { channel.shutdownWrites(); } catch (Exception cce) {/* do nothing */} throw e; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); connection.getSourceChannel().resumeReads(); connection.getSinkChannel().resumeWrites(); } }, new ChannelListener() { public void handleEvent(final SslConnection connection) { connection.getCloseSetter().set(new ChannelListener() { public void handleEvent(final SslConnection connection) { latch.countDown(); } }); connection.getSourceChannel().setReadListener(new ChannelListener() { private boolean continueReading() throws IOException { return serverHandshakeStarted.get() || serverReceived.get() < 101; } public void handleEvent(final ConduitStreamSourceChannel channel) { try { int c = 0; while (continueReading() && (c = channel.read(ByteBuffer.allocate(100))) > 0) { //log.info("server received: "+ (serverReceived.get() + c)); serverReceived.addAndGet(c); } if (c == -1) { //log.info("server shutdown reads"); channel.shutdownReads(); } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); connection.getSinkChannel().setWriteListener(new ChannelListener() { private boolean continueWriting() throws IOException { if (!serverHandshakeStarted.get() && serverSent.get() > 100) { if (clientReceived.get() == serverSent.get() && clientSent.get() > 100 && serverReceived.get() == clientSent.get() ) { //log.info("server starting handshake"); connection.startHandshake(); serverHandshakeStarted.set(true); return true; } return false; } return true; } public void handleEvent(final ConduitStreamSinkChannel channel) { try { final ByteBuffer buffer = ByteBuffer.allocate(100); buffer.put("This Is A Test\r\n".getBytes("UTF-8")).flip(); int c; try { while (continueWriting() && (c = channel.write(buffer)) > 0) { //log.info("server sent: "+ (serverSent.get() + c)); if (serverSent.addAndGet(c) > 1000) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel channel) { try { if (channel.flush()) { final ChannelListener listener = new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel channel) { // really lame, but due to the way SSL shuts down... if (clientReceived.get() == serverSent.get() && serverReceived.get() == clientSent.get() && clientSent.get() > 1000) { try { //log.info("server closing channel"); connection.close(); } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } } }; channel.getWriteSetter().set(listener); listener.handleEvent(channel); return; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }; channel.setWriteListener(listener); listener.handleEvent(channel); return; } } buffer.rewind(); } catch (ClosedChannelException e) { channel.shutdownWrites(); throw e; } } catch (Throwable t) { t.printStackTrace(); throw new RuntimeException(t); } } }); connection.getSourceChannel().resumeReads(); connection.getSinkChannel().resumeWrites(); } }); assertEquals(serverSent.get(), clientReceived.get()); assertEquals(clientSent.get(), serverReceived.get()); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/NioTcpChannelTestCase.java000066400000000000000000000277411257016060700302520ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.Inet4Address; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Ignore; import org.junit.Test; import org.xnio.ChannelListener; import org.xnio.FutureResult; import org.xnio.IoFuture; import org.xnio.IoUtils; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.Xnio; import org.xnio.XnioWorker; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.BoundChannel; import org.xnio.channels.Channels; import org.xnio.channels.ConnectedStreamChannel; /** * Test for TCP connected stream channels. * * @author David M. Lloyd * @author Flavia Rainone */ @SuppressWarnings("deprecation") public class NioTcpChannelTestCase extends AbstractNioTcpTest{ @Test @Ignore("Does not follow thread model") public void acceptor() throws Exception { log.info("Test: acceptor"); final CountDownLatch ioLatch = new CountDownLatch(4); final CountDownLatch closeLatch = new CountDownLatch(2); final AtomicBoolean clientOpened = new AtomicBoolean(); final AtomicBoolean clientReadOnceOK = new AtomicBoolean(); final AtomicBoolean clientReadDoneOK = new AtomicBoolean(); final AtomicBoolean clientReadTooMuch = new AtomicBoolean(); final AtomicBoolean clientWriteOK = new AtomicBoolean(); final AtomicBoolean serverOpened = new AtomicBoolean(); final AtomicBoolean serverReadOnceOK = new AtomicBoolean(); final AtomicBoolean serverReadDoneOK = new AtomicBoolean(); final AtomicBoolean serverReadTooMuch = new AtomicBoolean(); final AtomicBoolean serverWriteOK = new AtomicBoolean(); final byte[] bytes = "Ummagumma!".getBytes("UTF-8"); final Xnio xnio = Xnio.getInstance("nio"); final XnioWorker worker = xnio.createWorker(OptionMap.create(Options.WORKER_WRITE_THREADS, 2, Options.WORKER_READ_THREADS, 2)); try { final FutureResult futureAddressResult = new FutureResult(); final IoFuture futureAddress = futureAddressResult.getIoFuture(); worker.acceptStream(new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), 0), new ChannelListener() { private final ByteBuffer inboundBuf = ByteBuffer.allocate(512); private int readCnt = 0; private final ByteBuffer outboundBuf = ByteBuffer.wrap(bytes); public void handleEvent(final ConnectedStreamChannel channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { closeLatch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { final int res = channel.read(inboundBuf); if (res == 0) { channel.resumeReads(); } else if (res == -1) { serverReadDoneOK.set(true); ioLatch.countDown(); channel.shutdownReads(); } else { final int ttl = readCnt += res; if (ttl == bytes.length) { serverReadOnceOK.set(true); } else if (ttl > bytes.length) { serverReadTooMuch.set(true); IoUtils.safeClose(channel); return; } channel.resumeReads(); } } catch (IOException e) { log.errorf(e, "Server read failed"); IoUtils.safeClose(channel); } } }); channel.getWriteSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { channel.write(outboundBuf); if (!outboundBuf.hasRemaining()) { serverWriteOK.set(true); Channels.shutdownWritesBlocking(channel); ioLatch.countDown(); } } catch (IOException e) { log.errorf(e, "Server write failed"); IoUtils.safeClose(channel); } } }); channel.resumeReads(); channel.resumeWrites(); serverOpened.set(true); } }, new ChannelListener() { public void handleEvent(final BoundChannel channel) { futureAddressResult.setResult(channel.getLocalAddress(InetSocketAddress.class)); } }, OptionMap.create(Options.REUSE_ADDRESSES, Boolean.TRUE)); final InetSocketAddress localAddress = futureAddress.get(); worker.connectStream(localAddress, new ChannelListener() { private final ByteBuffer inboundBuf = ByteBuffer.allocate(512); private int readCnt = 0; private final ByteBuffer outboundBuf = ByteBuffer.wrap(bytes); public void handleEvent(final ConnectedStreamChannel channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { closeLatch.countDown(); } }); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { final int res = channel.read(inboundBuf); if (res == 0) { channel.resumeReads(); } else if (res == -1) { channel.shutdownReads(); clientReadDoneOK.set(true); ioLatch.countDown(); } else { final int ttl = readCnt += res; if (ttl == bytes.length) { clientReadOnceOK.set(true); } else if (ttl > bytes.length) { clientReadTooMuch.set(true); IoUtils.safeClose(channel); return; } channel.resumeReads(); } } catch (IOException e) { log.errorf(e, "Client read failed"); IoUtils.safeClose(channel); } } }); channel.getWriteSetter().set(new ChannelListener() { public void handleEvent(final ConnectedStreamChannel channel) { try { channel.write(outboundBuf); if (!outboundBuf.hasRemaining()) { clientWriteOK.set(true); Channels.shutdownWritesBlocking(channel); ioLatch.countDown(); } } catch (IOException e) { log.errorf(e, "Client write failed"); IoUtils.safeClose(channel); } } }); channel.resumeReads(); channel.resumeWrites(); clientOpened.set(true); } }, null, OptionMap.EMPTY); assertTrue("Read timed out", ioLatch.await(500L, TimeUnit.MILLISECONDS)); assertTrue("Close timed out", closeLatch.await(500L, TimeUnit.MILLISECONDS)); assertFalse("Client read too much", clientReadTooMuch.get()); assertTrue("Client read OK", clientReadOnceOK.get()); assertTrue("Client read done", clientReadDoneOK.get()); assertTrue("Client write OK", clientWriteOK.get()); assertFalse("Server read too much", serverReadTooMuch.get()); assertTrue("Server read OK", serverReadOnceOK.get()); assertTrue("Server read done", serverReadDoneOK.get()); assertTrue("Server write OK", serverWriteOK.get()); } finally { worker.shutdown(); } } @Override protected AcceptingChannel createServer(XnioWorker worker, InetSocketAddress address, ChannelListener> openListener, OptionMap optionMap) throws IOException { return worker.createStreamServer(address, openListener, optionMap); } @Override protected IoFuture connect(XnioWorker worker, InetSocketAddress address, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { return worker.connectStream(address, openListener, bindListener, optionMap); } @Override protected void setReadListener(ConnectedStreamChannel channel, ChannelListener readListener) { channel.getReadSetter().set(readListener); } @Override protected void setWriteListener(ConnectedStreamChannel channel, ChannelListener writeListener) { channel.getWriteSetter().set(writeListener); } @Override protected void resumeReads(ConnectedStreamChannel channel) { channel.resumeReads(); } @Override protected void resumeWrites(ConnectedStreamChannel channel) { channel.resumeWrites(); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/NioTcpConnectionTestCase.java000066400000000000000000000306751257016060700310010ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.Inet4Address; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import org.junit.Ignore; import org.junit.Test; import org.xnio.ChannelListener; import org.xnio.FutureResult; import org.xnio.IoFuture; import org.xnio.IoUtils; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.StreamConnection; import org.xnio.Xnio; import org.xnio.XnioWorker; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.BoundChannel; import org.xnio.channels.Channels; import org.xnio.conduits.ConduitStreamSinkChannel; import org.xnio.conduits.ConduitStreamSourceChannel; /** * Test for TCP stream connections. * * @author Flavia Rainone */ public class NioTcpConnectionTestCase extends AbstractNioTcpTest { @Test @Ignore("Does not follow thread model") public void acceptor() throws Exception { log.info("Test: acceptor"); final CountDownLatch ioLatch = new CountDownLatch(4); final CountDownLatch closeLatch = new CountDownLatch(2); final AtomicBoolean clientOpened = new AtomicBoolean(); final AtomicBoolean clientReadOnceOK = new AtomicBoolean(); final AtomicBoolean clientReadDoneOK = new AtomicBoolean(); final AtomicBoolean clientReadTooMuch = new AtomicBoolean(); final AtomicBoolean clientWriteOK = new AtomicBoolean(); final AtomicBoolean serverOpened = new AtomicBoolean(); final AtomicBoolean serverReadOnceOK = new AtomicBoolean(); final AtomicBoolean serverReadDoneOK = new AtomicBoolean(); final AtomicBoolean serverReadTooMuch = new AtomicBoolean(); final AtomicBoolean serverWriteOK = new AtomicBoolean(); final byte[] bytes = "Ummagumma!".getBytes("UTF-8"); final Xnio xnio = Xnio.getInstance("nio"); final XnioWorker worker = xnio.createWorker(OptionMap.EMPTY); try { final FutureResult futureAddressResult = new FutureResult(); final IoFuture futureAddress = futureAddressResult.getIoFuture(); worker.acceptStreamConnection(new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), 0), new ChannelListener() { private final ByteBuffer inboundBuf = ByteBuffer.allocate(512); private int readCnt = 0; private final ByteBuffer outboundBuf = ByteBuffer.wrap(bytes); public void handleEvent(final StreamConnection connection) { connection.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamConnection channel) { closeLatch.countDown(); } }); final ConduitStreamSourceChannel sourceChannel = connection.getSourceChannel(); sourceChannel.setReadListener(new ChannelListener() { public void handleEvent(final ConduitStreamSourceChannel sourceChannel) { try { final int res = sourceChannel.read(inboundBuf); if (res == 0) { sourceChannel.resumeReads(); } else if (res == -1) { serverReadDoneOK.set(true); ioLatch.countDown(); sourceChannel.shutdownReads(); } else { final int ttl = readCnt += res; if (ttl == bytes.length) { serverReadOnceOK.set(true); } else if (ttl > bytes.length) { serverReadTooMuch.set(true); IoUtils.safeClose(connection); return; } sourceChannel.resumeReads(); } } catch (IOException e) { log.errorf(e, "Server read failed"); IoUtils.safeClose(connection); } } }); final ConduitStreamSinkChannel sinkChannel = connection.getSinkChannel(); sinkChannel.setWriteListener(new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel sinkChannel) { try { sinkChannel.write(outboundBuf); if (!outboundBuf.hasRemaining()) { serverWriteOK.set(true); Channels.shutdownWritesBlocking(sinkChannel); ioLatch.countDown(); } } catch (IOException e) { log.errorf(e, "Server write failed"); IoUtils.safeClose(connection); } } }); sourceChannel.resumeReads(); sinkChannel.resumeWrites(); serverOpened.set(true); } }, new ChannelListener() { public void handleEvent(final BoundChannel channel) { futureAddressResult.setResult(channel.getLocalAddress(InetSocketAddress.class)); } }, OptionMap.create(Options.REUSE_ADDRESSES, Boolean.TRUE)); final InetSocketAddress localAddress = futureAddress.get(); worker.openStreamConnection(localAddress, new ChannelListener() { private final ByteBuffer inboundBuf = ByteBuffer.allocate(512); private int readCnt = 0; private final ByteBuffer outboundBuf = ByteBuffer.wrap(bytes); public void handleEvent(final StreamConnection connection) { connection.getCloseSetter().set(new ChannelListener() { public void handleEvent(final StreamConnection connection) { closeLatch.countDown(); } }); final ConduitStreamSourceChannel sourceChannel = connection.getSourceChannel(); sourceChannel.setReadListener(new ChannelListener() { public void handleEvent(final ConduitStreamSourceChannel sourceChannel) { try { final int res = sourceChannel.read(inboundBuf); if (res == 0) { sourceChannel.resumeReads(); } else if (res == -1) { sourceChannel.shutdownReads(); clientReadDoneOK.set(true); ioLatch.countDown(); } else { final int ttl = readCnt += res; if (ttl == bytes.length) { clientReadOnceOK.set(true); } else if (ttl > bytes.length) { clientReadTooMuch.set(true); IoUtils.safeClose(connection); return; } sourceChannel.resumeReads(); } } catch (IOException e) { log.errorf(e, "Client read failed"); IoUtils.safeClose(connection); } } }); final ConduitStreamSinkChannel sinkChannel = connection.getSinkChannel(); sinkChannel.setWriteListener(new ChannelListener() { public void handleEvent(final ConduitStreamSinkChannel sinkChannel) { try { sinkChannel.write(outboundBuf); if (!outboundBuf.hasRemaining()) { clientWriteOK.set(true); Channels.shutdownWritesBlocking(sinkChannel); ioLatch.countDown(); } } catch (IOException e) { log.errorf(e, "Client write failed"); IoUtils.safeClose(connection); } } }); sourceChannel.resumeReads(); sinkChannel.resumeWrites(); clientOpened.set(true); } }, null, OptionMap.EMPTY); assertTrue("Read timed out", ioLatch.await(500L, TimeUnit.MILLISECONDS)); assertTrue("Close timed out", closeLatch.await(500L, TimeUnit.MILLISECONDS)); assertFalse("Client read too much", clientReadTooMuch.get()); assertTrue("Client read OK", clientReadOnceOK.get()); assertTrue("Client read done", clientReadDoneOK.get()); assertTrue("Client write OK", clientWriteOK.get()); assertFalse("Server read too much", serverReadTooMuch.get()); assertTrue("Server read OK", serverReadOnceOK.get()); assertTrue("Server read done", serverReadDoneOK.get()); assertTrue("Server write OK", serverWriteOK.get()); } finally { worker.shutdown(); } } @Override protected AcceptingChannel createServer(XnioWorker worker, InetSocketAddress address, ChannelListener> openListener, OptionMap optionMap) throws IOException { return worker.createStreamConnectionServer(address, openListener, optionMap); } @Override protected IoFuture connect(XnioWorker worker, InetSocketAddress address, ChannelListener openListener, ChannelListener bindListener, OptionMap optionMap) { return worker.openStreamConnection(address, openListener, bindListener, optionMap); } @Override protected void setReadListener(StreamConnection channel, ChannelListener readListener) { channel.getSourceChannel().setReadListener(readListener); } @Override protected void setWriteListener(StreamConnection channel, ChannelListener writeListener) { channel.getSinkChannel().setWriteListener(writeListener); } @Override protected void resumeReads(StreamConnection channel) { channel.getSourceChannel().resumeReads(); } @Override protected void resumeWrites(StreamConnection channel) { channel.getSinkChannel().resumeWrites(); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/NioUdpTestCase.java000066400000000000000000000271141257016060700267550ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio.test; import java.io.IOException; import java.net.Inet4Address; import java.net.InetSocketAddress; import java.net.UnknownHostException; import java.nio.ByteBuffer; import java.util.Arrays; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import junit.framework.TestCase; import org.jboss.logging.Logger; import org.junit.Ignore; import org.xnio.Buffers; import org.xnio.IoUtils; import org.xnio.Xnio; import org.xnio.OptionMap; import org.xnio.ChannelListener; import org.xnio.Options; import org.xnio.XnioWorker; import org.xnio.channels.MulticastMessageChannel; import org.xnio.channels.SocketAddressBuffer; /** * * Test for UDP connections. * * @author David M. Lloyd * */ public final class NioUdpTestCase extends TestCase { private static final int SERVER_PORT = 12345; private static final InetSocketAddress SERVER_SOCKET_ADDRESS; private static final InetSocketAddress CLIENT_SOCKET_ADDRESS; private static final Logger log = Logger.getLogger("TEST"); static { try { SERVER_SOCKET_ADDRESS = new InetSocketAddress(Inet4Address.getByAddress(new byte[] {127, 0, 0, 1}), SERVER_PORT); CLIENT_SOCKET_ADDRESS = new InetSocketAddress(Inet4Address.getByAddress(new byte[] {127, 0, 0, 1}), 0); } catch (UnknownHostException e) { throw new RuntimeException(e); } } private synchronized void doServerSideTest(final boolean multicast, final ChannelListener handler, final Runnable body) throws IOException { final Xnio xnio = Xnio.getInstance("nio"); doServerSidePart(multicast, handler, body, xnio.createWorker(OptionMap.EMPTY)); } private void doServerSidePart(final boolean multicast, final ChannelListener handler, final Runnable body, final XnioWorker worker) throws IOException { doPart(multicast, handler, body, SERVER_SOCKET_ADDRESS, worker); } private void doClientSidePart(final boolean multicast, final ChannelListener handler, final Runnable body, final XnioWorker worker) throws IOException { doPart(multicast, handler, body, CLIENT_SOCKET_ADDRESS, worker); } private synchronized void doPart(final boolean multicast, final ChannelListener handler, final Runnable body, final InetSocketAddress bindAddress, final XnioWorker worker) throws IOException { final MulticastMessageChannel server = worker.createUdpServer(bindAddress, handler, OptionMap.create(Options.MULTICAST, Boolean.valueOf(multicast))); try { body.run(); server.close(); } catch (RuntimeException e) { log.errorf(e, "Error running part"); throw e; } catch (IOException e) { log.errorf(e, "Error running part"); throw e; } catch (Error e) { log.errorf(e, "Error running part"); throw e; } finally { IoUtils.safeClose(server); } } private synchronized void doClientServerSide(final boolean clientMulticast, final boolean serverMulticast, final ChannelListener serverHandler, final ChannelListener clientHandler, final Runnable body) throws IOException { final Xnio xnio = Xnio.getInstance("nio"); final XnioWorker worker = xnio.createWorker(OptionMap.EMPTY); try { doServerSidePart(serverMulticast, serverHandler, new Runnable() { public void run() { try { doClientSidePart(clientMulticast, clientHandler, body, worker); } catch (IOException e) { throw new RuntimeException(e); } } }, worker); } finally { worker.shutdown(); try { worker.awaitTermination(1L, TimeUnit.MINUTES); } catch (InterruptedException ignored) { } } } private void doServerCreate(boolean multicast) throws Exception { final CountDownLatch latch = new CountDownLatch(2); final AtomicBoolean openedOk = new AtomicBoolean(false); final AtomicBoolean closedOk = new AtomicBoolean(false); doServerSideTest(multicast, new ChannelListener() { public void handleEvent(final MulticastMessageChannel channel) { channel.getCloseSetter().set(new ChannelListener() { public void handleEvent(final MulticastMessageChannel channel) { closedOk.set(true); latch.countDown(); } }); log.infof("In handleEvent for %s", channel); openedOk.set(true); latch.countDown(); } }, new Runnable() { public void run() { } }); assertTrue(latch.await(500L, TimeUnit.MILLISECONDS)); assertTrue(openedOk.get()); assertTrue(closedOk.get()); } public void testServerCreate() throws Exception { log.info("Test: testServerCreate"); doServerCreate(false); } public void testServerCreateMulticast() throws Exception { log.info("Test: testServerCreateMulticast"); doServerCreate(true); } @SuppressWarnings("unused") @Ignore /* XXX - depends on each server getting a separate thread */ public void testClientToServerTransmitNioToNio() throws Exception { if (true) return; log.info("Test: testClientToServerTransmitNioToNio"); final AtomicBoolean clientOK = new AtomicBoolean(false); final AtomicBoolean serverOK = new AtomicBoolean(false); final CountDownLatch startLatch = new CountDownLatch(1); final CountDownLatch receivedLatch = new CountDownLatch(1); final CountDownLatch doneLatch = new CountDownLatch(2); final byte[] payload = new byte[] { 10, 5, 15, 10, 100, -128, 30, 0, 0 }; doClientServerSide(true, true, new ChannelListener() { public void handleEvent(final MulticastMessageChannel channel) { log.infof("In handleEvent for %s", channel); channel.getReadSetter().set(new ChannelListener() { public void handleEvent(final MulticastMessageChannel channel) { log.infof("In handleReadable for %s", channel); try { final ByteBuffer buffer = ByteBuffer.allocate(50); final SocketAddressBuffer addressBuffer = new SocketAddressBuffer(); final int result = channel.receiveFrom(addressBuffer, buffer); if (result == 0) { log.infof("Whoops, spurious read notification for %s", channel); channel.resumeReads(); return; } try { final byte[] testPayload = new byte[payload.length]; Buffers.flip(buffer).get(testPayload); log.infof("We received the packet on %s", channel); assertTrue(Arrays.equals(testPayload, payload)); assertFalse(buffer.hasRemaining()); assertNotNull(addressBuffer.getSourceAddress()); try { channel.close(); serverOK.set(true); } finally { IoUtils.safeClose(channel); } } finally { receivedLatch.countDown(); doneLatch.countDown(); } } catch (IOException e) { IoUtils.safeClose(channel); throw new RuntimeException(e); } } }); channel.resumeReads(); startLatch.countDown(); } }, new ChannelListener() { public void handleEvent(final MulticastMessageChannel channel) { log.infof("In handleEvent for %s", channel); channel.getWriteSetter().set(new ChannelListener() { public void handleEvent(final MulticastMessageChannel channel) { log.infof("In handleWritable for %s", channel); try { if (clientOK.get()) { log.infof("Extra writable notification on %s (?!)", channel); } else if (! channel.sendTo(SERVER_SOCKET_ADDRESS, ByteBuffer.wrap(payload))) { log.infof("Whoops, spurious write notification for %s", channel); channel.resumeWrites(); } else { log.infof("We sent the packet on %s", channel); try { assertTrue(receivedLatch.await(500000L, TimeUnit.MILLISECONDS)); channel.close(); } finally { IoUtils.safeClose(channel); } clientOK.set(true); doneLatch.countDown(); } } catch (IOException e) { IoUtils.safeClose(channel); e.printStackTrace(); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); try { // wait until server is ready assertTrue(startLatch.await(500000L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } channel.resumeWrites(); } }, new Runnable() { public void run() { try { assertTrue(doneLatch.await(500000L, TimeUnit.MILLISECONDS)); } catch (InterruptedException e) { throw new RuntimeException(e); } } }); assertTrue(clientOK.get()); assertTrue(serverOK.get()); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/OptionHelper.java000066400000000000000000000070321257016060700265300ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio.test; import java.util.HashSet; import org.xnio.Option; import org.xnio.Options; /** * Utility class. * * @author Flavia Rainone */ public class OptionHelper { @SuppressWarnings("deprecation") private static Option[] options = {Options.ALLOW_BLOCKING, Options.BACKLOG, Options.BROADCAST, Options.CLOSE_ABORT, Options.CONNECTION_HIGH_WATER, Options.CONNECTION_LOW_WATER, Options.CORK, Options.FILE_ACCESS, Options.IP_TRAFFIC_CLASS, Options.KEEP_ALIVE, Options.MAX_INBOUND_MESSAGE_SIZE, Options.MAX_OUTBOUND_MESSAGE_SIZE, Options.MULTICAST, Options.MULTICAST_TTL, Options.READ_TIMEOUT, Options.RECEIVE_BUFFER, Options.REUSE_ADDRESSES, Options.SASL_DISALLOWED_MECHANISMS, Options.SASL_MECHANISMS, Options.SASL_POLICY_FORWARD_SECRECY, Options.SASL_POLICY_NOACTIVE, Options.SASL_POLICY_NOANONYMOUS, Options.SASL_POLICY_NODICTIONARY, Options.SASL_POLICY_NOPLAINTEXT, Options.SASL_POLICY_PASS_CREDENTIALS, Options.SASL_PROPERTIES, Options.SASL_QOP, Options.SASL_REUSE, Options.SASL_SERVER_AUTH, Options.SASL_STRENGTH, Options.SECURE, Options.SEND_BUFFER, Options.SSL_APPLICATION_BUFFER_REGION_SIZE, Options.SSL_APPLICATION_BUFFER_SIZE, Options.SSL_CLIENT_AUTH_MODE, Options.SSL_CLIENT_SESSION_CACHE_SIZE, Options.SSL_CLIENT_SESSION_TIMEOUT, Options.SSL_ENABLE_SESSION_CREATION, Options.SSL_ENABLED, Options.SSL_ENABLED_CIPHER_SUITES, Options.SSL_ENABLED_PROTOCOLS, Options.SSL_JSSE_KEY_MANAGER_CLASSES, Options.SSL_JSSE_TRUST_MANAGER_CLASSES, Options.SSL_PACKET_BUFFER_REGION_SIZE, Options.SSL_PACKET_BUFFER_SIZE, Options.SSL_PEER_HOST_NAME, Options.SSL_PEER_PORT, Options.SSL_PROTOCOL, Options.SSL_PROVIDER, Options.SSL_RNG_OPTIONS, Options.SSL_SERVER_SESSION_CACHE_SIZE, Options.SSL_SERVER_SESSION_TIMEOUT, Options.SSL_STARTTLS, Options.SSL_SUPPORTED_CIPHER_SUITES, Options.SSL_SUPPORTED_PROTOCOLS, Options.SSL_USE_CLIENT_MODE, Options.STACK_SIZE, Options.TCP_OOB_INLINE, Options.TCP_NODELAY, Options.THREAD_DAEMON, Options.THREAD_PRIORITY, Options.USE_DIRECT_BUFFERS, Options.WRITE_TIMEOUT, Options.WORKER_NAME, Options.WORKER_ACCEPT_THREADS, Options.WORKER_READ_THREADS, Options.WORKER_ESTABLISH_WRITING, Options.WORKER_TASK_CORE_THREADS, Options.WORKER_TASK_KEEPALIVE, Options.WORKER_TASK_LIMIT, Options.WORKER_TASK_MAX_THREADS, Options.WORKER_WRITE_THREADS}; public static Option[] getNotSupportedOptions(Option ... supportedOptions) { final HashSet> temp = new HashSet>(); for (Option option: options) { temp.add(option); } for (Option supportedOption: supportedOptions) { temp.remove(supportedOption); } return temp.toArray(new Option[0]); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/TcpChannelTestCase.java000066400000000000000000000240151257016060700275730ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.Inet4Address; import java.net.InetSocketAddress; import java.net.SocketAddress; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.xnio.ChannelListener; import org.xnio.FutureResult; import org.xnio.IoFuture; import org.xnio.LocalSocketAddress; import org.xnio.Option; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.XnioWorker; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.ConnectedStreamChannel; import org.xnio.channels.StreamChannel; /** * Tests a pair of connected TCP stream channels (client/server). * * @author Flavia Rainone */ @SuppressWarnings("deprecation") public class TcpChannelTestCase extends AbstractNioStreamChannelTest { protected SocketAddress bindAddress; protected ConnectedStreamChannel channel = null; protected ConnectedStreamChannel serverChannel = null; protected AcceptingChannel server; @Before public void createServer() throws IOException { bindAddress = new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), 12345); final ChannelListener> acceptingChannelListener = new TestChannelListener>();; server = worker.createStreamServer( bindAddress, acceptingChannelListener, OptionMap.EMPTY); assertNotNull(server); } @After public void closeServer() throws IOException { server.close(); } @Override protected synchronized void initChannels(XnioWorker xnioWorker, OptionMap optionMap, TestChannelListener channelListener, TestChannelListener serverChannelListener) throws IOException { if (channel != null) { channel.close(); serverChannel.close(); } final IoFuture connectedStreamChannel = xnioWorker.connectStream(bindAddress, null, optionMap); final FutureResult accepted = new FutureResult(xnioWorker); server.getAcceptThread().execute(new Runnable() { public void run() { try { accepted.setResult(server.accept()); } catch (IOException e) { accepted.setException(e); } } }); serverChannel = accepted.getIoFuture().get(); channel = connectedStreamChannel.get(); assertNotNull(serverChannel); assertNotNull(channel); channelListener.handleEvent(channel); serverChannelListener.handleEvent(serverChannel); } @Test public void optionSetup() throws IOException { initChannels(); final Option[] unsupportedOptions = OptionHelper.getNotSupportedOptions(Options.CLOSE_ABORT, Options.IP_TRAFFIC_CLASS, Options.KEEP_ALIVE, Options.READ_TIMEOUT, Options.RECEIVE_BUFFER, Options.RECEIVE_BUFFER, Options.SEND_BUFFER, Options.TCP_NODELAY, Options.TCP_OOB_INLINE, Options.WRITE_TIMEOUT); for (Option option: unsupportedOptions) { assertFalse("Channel supports " + option, channel.supportsOption(option)); assertNull("Expected null value for option " + option + " but got " + channel.getOption(option) + " instead", channel.getOption(option)); } assertTrue(channel.supportsOption(Options.CLOSE_ABORT)); assertFalse(channel.getOption(Options.CLOSE_ABORT)); assertTrue(channel.supportsOption(Options.IP_TRAFFIC_CLASS)); assertEquals(0, (int) channel.getOption(Options.IP_TRAFFIC_CLASS)); assertTrue(channel.supportsOption(Options.KEEP_ALIVE)); assertFalse(channel.getOption(Options.KEEP_ALIVE)); assertTrue(channel.supportsOption(Options.READ_TIMEOUT)); assertEquals(0, (int) channel.getOption(Options.READ_TIMEOUT)); assertTrue(channel.supportsOption(Options.RECEIVE_BUFFER)); assertTrue(channel.getOption(Options.RECEIVE_BUFFER) > 0); assertTrue(channel.supportsOption(Options.SEND_BUFFER)); assertTrue(channel.getOption(Options.SEND_BUFFER) > 0); assertTrue(channel.supportsOption(Options.TCP_NODELAY)); assertNotNull(channel.getOption(Options.TCP_NODELAY)); assertTrue(channel.supportsOption(Options.TCP_OOB_INLINE)); assertFalse(channel.getOption(Options.TCP_OOB_INLINE)); assertTrue(channel.supportsOption(Options.WRITE_TIMEOUT)); assertEquals(0, (int) channel.getOption(Options.WRITE_TIMEOUT)); channel.setOption(Options.CLOSE_ABORT, true); channel.setOption(Options.IP_TRAFFIC_CLASS, 5); channel.setOption(Options.KEEP_ALIVE, true); channel.setOption(Options.READ_TIMEOUT, 234095747); channel.setOption(Options.RECEIVE_BUFFER, 5000); channel.setOption(Options.SEND_BUFFER, 3000); channel.setOption(Options.TCP_NODELAY, true); channel.setOption(Options.TCP_OOB_INLINE, true); channel.setOption(Options.WRITE_TIMEOUT, 1301093); assertNull("Unexpected option value: " + channel.getOption(Options.MAX_INBOUND_MESSAGE_SIZE), channel.setOption(Options.MAX_INBOUND_MESSAGE_SIZE, 50000));// unsupported assertTrue(channel.getOption(Options.CLOSE_ABORT)); assertTrue(channel.getOption(Options.IP_TRAFFIC_CLASS) >= 0);// it is okay that 5 is not returned // 5 value will only be set if the channels' family equals StandardProtocolFamily.INET assertTrue(channel.getOption(Options.KEEP_ALIVE)); assertEquals(234095747, (int) channel.getOption(Options.READ_TIMEOUT)); assertTrue(channel.getOption(Options.RECEIVE_BUFFER) > 0); assertTrue(channel.getOption(Options.SEND_BUFFER) >= 3000); assertTrue(channel.getOption(Options.TCP_NODELAY)); assertTrue(channel.getOption(Options.TCP_OOB_INLINE)); assertEquals(1301093, (int) channel.getOption(Options.WRITE_TIMEOUT)); assertTrue(channel.getOption(Options.CLOSE_ABORT)); assertNull(channel.getOption(Options.MAX_INBOUND_MESSAGE_SIZE));// unsupported assertTrue(channel.setOption(Options.CLOSE_ABORT, false)); assertTrue(channel.setOption(Options.IP_TRAFFIC_CLASS, 30) >= 0); assertTrue(channel.setOption(Options.KEEP_ALIVE, false)); assertEquals(234095747, (int) channel.setOption(Options.READ_TIMEOUT, 1290455)); assertTrue(channel.setOption(Options.RECEIVE_BUFFER, 3000) >= 5000); assertTrue(channel.setOption(Options.SEND_BUFFER, 5000) >= 3000); assertTrue(channel.setOption(Options.TCP_NODELAY, false)); assertTrue(channel.setOption(Options.TCP_OOB_INLINE, false)); assertEquals(1301093, (int) channel.setOption(Options.WRITE_TIMEOUT, 293265)); assertFalse(channel.getOption(Options.CLOSE_ABORT)); assertTrue(channel.getOption(Options.IP_TRAFFIC_CLASS) >= 0); assertFalse(channel.getOption(Options.KEEP_ALIVE)); assertEquals(1290455, (int) channel.getOption(Options.READ_TIMEOUT)); assertTrue(channel.getOption(Options.RECEIVE_BUFFER) > 0); assertEquals(5000, (int) channel.getOption(Options.SEND_BUFFER)); assertFalse(channel.getOption(Options.TCP_NODELAY)); assertFalse(channel.getOption(Options.TCP_OOB_INLINE)); assertEquals(293265, (int) channel.getOption(Options.WRITE_TIMEOUT)); assertFalse(channel.setOption(Options.CLOSE_ABORT, null)); assertFalse(channel.setOption(Options.KEEP_ALIVE, null)); assertEquals(1290455, (int) channel.setOption(Options.READ_TIMEOUT, null)); assertFalse(channel.setOption(Options.TCP_NODELAY, null)); assertFalse(channel.setOption(Options.TCP_OOB_INLINE, null)); assertEquals(293265, (int) channel.setOption(Options.WRITE_TIMEOUT, null)); assertFalse(channel.getOption(Options.CLOSE_ABORT)); assertEquals(0, (int) channel.getOption(Options.IP_TRAFFIC_CLASS)); assertFalse(channel.getOption(Options.KEEP_ALIVE)); assertEquals(0, (int) channel.getOption(Options.READ_TIMEOUT)); assertTrue(channel.getOption(Options.RECEIVE_BUFFER) > 0); assertTrue(channel.getOption(Options.SEND_BUFFER) > 0); assertNotNull(channel.getOption(Options.TCP_NODELAY)); assertFalse(channel.getOption(Options.TCP_OOB_INLINE)); assertEquals(0, (int) channel.getOption(Options.WRITE_TIMEOUT)); } @Test public void channelAddress() throws IOException { initChannels(); assertEquals(bindAddress, channel.getPeerAddress()); assertEquals(bindAddress, channel.getPeerAddress(InetSocketAddress.class)); assertNull(channel.getPeerAddress(LocalSocketAddress.class)); final SocketAddress clientAddress = channel.getLocalAddress(); assertNotNull(clientAddress); assertEquals(clientAddress, channel.getLocalAddress((InetSocketAddress.class))); assertNull(channel.getLocalAddress((LocalSocketAddress.class))); assertNotNull(channel.toString()); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/TcpConnectionTestCase.java000066400000000000000000000245261257016060700303310ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.Inet4Address; import java.net.InetSocketAddress; import java.net.SocketAddress; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.xnio.ChannelListener; import org.xnio.FutureResult; import org.xnio.IoFuture; import org.xnio.LocalSocketAddress; import org.xnio.Option; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.StreamConnection; import org.xnio.XnioWorker; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.StreamSinkChannel; import org.xnio.channels.StreamSourceChannel; /** * Tests a pair of connected TCP connections (client/server). * * @author Flavia Rainone */ public class TcpConnectionTestCase extends AbstractStreamSinkSourceChannelTest { protected SocketAddress bindAddress; protected StreamConnection connection = null; protected StreamConnection serverConnection = null; protected AcceptingChannel server; @Before public void createServer() throws IOException { bindAddress = new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), 12345); final ChannelListener> acceptingChannelListener = new TestChannelListener>();; server = worker.createStreamConnectionServer( bindAddress, acceptingChannelListener, OptionMap.EMPTY); assertNotNull(server); } @After public void closeServer() throws IOException { server.close(); } @Override protected synchronized void initChannels(XnioWorker xnioWorker, OptionMap optionMap, TestChannelListener channelListener, TestChannelListener serverChannelListener) throws IOException { if (connection != null) { connection.close(); serverConnection.close(); } final IoFuture openedConnection = xnioWorker.openStreamConnection(bindAddress, null, optionMap); final FutureResult accepted = new FutureResult(xnioWorker); server.getIoThread().execute(new Runnable() { public void run() { try { accepted.setResult(server.accept()); } catch (IOException e) { accepted.setException(e); } } }); serverConnection = accepted.getIoFuture().get(); connection = openedConnection.get(); assertNotNull(serverConnection); assertNotNull(connection); channelListener.handleEvent(connection.getSinkChannel()); serverChannelListener.handleEvent(serverConnection.getSourceChannel()); } @Test public void optionSetup() throws IOException { initChannels(); final Option[] unsupportedOptions = OptionHelper.getNotSupportedOptions(Options.CLOSE_ABORT, Options.IP_TRAFFIC_CLASS, Options.KEEP_ALIVE, Options.READ_TIMEOUT, Options.RECEIVE_BUFFER, Options.RECEIVE_BUFFER, Options.SEND_BUFFER, Options.TCP_NODELAY, Options.TCP_OOB_INLINE, Options.WRITE_TIMEOUT); for (Option option: unsupportedOptions) { assertFalse("Channel supports " + option, connection.supportsOption(option)); assertNull("Expected null value for option " + option + " but got " + connection.getOption(option) + " instead", connection.getOption(option)); } assertTrue(connection.supportsOption(Options.CLOSE_ABORT)); assertFalse(connection.getOption(Options.CLOSE_ABORT)); assertTrue(connection.supportsOption(Options.IP_TRAFFIC_CLASS)); assertEquals(0, (int) connection.getOption(Options.IP_TRAFFIC_CLASS)); assertTrue(connection.supportsOption(Options.KEEP_ALIVE)); assertFalse(connection.getOption(Options.KEEP_ALIVE)); assertTrue(connection.supportsOption(Options.READ_TIMEOUT)); assertEquals(0, (int) connection.getOption(Options.READ_TIMEOUT)); assertTrue(connection.supportsOption(Options.RECEIVE_BUFFER)); assertTrue(connection.getOption(Options.RECEIVE_BUFFER) > 0); assertTrue(connection.supportsOption(Options.SEND_BUFFER)); assertTrue(connection.getOption(Options.SEND_BUFFER) > 0); assertTrue(connection.supportsOption(Options.TCP_NODELAY)); assertNotNull(connection.getOption(Options.TCP_NODELAY)); assertTrue(connection.supportsOption(Options.TCP_OOB_INLINE)); assertFalse(connection.getOption(Options.TCP_OOB_INLINE)); assertTrue(connection.supportsOption(Options.WRITE_TIMEOUT)); assertEquals(0, (int) connection.getOption(Options.WRITE_TIMEOUT)); connection.setOption(Options.CLOSE_ABORT, true); connection.setOption(Options.IP_TRAFFIC_CLASS, 5); connection.setOption(Options.KEEP_ALIVE, true); connection.setOption(Options.READ_TIMEOUT, 234095747); connection.setOption(Options.RECEIVE_BUFFER, 5000); connection.setOption(Options.SEND_BUFFER, 3000); connection.setOption(Options.TCP_NODELAY, true); connection.setOption(Options.TCP_OOB_INLINE, true); connection.setOption(Options.WRITE_TIMEOUT, 1301093); assertNull("Unexpected option value: " + connection.getOption(Options.MAX_INBOUND_MESSAGE_SIZE), connection.setOption(Options.MAX_INBOUND_MESSAGE_SIZE, 50000));// unsupported assertTrue(connection.getOption(Options.CLOSE_ABORT)); assertTrue(connection.getOption(Options.IP_TRAFFIC_CLASS) >= 0);// it is okay that 5 is not returned // 5 value will only be set if the channels' family equals StandardProtocolFamily.INET assertTrue(connection.getOption(Options.KEEP_ALIVE)); assertEquals(234095747, (int) connection.getOption(Options.READ_TIMEOUT)); assertTrue(connection.getOption(Options.RECEIVE_BUFFER) > 0); assertTrue(connection.getOption(Options.SEND_BUFFER) >= 3000); assertTrue(connection.getOption(Options.TCP_NODELAY)); assertTrue(connection.getOption(Options.TCP_OOB_INLINE)); assertEquals(1301093, (int) connection.getOption(Options.WRITE_TIMEOUT)); assertTrue(connection.getOption(Options.CLOSE_ABORT)); assertNull(connection.getOption(Options.MAX_INBOUND_MESSAGE_SIZE));// unsupported assertTrue(connection.setOption(Options.CLOSE_ABORT, false)); assertTrue(connection.setOption(Options.IP_TRAFFIC_CLASS, 30) >= 0); assertTrue(connection.setOption(Options.KEEP_ALIVE, false)); assertEquals(234095747, (int) connection.setOption(Options.READ_TIMEOUT, 1290455)); assertTrue(connection.setOption(Options.RECEIVE_BUFFER, 3000) >= 5000); assertTrue(connection.setOption(Options.SEND_BUFFER, 5000) >= 3000); assertTrue(connection.setOption(Options.TCP_NODELAY, false)); assertTrue(connection.setOption(Options.TCP_OOB_INLINE, false)); assertEquals(1301093, (int) connection.setOption(Options.WRITE_TIMEOUT, 293265)); assertFalse(connection.getOption(Options.CLOSE_ABORT)); assertTrue(connection.getOption(Options.IP_TRAFFIC_CLASS) >= 0); assertFalse(connection.getOption(Options.KEEP_ALIVE)); assertEquals(1290455, (int) connection.getOption(Options.READ_TIMEOUT)); assertTrue(connection.getOption(Options.RECEIVE_BUFFER) > 0); assertEquals(5000, (int) connection.getOption(Options.SEND_BUFFER)); assertFalse(connection.getOption(Options.TCP_NODELAY)); assertFalse(connection.getOption(Options.TCP_OOB_INLINE)); assertEquals(293265, (int) connection.getOption(Options.WRITE_TIMEOUT)); assertFalse(connection.setOption(Options.CLOSE_ABORT, null)); assertFalse(connection.setOption(Options.KEEP_ALIVE, null)); assertEquals(1290455, (int) connection.setOption(Options.READ_TIMEOUT, null)); assertFalse(connection.setOption(Options.TCP_NODELAY, null)); assertFalse(connection.setOption(Options.TCP_OOB_INLINE, null)); assertEquals(293265, (int) connection.setOption(Options.WRITE_TIMEOUT, null)); assertFalse(connection.getOption(Options.CLOSE_ABORT)); assertEquals(0, (int) connection.getOption(Options.IP_TRAFFIC_CLASS)); assertFalse(connection.getOption(Options.KEEP_ALIVE)); assertEquals(0, (int) connection.getOption(Options.READ_TIMEOUT)); assertTrue(connection.getOption(Options.RECEIVE_BUFFER) > 0); assertTrue(connection.getOption(Options.SEND_BUFFER) > 0); assertNotNull(connection.getOption(Options.TCP_NODELAY)); assertFalse(connection.getOption(Options.TCP_OOB_INLINE)); assertEquals(0, (int) connection.getOption(Options.WRITE_TIMEOUT)); } @Test public void channelAddress() throws IOException { initChannels(); assertEquals(bindAddress, connection.getPeerAddress()); assertEquals(bindAddress, connection.getPeerAddress(InetSocketAddress.class)); assertNull(connection.getPeerAddress(LocalSocketAddress.class)); final SocketAddress clientAddress = connection.getLocalAddress(); assertNotNull(clientAddress); assertEquals(clientAddress, connection.getLocalAddress((InetSocketAddress.class))); assertNull(connection.getLocalAddress((LocalSocketAddress.class))); assertNotNull(connection.toString()); } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/TcpServerTest.java000066400000000000000000000117451257016060700267030ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.Inet4Address; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.util.concurrent.TimeUnit; import org.junit.After; import org.junit.AfterClass; import org.junit.BeforeClass; import org.xnio.LocalSocketAddress; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.Xnio; import org.xnio.XnioWorker; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.ConnectedStreamChannel; /** * Super class common to all TCP server tests. * * @author Flavia Rainone * */ public abstract class TcpServerTest { protected static final int SERVER_PORT = 12345; private static int workerWriteThreadsValue; private static int workerReadThreadsValue; private static SocketAddress bindAddress; protected static Xnio xnio; private static XnioWorker worker; protected AcceptingChannel server; @SuppressWarnings("deprecation") @BeforeClass public static void createWorker() throws IOException { int readThreads = (int) Math.round(Math.random() * 10); if (readThreads == 0) { readThreads = 1; } workerReadThreadsValue = readThreads; int writeThreads = (int) Math.round(Math.random() * 10); if (writeThreads == 0) { writeThreads = 1; } workerWriteThreadsValue = writeThreads; xnio = Xnio.getInstance("nio", TcpServerTest.class.getClassLoader()); worker = xnio.createWorker(OptionMap.create(Options.WORKER_WRITE_THREADS, workerWriteThreadsValue, Options.WORKER_READ_THREADS, workerReadThreadsValue)); bindAddress = new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), SERVER_PORT); } @AfterClass public static void destroyWorker() throws InterruptedException { worker.shutdown(); worker.awaitTermination(1L, TimeUnit.MINUTES); } /** * Utility method to create the server. The field server is updated with the value of the server created. *

Every server created by this method will be automatically closed after the test executes, or as soon as a * new request to create a server is made. * * @param optionMap the options that will be used to create the server */ protected void createServer(OptionMap optionMap) throws IOException { createServer(worker, optionMap); } /** * Utility method to create the server. The field server is updated with the value of the server created. *

Every server created by this method will be automatically closed after the test executes, or as soon as a * new request to create a server is made. * * @param worker the worker * @param optionMap the options that will be used to create the server */ @SuppressWarnings("deprecation") protected void createServer(XnioWorker worker, OptionMap optionMap) throws IOException { if (server != null) { server.close(); assertFalse(server.isOpen()); } server = worker.createStreamServer(bindAddress, null, optionMap); assertTrue(server.isOpen()); assertNotNull(server); assertEquals(bindAddress, server.getLocalAddress()); assertEquals(bindAddress, server.getLocalAddress(InetSocketAddress.class)); assertNull(server.getLocalAddress(LocalSocketAddress.class)); } /** * Returns the number of write threads in the worker, which is randomly generated at every execution. */ protected static int getWorkerWriteThreads() { return workerWriteThreadsValue; } /** * Returns the number of readthreads in the worker, which is randomly generated at every execution. */ protected static int getWorkerReadThreads() { return workerReadThreadsValue; } @After public void closeServer() throws IOException { if (server != null) { server.close(); assertFalse(server.isOpen()); } } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/TestChannelListener.java000066400000000000000000000043361257016060700300420ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xnio.nio.test; import java.nio.channels.Channel; import java.util.concurrent.CountDownLatch; import org.xnio.ChannelListener; /** * Utility channel listener. * * @author Flavia Rainone * */ class TestChannelListener implements ChannelListener { private boolean invoked = false; private C channel = null; private CountDownLatch latch = new CountDownLatch(1); @Override public synchronized void handleEvent(C c) { invoked = true; channel = c; latch.countDown(); } public boolean isInvoked() { final CountDownLatch currentLatch; synchronized (this) { currentLatch = latch; } try { currentLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } synchronized (this) { return invoked; } } public synchronized boolean isInvokedYet() { return invoked; } public synchronized C getChannel() { return channel; } public synchronized void clear() { invoked = false; channel = null; latch = new CountDownLatch(1); } }xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/UdpChannelTestCase.java000066400000000000000000000573341257016060700276070ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2013 Red Hat, Inc., and individual contributors * as indicated by the @author tags. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.InetSocketAddress; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.util.concurrent.TimeUnit; import org.junit.Ignore; import org.junit.Test; import org.xnio.Buffers; import org.xnio.LocalSocketAddress; import org.xnio.Option; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.Xnio; import org.xnio.XnioWorker; import org.xnio.channels.MulticastMessageChannel; import org.xnio.channels.SocketAddressBuffer; /** * Test for the UDP channel. * * @author Flavia Rainone * */ public class UdpChannelTestCase { private static final InetSocketAddress address1 = new InetSocketAddress("localhost", 1050); private static final InetSocketAddress address2 = new InetSocketAddress("localhost", 2050); private static final Xnio xnio = Xnio.getInstance(); @Test public void addressRetrieval() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final MulticastMessageChannel server1 = xnioWorker.createUdpServer(address1, OptionMap.EMPTY); final MulticastMessageChannel server2 = xnioWorker.createUdpServer(address2, OptionMap.EMPTY); try { assertEquals(address1, server1.getLocalAddress()); assertEquals(address1, server1.getLocalAddress(InetSocketAddress.class)); assertNull(server1.getLocalAddress(LocalSocketAddress.class)); assertEquals(address2, server2.getLocalAddress()); assertEquals(address2, server2.getLocalAddress(InetSocketAddress.class)); assertNull(server2.getLocalAddress(LocalSocketAddress.class)); } finally { server1.close(); server2.close(); xnioWorker.shutdown(); } } @Test public void testSimpleConnection() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final MulticastMessageChannel server1 = xnioWorker.createUdpServer(address1, OptionMap.EMPTY); final MulticastMessageChannel server2 = xnioWorker.createUdpServer(address2, OptionMap.EMPTY); assertTrue(server1.isOpen()); assertTrue(server2.isOpen()); try { final ByteBuffer buffer = ByteBuffer.allocate(10); buffer.put("1234567890".getBytes()).flip(); assertTrue(server2.sendTo(address1, buffer)); final ByteBuffer receiveBuffer = ByteBuffer.allocate(10); SocketAddressBuffer addressBuffer = new SocketAddressBuffer(); assertEquals(10, server1.receiveFrom(addressBuffer, receiveBuffer)); receiveBuffer.flip(); assertEquals("1234567890", Buffers.getModifiedUtf8(receiveBuffer)); assertEquals(address2, addressBuffer.getSourceAddress()); assertNull(addressBuffer.getDestinationAddress()); buffer.clear(); buffer.put("0987654321".getBytes()).flip(); assertTrue(server1.sendTo(address2, buffer)); receiveBuffer.clear(); addressBuffer = new SocketAddressBuffer(); assertEquals(10, server2.receiveFrom(null, receiveBuffer)); receiveBuffer.flip(); assertEquals("0987654321", Buffers.getModifiedUtf8(receiveBuffer)); assertTrue(server1.isOpen()); assertTrue(server2.isOpen()); } finally { server1.close(); server2.close(); xnioWorker.shutdown(); assertFalse(server1.isOpen()); assertFalse(server2.isOpen()); } } @Test @Ignore("Does not follow thread model") public void testChannelWithOneThreadOnly() throws IllegalArgumentException, IOException { final XnioWorker xnioWorker1 = xnio.createWorker(OptionMap.create(Options.WORKER_IO_THREADS, 1)); final XnioWorker xnioWorker2 = xnio.createWorker(OptionMap.create(Options.WORKER_IO_THREADS, 1)); final MulticastMessageChannel server1 = xnioWorker1.createUdpServer(address1, OptionMap.EMPTY); final MulticastMessageChannel server2 = xnioWorker2.createUdpServer(address2, OptionMap.EMPTY); assertTrue(server1.isOpen()); assertTrue(server2.isOpen()); try { final ByteBuffer buffer = ByteBuffer.allocate(15); buffer.put("msg to server 2".getBytes()).flip(); assertTrue(server1.sendTo(address2, buffer)); final ByteBuffer receiveBuffer = ByteBuffer.allocate(15); SocketAddressBuffer addressBuffer = new SocketAddressBuffer(); assertEquals(15, server2.receiveFrom(addressBuffer, receiveBuffer)); receiveBuffer.flip(); assertEquals("msg to server 2", Buffers.getModifiedUtf8(receiveBuffer)); assertEquals(address1, addressBuffer.getSourceAddress()); assertNull(addressBuffer.getDestinationAddress()); buffer.clear(); buffer.put("msg to server 1".getBytes()).flip(); assertTrue(server2.sendTo(address1, buffer)); receiveBuffer.clear(); assertEquals(15, server1.receiveFrom(null, receiveBuffer)); receiveBuffer.flip(); assertEquals("msg to server 1", Buffers.getModifiedUtf8(receiveBuffer)); assertTrue(server1.isOpen()); assertTrue(server2.isOpen()); TestChannelListener server1Listener = new TestChannelListener(); server1.getWriteSetter().set(server1Listener); server1.resumeWrites(); server1.wakeupWrites(); assertTrue(server1Listener.isInvoked()); assertFalse(server1.isReadResumed()); assertTrue(server1.isWriteResumed()); server1.suspendReads(); server1.suspendWrites(); assertFalse(server1.isReadResumed()); assertFalse(server1.isWriteResumed()); TestChannelListener server2Listener = new TestChannelListener(); server2.getReadSetter().set(server2Listener); server2.resumeReads(); server2.wakeupReads(); assertTrue(server2Listener.isInvoked()); assertTrue(server2.isReadResumed()); assertFalse(server2.isWriteResumed()); server2.suspendReads(); server2.suspendWrites(); assertFalse(server2.isReadResumed()); assertFalse(server2.isWriteResumed()); } finally { server1.close(); server2.close(); xnioWorker1.shutdown(); xnioWorker2.shutdown(); assertFalse(server1.isOpen()); assertFalse(server2.isOpen()); } } @SuppressWarnings("deprecation") @Test public void communicateUsingClosedChannel() throws IOException { final XnioWorker xnioWorker1 = xnio.createWorker(OptionMap.create(Options.WORKER_READ_THREADS, 0)); final XnioWorker xnioWorker2 = xnio.createWorker(OptionMap.create(Options.WORKER_WRITE_THREADS, 0)); final MulticastMessageChannel server1 = xnioWorker1.createUdpServer(address1, OptionMap.EMPTY); final MulticastMessageChannel server2 = xnioWorker2.createUdpServer(address2, OptionMap.EMPTY); assertTrue(server1.isOpen()); assertTrue(server2.isOpen()); server1.close(); assertFalse(server1.isOpen()); assertTrue(server2.isOpen()); try { assertTrue(server1.flush()); assertTrue(server2.flush()); final ByteBuffer buffer = ByteBuffer.allocate(15); buffer.put("attempt to send".getBytes()).flip(); ClosedChannelException expected = null; try { server1.sendTo(address2, buffer); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { server1.sendTo(address2, new ByteBuffer[]{buffer}); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); expected = null; try { server1.sendTo(address2, new ByteBuffer[]{buffer, buffer, buffer}, 0, 2); } catch (ClosedChannelException e) { expected = e; } assertNotNull(expected); final SocketAddressBuffer addressBuffer = new SocketAddressBuffer(); final ByteBuffer receiveBuffer = ByteBuffer.allocate(3); expected = null; assertEquals(-1, server1.receiveFrom(addressBuffer, receiveBuffer)); assertEquals(-1, server1.receiveFrom(addressBuffer, new ByteBuffer[]{receiveBuffer})); assertEquals(-1, server1.receiveFrom(addressBuffer, new ByteBuffer[]{receiveBuffer, receiveBuffer, receiveBuffer})); assertFalse(server2.sendTo(address1, buffer)); assertEquals(0, server2.receiveFrom(addressBuffer, receiveBuffer)); assertTrue(server1.flush()); assertTrue(server1.flush()); assertTrue(server2.flush()); } finally { server2.close(); xnioWorker1.shutdown(); xnioWorker2.shutdown(); assertFalse(server1.isOpen()); assertFalse(server2.isOpen()); } } @Test public void sendEmptyBuffer() throws IOException { @SuppressWarnings("deprecation") final XnioWorker xnioWorker = xnio.createWorker(OptionMap.create(Options.WORKER_READ_THREADS, 0)); final MulticastMessageChannel server = xnioWorker.createUdpServer(address1, OptionMap.EMPTY); assertTrue(server.isOpen()); try { assertFalse(server.sendTo(address2, Buffers.EMPTY_BYTE_BUFFER)); } finally { server.close(); xnioWorker.shutdown(); } } @Test public void sendAndReceiveMultipleBuffers() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final MulticastMessageChannel server1 = xnioWorker.createUdpServer(address1, OptionMap.EMPTY); final MulticastMessageChannel server2 = xnioWorker.createUdpServer(address2, OptionMap.EMPTY); assertTrue(server1.isOpen()); assertTrue(server2.isOpen()); try { final ByteBuffer[] buffers = new ByteBuffer[] {Buffers.EMPTY_BYTE_BUFFER, ByteBuffer.allocate(10), ByteBuffer.allocate(5), ByteBuffer.allocate(1), ByteBuffer.allocate(1), ByteBuffer.allocate(1), ByteBuffer.allocate(2)}; buffers[1].put("nio udp".getBytes()).flip(); buffers[2].put("test".getBytes()).flip(); buffers[3].put((byte) 'c').flip(); buffers[4].put((byte) 'a').flip(); buffers[5].put((byte) 's').flip(); buffers[6].put("e!".getBytes()).flip(); assertTrue(server2.sendTo(address1, buffers, 0, 2)); final ByteBuffer[] receiveBuffers = new ByteBuffer[]{ByteBuffer.allocate(5), ByteBuffer.allocate(6), ByteBuffer.allocate(8)}; SocketAddressBuffer addressBuffer = new SocketAddressBuffer(); assertEquals(5, server1.receiveFrom(addressBuffer, receiveBuffers, 0, 1)); receiveBuffers[0].flip(); assertEquals("nio u", Buffers.getModifiedUtf8(receiveBuffers[0])); assertEquals(address2, addressBuffer.getSourceAddress()); assertNull(addressBuffer.getDestinationAddress()); receiveBuffers[0].clear(); assertEquals(0, server1.receiveFrom(null, receiveBuffers, 0, 1)); assertFalse(server1.sendTo(address2, buffers, 0, 0)); assertEquals(0, server2.receiveFrom(null, receiveBuffers, 2, 0)); assertTrue(server2.sendTo(address1, buffers, 2, 1)); assertEquals(4, server1.receiveFrom(null, receiveBuffers)); receiveBuffers[0].flip(); assertEquals("test", Buffers.getModifiedUtf8(receiveBuffers[0])); receiveBuffers[0].clear(); assertFalse(server1.sendTo(address2, buffers, 0, 2)); addressBuffer = new SocketAddressBuffer(); assertEquals(0, server2.receiveFrom(addressBuffer, receiveBuffers, 0, 3)); assertEquals(address1, addressBuffer.getSourceAddress()); assertNull(addressBuffer.getDestinationAddress()); addressBuffer = new SocketAddressBuffer(); assertEquals(0, server2.receiveFrom(addressBuffer, receiveBuffers, 0, 3)); assertNull(addressBuffer.getSourceAddress()); assertNull(addressBuffer.getDestinationAddress()); buffers[1].flip(); buffers[2].flip(); assertTrue(server1.sendTo(address2, buffers)); assertEquals(16, server2.receiveFrom(addressBuffer, receiveBuffers)); receiveBuffers[0].flip(); assertEquals("nio u", Buffers.getModifiedUtf8(receiveBuffers[0])); receiveBuffers[1].flip(); assertEquals("dptest", Buffers.getModifiedUtf8(receiveBuffers[1])); receiveBuffers[2].flip(); assertEquals("case!", Buffers.getModifiedUtf8(receiveBuffers[2])); } finally { server1.close(); server2.close(); xnioWorker.shutdown(); assertFalse(server1.isOpen()); assertFalse(server2.isOpen()); } } @Test public void sendTooBigBuffer() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final MulticastMessageChannel server = xnioWorker.createUdpServer(address1, OptionMap.EMPTY); assertTrue(server.isOpen()); try { final ByteBuffer[] buffers = new ByteBuffer[] {ByteBuffer.allocate(65536), ByteBuffer.allocate(65536)}; buffers[0].limit(buffers[0].capacity()); IllegalArgumentException expected = null; try { server.sendTo(address1, buffers); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } finally { server.close(); xnioWorker.shutdown(); assertFalse(server.isOpen()); } } @Test public void shutdownReadsAndWrite() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final MulticastMessageChannel server = xnioWorker.createUdpServer(address1, OptionMap.EMPTY); try { UnsupportedOperationException expected = null; try { server.shutdownReads(); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); expected = null; try { server.shutdownWrites(); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); } finally { server.close(); xnioWorker.shutdown(); } } @Test public void awaitReadableWritable() throws IOException, InterruptedException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final MulticastMessageChannel server1 = xnioWorker.createUdpServer(address1, OptionMap.EMPTY); final MulticastMessageChannel server2 = xnioWorker.createUdpServer(address2, OptionMap.EMPTY); try { server1.awaitWritable(); final Thread readWaitThread1 = new Thread(new ReadableWaiter(server1)); final Thread readWaitThread2 = new Thread(new ReadableWaiter(server1, 7, TimeUnit.MICROSECONDS)); final Thread readWaitThread3 = new Thread(new ReadableWaiter(server1, 7, TimeUnit.DAYS)); readWaitThread1.start(); readWaitThread2.start(); readWaitThread3.start(); readWaitThread1.join(30); readWaitThread2.join(); readWaitThread3.join(30); assertTrue(readWaitThread1.isAlive()); assertTrue(readWaitThread3.isAlive()); server1.resumeReads(); readWaitThread1.join(20); readWaitThread3.join(20); assertTrue(readWaitThread1.isAlive()); assertTrue(readWaitThread3.isAlive()); final ByteBuffer buffer = ByteBuffer.allocate(3); buffer.put("msg".getBytes()).flip(); assertTrue(server2.sendTo(address1, buffer)); readWaitThread1.join(); readWaitThread3.join(); server1.awaitWritable(); server1.awaitWritable(10, TimeUnit.MICROSECONDS); } finally { server1.close(); server2.close(); xnioWorker.shutdown(); } } // @Test // public void join() throws IOException { // final InetAddress address = InetAddress.getByName("225.0.0.100"); // final NetworkInterface ni = NetworkInterface.getByName("wlan0"); // assertNotNull(ni); // // final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); // final MulticastMessageChannel server1 = xnioWorker.createUdpServer(address1, OptionMap.create(Options.MULTICAST, true)); // final MulticastMessageChannel server2 = xnioWorker.createUdpServer(address2, OptionMap.create(Options.MULTICAST, true)); // final InetSocketAddress address3 = new InetSocketAddress("localhost", 1051); // final InetSocketAddress address4 = new InetSocketAddress("localhost", 1052); // final InetSocketAddress address5 = new InetSocketAddress("localhost", 1053); // final InetSocketAddress address6 = new InetSocketAddress("localhost", 1054); // final InetSocketAddress address7 = new InetSocketAddress("localhost", 1055); // final MulticastMessageChannel server3 = xnioWorker.createUdpServer(address3, OptionMap.create(Options.MULTICAST, true)); // final MulticastMessageChannel server4 = xnioWorker.createUdpServer(address4, OptionMap.create(Options.MULTICAST, true)); // final MulticastMessageChannel server5 = xnioWorker.createUdpServer(address5, OptionMap.create(Options.MULTICAST, true)); // final MulticastMessageChannel server6 = xnioWorker.createUdpServer(address6, OptionMap.create(Options.MULTICAST, true)); // final MulticastMessageChannel server7 = xnioWorker.createUdpServer(address7, OptionMap.create(Options.MULTICAST, true)); // server1.setOption(Options.MULTICAST, true); // try { // server1.join(address, ni); // server2.join(address, ni); // server3.join(address, ni); // server4.join(address, ni); // // final ByteBuffer buffer = ByteBuffer.allocate(3); // buffer.put("abc".getBytes()).flip(); // // assertTrue(server5.sendTo(new InetSocketAddress(address, 950), buffer)); // // final ByteBuffer receiveBuffer = ByteBuffer.allocate(5); // SocketAddressBuffer addressBuffer = new SocketAddressBuffer(); // assertEquals(3, server3.receiveFrom(addressBuffer, receiveBuffer)); // } finally { // server1.close(); // server2.close(); // server3.close(); // server4.close(); // server5.close(); // server6.close(); // server7.close(); // xnioWorker.shutdown(); // } // } @Test public void optionSetup() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final MulticastMessageChannel server = xnioWorker.createUdpServer(address1, OptionMap.EMPTY); final Option[] unsupportedOptions = OptionHelper.getNotSupportedOptions(Options.BROADCAST, Options.RECEIVE_BUFFER, Options.SEND_BUFFER, Options.IP_TRAFFIC_CLASS, Options.MULTICAST_TTL); try { for (Option option: unsupportedOptions) { assertFalse("Server supports " + option, server.supportsOption(option)); assertNull("Expected null value for option " + option + " but got " + server.getOption(option) + " instead", server.getOption(option)); } assertTrue(server.supportsOption(Options.BROADCAST)); assertFalse(server.getOption(Options.BROADCAST)); assertTrue(server.supportsOption(Options.RECEIVE_BUFFER)); assertTrue(server.getOption(Options.RECEIVE_BUFFER) > 0); assertTrue(server.supportsOption(Options.SEND_BUFFER)); assertTrue(server.getOption(Options.SEND_BUFFER) > 0); assertTrue(server.supportsOption(Options.IP_TRAFFIC_CLASS)); assertNotNull(server.getOption(Options.IP_TRAFFIC_CLASS)); assertTrue(server.supportsOption(Options.MULTICAST_TTL)); assertNotNull(server.getOption(Options.MULTICAST_TTL)); assertFalse(server.setOption(Options.BROADCAST, true)); assertTrue(server.setOption(Options.RECEIVE_BUFFER, 30000) > 0); assertTrue(server.setOption(Options.SEND_BUFFER, 3000) > 0); assertNotNull(server.setOption(Options.IP_TRAFFIC_CLASS, 200)); assertNotNull(server.setOption(Options.MULTICAST_TTL, 150)); assertNull(server.setOption(Options.REUSE_ADDRESSES, true)); assertTrue(server.getOption(Options.BROADCAST)); assertEquals(30000, (int) server.getOption(Options.RECEIVE_BUFFER)); assertEquals(3000, (int) server.getOption(Options.SEND_BUFFER)); assertNotNull((int) server.getOption(Options.IP_TRAFFIC_CLASS)); // it is okay that 200 is not returned // 200 will only be set if the channels' family equals StandardProtocolFamily.INET assertEquals(150, (int) server.getOption(Options.MULTICAST_TTL)); assertNull(server.getOption(Options.REUSE_ADDRESSES)); } finally { server.close(); xnioWorker.shutdown(); } // TODO XNIO-171 we check setOption(*, null) } private class ReadableWaiter implements Runnable { private final MulticastMessageChannel channel; private final long timeout; private final TimeUnit timeoutUnit; public ReadableWaiter(MulticastMessageChannel c) { this(c, -1, null); } public ReadableWaiter(MulticastMessageChannel c, long t, TimeUnit tu) { channel = c; timeout = t; timeoutUnit = tu; } public void run() { try { if (timeout == -1) { channel.awaitReadable(); } else { channel.awaitReadable(timeout, timeoutUnit); } } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } } } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/XnioWorkerTestCase.java000066400000000000000000001157561257016060700277000ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * * Copyright 2013 Red Hat, Inc. and/or its affiliates, and individual * contributors as indicated by the @author tags. * * 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 org.xnio.nio.test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; import java.io.IOException; import java.net.Inet4Address; import java.net.InetSocketAddress; import java.net.SocketAddress; import java.nio.channels.Channel; import java.util.concurrent.CancellationException; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.xnio.ChannelListener; import org.xnio.IoFuture; import org.xnio.LocalSocketAddress; import org.xnio.OptionMap; import org.xnio.Options; import org.xnio.StreamConnection; import org.xnio.Xnio; import org.xnio.XnioWorker; import org.xnio.channels.AcceptingChannel; import org.xnio.channels.BoundChannel; import org.xnio.channels.ConnectedChannel; import org.xnio.channels.ConnectedStreamChannel; import org.xnio.channels.MulticastMessageChannel; /** * Test for XnioWorker. * * @author Flavia Rainone * */ @SuppressWarnings("deprecation") public class XnioWorkerTestCase { private static final int SERVER_PORT = 12345; private static SocketAddress bindAddress; private static XnioWorker worker; private static Xnio xnio; protected AcceptingChannel server; @BeforeClass public static void createWorker() throws IOException { xnio = Xnio.getInstance("nio", XnioWorkerTestCase.class.getClassLoader()); bindAddress = new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), SERVER_PORT); } @AfterClass public static void destroyWorker() throws InterruptedException { if (worker != null && !worker.isShutdown()) { worker.shutdown(); worker.awaitTermination(1L, TimeUnit.MINUTES); } } @Test public void illegalWorker() throws IOException { IllegalArgumentException expected = null; try { xnio.createWorker(OptionMap.create(Options.WORKER_IO_THREADS, -1)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { xnio.createWorker(OptionMap.create(Options.STACK_SIZE, -10000l)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void createTcpStreamServerAndConnect() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.create(Options.THREAD_DAEMON, true)); final ChannelListener> acceptingChannelListener = new TestChannelListener>();; final AcceptingChannel streamServer = xnioWorker.createStreamConnectionServer( bindAddress, acceptingChannelListener, OptionMap.create(Options.BROADCAST, true)); assertNotNull(streamServer); try { assertEquals(bindAddress, streamServer.getLocalAddress()); assertSame(xnioWorker, streamServer.getWorker()); final TestChannelListener connectionListener1 = new TestChannelListener(); final TestChannelListener connectionListener2 = new TestChannelListener(); final TestChannelListener bindListener = new TestChannelListener(); final IoFuture connection1 = xnioWorker.openStreamConnection(bindAddress, connectionListener1, OptionMap.create(Options.MAX_INBOUND_MESSAGE_SIZE, 50000, Options.WORKER_ESTABLISH_WRITING, true)); final IoFuture connection2 = xnioWorker.openStreamConnection(bindAddress, connectionListener2, bindListener, OptionMap.create(Options.MAX_OUTBOUND_MESSAGE_SIZE, 50000)); assertNotNull(connection1); assertNotNull(connection2); assertServerClientConnection(streamServer, bindListener, connection1.get(), connectionListener1, connection2.get(), connectionListener2); } finally { streamServer.close(); } } private void assertServerClientConnection(AcceptingChannel server, TestChannelListener bindListener, ConnectedChannel clientChannel1, final TestChannelListener clientListener1, ConnectedChannel clientChannel2, final TestChannelListener clientListener2) throws IOException { assertNotNull(server); assertNotNull(clientChannel1); assertNotNull(clientChannel2); try { assertTrue(clientListener1.isInvoked()); assertSame(clientChannel1, clientListener1.getChannel()); assertEquals(bindAddress, clientChannel1.getPeerAddress()); assertTrue(clientListener2.isInvoked()); assertSame(clientChannel2, clientListener2.getChannel()); assertTrue(bindListener.isInvoked()); final BoundChannel boundChannel = bindListener.getChannel(); assertNotNull(boundChannel); assertEquals(clientChannel2.getLocalAddress(), boundChannel.getLocalAddress()); assertEquals(clientChannel2.getLocalAddress(InetSocketAddress.class), boundChannel.getLocalAddress(InetSocketAddress.class)); assertEquals(clientChannel2.getLocalAddress(LocalSocketAddress.class), boundChannel.getLocalAddress(LocalSocketAddress.class)); assertSame(clientChannel2.getWorker(), boundChannel.getWorker()); assertEquals(clientChannel2.getOption(Options.SEND_BUFFER), boundChannel.getOption(Options.SEND_BUFFER)); clientChannel2.setOption(Options.SEND_BUFFER, 3000); assertEquals(3000, (int) boundChannel.getOption(Options.SEND_BUFFER)); assertEquals(bindAddress, clientChannel2.getPeerAddress()); assertTrue(boundChannel.supportsOption(Options.KEEP_ALIVE)); assertFalse(boundChannel.supportsOption(Options.CONNECTION_LOW_WATER)); assertNotNull(boundChannel.toString()); final TestChannelListener boundChannelCloseListener = new TestChannelListener(); boundChannel.getCloseSetter().set(boundChannelCloseListener); assertTrue(boundChannel.isOpen()); assertTrue(clientChannel2.isOpen()); assertFalse(boundChannelCloseListener.isInvokedYet()); boundChannel.close(); assertTrue(boundChannelCloseListener.isInvoked()); assertFalse(boundChannel.isOpen()); assertFalse(clientChannel2.isOpen()); } finally { clientChannel1.close(); clientChannel2.close(); } } @Test public void createTcpStreamChannelServerAndConnect() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.create(Options.THREAD_DAEMON, true)); final ChannelListener> acceptingChannelListener = new TestChannelListener>();; final AcceptingChannel streamServer = xnioWorker.createStreamServer( bindAddress, acceptingChannelListener, OptionMap.create(Options.BROADCAST, true)); assertNotNull(streamServer); try { assertEquals(bindAddress, streamServer.getLocalAddress()); assertSame(xnioWorker, streamServer.getWorker()); final TestChannelListener channelListener1 = new TestChannelListener(); final TestChannelListener channelListener2 = new TestChannelListener(); final TestChannelListener bindListener = new TestChannelListener(); final IoFuture connectedStreamChannel1 = xnioWorker.connectStream(bindAddress, channelListener1, OptionMap.create(Options.MAX_INBOUND_MESSAGE_SIZE, 50000, Options.WORKER_ESTABLISH_WRITING, true)); final IoFuture connectedStreamChannel2 = xnioWorker.connectStream(bindAddress, channelListener2, bindListener, OptionMap.create(Options.MAX_OUTBOUND_MESSAGE_SIZE, 50000)); assertNotNull(connectedStreamChannel1); assertNotNull(connectedStreamChannel2); assertServerClientConnection(streamServer, bindListener, connectedStreamChannel1.get(), channelListener1, connectedStreamChannel2.get(), channelListener2); } finally { streamServer.close(); } } @Test public void cancelOpenStreamConnection() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.create(Options.THREAD_DAEMON, true)); final ChannelListener> acceptingChannelListener = new TestChannelListener>();; final AcceptingChannel streamServer = xnioWorker.createStreamConnectionServer( bindAddress, acceptingChannelListener, OptionMap.create(Options.BROADCAST, true)); assertNotNull(streamServer); try { final TestChannelListener channelListener = new TestChannelListener(); final TestChannelListener bindListener = new TestChannelListener(); IoFuture connectedStreamChannel = null; do { if (connectedStreamChannel != null) { connectedStreamChannel.await(); final IoFuture.Status status = connectedStreamChannel.getStatus(); if (status == IoFuture.Status.DONE) { connectedStreamChannel.get().close(); } channelListener.clear(); } connectedStreamChannel = xnioWorker.openStreamConnection(bindAddress, channelListener, OptionMap.create(Options.MAX_INBOUND_MESSAGE_SIZE, 50000, Options.WORKER_ESTABLISH_WRITING, true)).cancel(); connectedStreamChannel.cancel(); } while (connectedStreamChannel.getStatus() != IoFuture.Status.CANCELLED); CancellationException expected = null; try { connectedStreamChannel.get(); } catch (CancellationException e) { expected = e; } assertNotNull(expected); assertSame(IoFuture.Status.CANCELLED, connectedStreamChannel.getStatus()); assertFalse(channelListener.isInvokedYet()); assertFalse(bindListener.isInvokedYet()); // make sure that the server is up and can accept more connections assertTrue(streamServer.isOpen()); final IoFuture anotherChannel = xnioWorker.openStreamConnection(bindAddress, null, OptionMap.EMPTY); assertNotNull(anotherChannel.get()); anotherChannel.get().close(); } finally { streamServer.close(); } } @Test public void cancelConnectStream() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.create(Options.THREAD_DAEMON, true)); final ChannelListener> acceptingChannelListener = new TestChannelListener>();; final AcceptingChannel streamServer = xnioWorker.createStreamServer( bindAddress, acceptingChannelListener, OptionMap.create(Options.BROADCAST, true)); assertNotNull(streamServer); try { final TestChannelListener channelListener = new TestChannelListener(); final TestChannelListener bindListener = new TestChannelListener(); IoFuture connectedStreamChannel = null; do { if (connectedStreamChannel != null) { connectedStreamChannel.await(); final IoFuture.Status status = connectedStreamChannel.getStatus(); if (status == IoFuture.Status.DONE) { connectedStreamChannel.get().close(); } channelListener.clear(); } connectedStreamChannel = xnioWorker.connectStream(bindAddress, channelListener, OptionMap.create(Options.MAX_INBOUND_MESSAGE_SIZE, 50000, Options.WORKER_ESTABLISH_WRITING, true)).cancel(); connectedStreamChannel.cancel(); } while (connectedStreamChannel.getStatus() != IoFuture.Status.CANCELLED); CancellationException expected = null; try { connectedStreamChannel.get(); } catch (CancellationException e) { expected = e; } assertNotNull(expected); assertSame(IoFuture.Status.CANCELLED, connectedStreamChannel.getStatus()); assertFalse(channelListener.isInvokedYet()); assertFalse(bindListener.isInvokedYet()); // make sure that the server is up and can accept more connections assertTrue(streamServer.isOpen()); final IoFuture anotherChannel = xnioWorker.connectStream(bindAddress, null, OptionMap.EMPTY); assertNotNull(anotherChannel.get()); anotherChannel.get().close(); } finally { streamServer.close(); } } @Test public void createLocalStreamConnectionServer() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); UnsupportedOperationException expected = null; try { xnioWorker.createStreamConnectionServer(new LocalSocketAddress("server"), null, OptionMap.EMPTY); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); } @Test public void createLocalStreamServer() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); UnsupportedOperationException expected = null; try { xnioWorker.createStreamServer(new LocalSocketAddress("server"), null, OptionMap.EMPTY); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); } @Test public void openLocalStreamConnection() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); UnsupportedOperationException expected = null; try { xnioWorker.openStreamConnection(new LocalSocketAddress("server for test"), null, OptionMap.EMPTY); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); } @Test public void connectLocalStream() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); UnsupportedOperationException expected = null; try { xnioWorker.connectStream(new LocalSocketAddress("server for test"), null, OptionMap.EMPTY); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); } @Test public void acceptStreamConnection() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final InetSocketAddress bindAddress2 = new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), 23456); final TestChannelListener channelListener1 = new TestChannelListener(); final TestChannelListener channelListener2 = new TestChannelListener(); final TestChannelListener bindListener1 = new TestChannelListener(); final TestChannelListener bindListener2 = new TestChannelListener(); final OptionMap optionMap = OptionMap.create(Options.READ_TIMEOUT, 800000); final IoFuture channelFuture1 = xnioWorker.acceptStreamConnection(bindAddress, channelListener1, bindListener1, optionMap); final IoFuture channelFuture2 = xnioWorker.acceptStreamConnection(bindAddress2, channelListener2, bindListener2, optionMap); final IoFuture connectedStreamChannel1 = xnioWorker.openStreamConnection(bindAddress, null, OptionMap.EMPTY); final IoFuture connectedStreamChannel2 = xnioWorker.openStreamConnection(bindAddress2, null, OptionMap.EMPTY); assertNotNull(connectedStreamChannel1); assertNotNull(connectedStreamChannel2); assertNotNull(channelFuture1); assertNotNull(channelFuture2); final StreamConnection channel1 = channelFuture1.get(); final StreamConnection channel2 = channelFuture2.get(); assertNotNull(channel1); assertNotNull(channel2); assertAcceptedChannels(xnioWorker, channel1, channelListener1, bindListener1, bindAddress, connectedStreamChannel1.get().getLocalAddress(), channel2, channelListener2, bindListener2, bindAddress2, connectedStreamChannel2.get().getLocalAddress()); } private void assertAcceptedChannels(XnioWorker worker, ConnectedChannel channel1, TestChannelListener channelListener1, TestChannelListener bindListener1, SocketAddress bindAddress1, SocketAddress peerAddress1, ConnectedChannel channel2, TestChannelListener channelListener2, TestChannelListener bindListener2, SocketAddress bindAddress2, SocketAddress peerAddress2) throws IOException { try { assertTrue(channelListener1.isInvoked()); assertSame(channel1, channelListener1.getChannel()); assertTrue(bindListener1.isInvoked()); assertEquals(peerAddress1, channel1.getPeerAddress()); final BoundChannel boundChannel1 = bindListener1.getChannel(); assertNotNull(boundChannel1); assertSame(worker, boundChannel1.getWorker()); assertEquals(bindAddress, boundChannel1.getLocalAddress()); assertNull(boundChannel1.getLocalAddress(LocalSocketAddress.class)); assertNotNull(boundChannel1.getCloseSetter()); assertFalse(boundChannel1.isOpen()); // expected assertFalse(boundChannel1.supportsOption(Options.KEEP_ALIVE)); assertNull(boundChannel1.getOption(Options.KEEP_ALIVE)); assertNull(boundChannel1.setOption(Options.KEEP_ALIVE, null)); assertNull(boundChannel1.getOption(Options.KEEP_ALIVE)); assertNotNull(boundChannel1.toString()); assertTrue(channelListener2.isInvoked()); assertSame(channel2, channelListener2.getChannel()); assertTrue(bindListener2.isInvoked()); assertEquals(peerAddress2, channel2.getPeerAddress()); final BoundChannel boundChannel2 = bindListener2.getChannel(); assertNotNull(boundChannel2); assertSame(worker, boundChannel2.getWorker()); assertEquals(bindAddress2, boundChannel2.getLocalAddress()); assertNull(boundChannel2.getLocalAddress(LocalSocketAddress.class)); assertNotNull(boundChannel2.getCloseSetter()); assertFalse(boundChannel2.isOpen()); // expected assertFalse(boundChannel2.supportsOption(Options.KEEP_ALIVE)); assertNull(boundChannel2.getOption(Options.KEEP_ALIVE)); assertNull(boundChannel2.setOption(Options.KEEP_ALIVE, null)); assertNull(boundChannel2.getOption(Options.KEEP_ALIVE)); assertNotNull(boundChannel2.toString()); } finally { channel1.close(); channel2.close(); } } @Test public void acceptTcpStream() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final InetSocketAddress bindAddress2 = new InetSocketAddress(Inet4Address.getByAddress(new byte[] { 127, 0, 0, 1 }), 23456); final TestChannelListener channelListener1 = new TestChannelListener(); final TestChannelListener channelListener2 = new TestChannelListener(); final TestChannelListener bindListener1 = new TestChannelListener(); final TestChannelListener bindListener2 = new TestChannelListener(); final OptionMap optionMap = OptionMap.create(Options.READ_TIMEOUT, 800000); final IoFuture channelFuture1 = xnioWorker.acceptStream(bindAddress, channelListener1, bindListener1, optionMap); final IoFuture channelFuture2 = xnioWorker.acceptStream(bindAddress2, channelListener2, bindListener2, optionMap); final IoFuture connectedStreamChannel1 = xnioWorker.connectStream(bindAddress, null, OptionMap.EMPTY); final IoFuture connectedStreamChannel2 = xnioWorker.connectStream(bindAddress2, null, OptionMap.EMPTY); assertNotNull(connectedStreamChannel1); assertNotNull(connectedStreamChannel2); assertNotNull(channelFuture1); assertNotNull(channelFuture2); final ConnectedStreamChannel channel1 = channelFuture1.get(); final ConnectedStreamChannel channel2 = channelFuture2.get(); assertNotNull(channel1); assertNotNull(channel2); assertAcceptedChannels(xnioWorker, channel1, channelListener1, bindListener1, bindAddress, connectedStreamChannel1.get().getLocalAddress(), channel2, channelListener2, bindListener2, bindAddress2, connectedStreamChannel2.get().getLocalAddress()); } @Test public void cancelAcceptStreamConnection() throws CancellationException, IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final TestChannelListener channelListener = new TestChannelListener(); final TestChannelListener bindListener = new TestChannelListener(); final IoFuture connectionFuture1 = xnioWorker.acceptStreamConnection(bindAddress, channelListener, bindListener, OptionMap.EMPTY); final IoFuture connection2 = xnioWorker.openStreamConnection(bindAddress, null, OptionMap.EMPTY); assertNotNull(connectionFuture1); assertNotNull(connection2); connectionFuture1.cancel(); CancellationException expected = null; try { connectionFuture1.get(); } catch (CancellationException e) { expected = e; } assertNotNull(expected); assertFalse(channelListener.isInvokedYet()); assertFalse(channelListener.isInvokedYet()); if (bindListener.isInvokedYet()) { BoundChannel boundChannel = bindListener.getChannel(); assertNotNull(boundChannel); assertFalse(boundChannel.isOpen()); } } @Test public void cancelAcceptTcpStream() throws CancellationException, IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final TestChannelListener channelListener = new TestChannelListener(); final TestChannelListener bindListener = new TestChannelListener(); final IoFuture channelFuture = xnioWorker.acceptStream(bindAddress, channelListener, bindListener, OptionMap.EMPTY); final IoFuture connectedStreamChannel = xnioWorker.connectStream(bindAddress, null, OptionMap.EMPTY); assertNotNull(connectedStreamChannel); assertNotNull(channelFuture); channelFuture.cancel(); CancellationException expected = null; try { channelFuture.get(); } catch (CancellationException e) { expected = e; } assertNotNull(expected); assertFalse(channelListener.isInvokedYet()); if (bindListener.isInvokedYet()) { BoundChannel boundChannel = bindListener.getChannel(); assertNotNull(boundChannel); assertFalse(boundChannel.isOpen()); } } @Test public void acceptLocalStream() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); UnsupportedOperationException expected = null; try { xnioWorker.acceptStream(new LocalSocketAddress("local address"), null, null, OptionMap.EMPTY); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); expected = null; try { xnioWorker.acceptStreamConnection(new LocalSocketAddress("local address"), null, null, OptionMap.EMPTY); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); } @Test public void connectTcpDatagram() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); IllegalArgumentException expected = null; try { xnioWorker.connectDatagram(bindAddress, null, null, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void connectLocalDatagram() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); UnsupportedOperationException expected = null; try { xnioWorker.connectDatagram(new LocalSocketAddress("local"), null, null, OptionMap.EMPTY); } catch (UnsupportedOperationException e) { expected = e; } assertNotNull(expected); } @Test public void acceptDatagram() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); IllegalArgumentException expected = null; try { xnioWorker.acceptDatagram(bindAddress, null, null, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void acceptMessageConnection() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); IllegalArgumentException expected = null; try { xnioWorker.acceptMessageConnection(bindAddress, null, null, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } @Test public void createUdpServer() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final InetSocketAddress address = new InetSocketAddress(0); final OptionMap optionMap = OptionMap.create(Options.MULTICAST, true, Options.SECURE, false); final MulticastMessageChannel channel = xnioWorker.createUdpServer(address, optionMap); assertNotNull(channel); try { // check address assertNotNull(channel.getLocalAddress()); } finally { channel.close(); } } @Test public void createUdpServerWithListener() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); final InetSocketAddress address = new InetSocketAddress(0); final TestChannelListener listener = new TestChannelListener(); final OptionMap optionMap = OptionMap.create(Options.MULTICAST, true, Options.SECURE, true); final MulticastMessageChannel channel = xnioWorker.createUdpServer(address, listener, optionMap); assertNotNull(channel); try { // check address assertNotNull(channel.getLocalAddress()); // check listener assertTrue(listener.isInvoked()); assertSame(channel, listener.getChannel()); } finally { channel.close(); } } @Test public void createFullDuplexPipe() throws IOException { final XnioWorker xnioWorker = xnio.createWorker(OptionMap.EMPTY); assertNotNull(xnioWorker.createFullDuplexPipe()); assertNotNull(xnioWorker.createHalfDuplexPipe()); } @Test public void shutdownNowWithTerminationTask() throws IOException, InterruptedException { final TerminationTask terminationTask = new TerminationTask(); final XnioWorker xnioWorker = xnio.createWorker(Thread.currentThread().getThreadGroup(), OptionMap.EMPTY, terminationTask); assertFalse(xnioWorker.isShutdown()); assertFalse(xnioWorker.isTerminated()); xnioWorker.shutdownNow(); assertTrue(xnioWorker.isShutdown()); if (!xnioWorker.isTerminated()) { xnioWorker.awaitTermination(); } assertTrue(terminationTask.isInvoked()); assertTrue(xnioWorker.isShutdown()); assertTrue(xnioWorker.isTerminated()); xnioWorker.awaitTermination(); // idempotent xnioWorker.shutdown(); xnioWorker.shutdownNow(); } @Test public void awaitTerminationWithMultipleAwaiters1() throws IOException, InterruptedException { final XnioWorker worker = xnio.createWorker(OptionMap.EMPTY); final TerminationAwaiter awaiter1 = new TerminationAwaiter(worker); final TerminationAwaiter awaiter2 = new TerminationAwaiter(worker, 10, TimeUnit.HOURS); final TerminationAwaiter awaiter3 = new TerminationAwaiter(worker, 10, TimeUnit.MILLISECONDS); final Thread thread1 = new Thread(awaiter1); final Thread thread2 = new Thread(awaiter2); final Thread thread3 = new Thread(awaiter3); thread1.start(); thread2.start(); thread3.start(); thread1.join(20); thread2.join(20); thread3.join(); assertFalse(awaiter3.isInterrupted()); assertTrue(thread1.isAlive()); assertTrue(thread2.isAlive()); worker.shutdown(); thread1.join(); thread2.join(); assertFalse(awaiter1.isInterrupted()); assertFalse(awaiter2.isInterrupted()); } @Test public void awaitTerminationWithMultipleAwaiters2() throws IOException, InterruptedException { final XnioWorker worker = xnio.createWorker(OptionMap.EMPTY); final TerminationAwaiter awaiter1 = new TerminationAwaiter(worker); final TerminationAwaiter awaiter2 = new TerminationAwaiter(worker, 10, TimeUnit.HOURS); final TerminationAwaiter awaiter3 = new TerminationAwaiter(worker, 300, TimeUnit.MILLISECONDS); final TerminationAwaiter awaiter4 = new TerminationAwaiter(worker, 10, TimeUnit.MILLISECONDS); final TerminationAwaiter awaiter5 = new TerminationAwaiter(worker, 100, TimeUnit.MILLISECONDS); final TerminationAwaiter awaiter6 = new TerminationAwaiter(worker, 10, TimeUnit.MINUTES); final TerminationAwaiter awaiter7 = new TerminationAwaiter(worker, 1, TimeUnit.MILLISECONDS); final Thread thread1 = new Thread(awaiter1); final Thread thread2 = new Thread(awaiter2); final Thread thread3 = new Thread(awaiter3); final Thread thread4 = new Thread(awaiter4); final Thread thread5 = new Thread(awaiter5); final Thread thread6 = new Thread(awaiter6); final Thread thread7 = new Thread(awaiter7); thread1.start(); thread2.start(); thread3.start(); thread4.start(); thread5.start(); thread6.start(); thread7.start(); thread1.join(20); thread2.join(20); thread4.join(); thread5.join(); thread3.join(); thread6.join(20); thread7.join(); assertFalse(awaiter3.isInterrupted()); assertFalse(awaiter4.isInterrupted()); assertFalse(awaiter5.isInterrupted()); assertFalse(awaiter7.isInterrupted()); assertTrue(thread1.isAlive()); assertTrue(thread2.isAlive()); assertTrue(thread6.isAlive()); worker.shutdown(); thread1.join(); thread2.join(); thread6.join(); assertFalse(awaiter1.isInterrupted()); assertFalse(awaiter2.isInterrupted()); assertFalse(awaiter6.isInterrupted()); } @Test public void awaitTerminationWithMultipleAwaiters3() throws IOException, InterruptedException { final XnioWorker worker = xnio.createWorker(OptionMap.EMPTY); final TerminationAwaiter awaiter1 = new TerminationAwaiter(worker, 1, TimeUnit.NANOSECONDS); final TerminationAwaiter awaiter2 = new TerminationAwaiter(worker, 10, TimeUnit.HOURS); final TerminationAwaiter awaiter3 = new TerminationAwaiter(worker); final TerminationAwaiter awaiter4 = new TerminationAwaiter(worker, 3, TimeUnit.MILLISECONDS); final TerminationAwaiter awaiter5 = new TerminationAwaiter(worker); final Thread thread1 = new Thread(awaiter1); final Thread thread2 = new Thread(awaiter2); final Thread thread3 = new Thread(awaiter3); final Thread thread4 = new Thread(awaiter4); final Thread thread5 = new Thread(awaiter5); thread1.start(); thread2.start(); thread3.start(); thread4.start(); thread5.start(); thread1.join(); thread2.join(20); thread3.join(20); thread4.join(); thread5.join(20); assertFalse(awaiter1.isInterrupted()); assertFalse(awaiter4.isInterrupted()); assertTrue(thread2.isAlive()); assertTrue(thread3.isAlive()); assertTrue(thread5.isAlive()); worker.shutdown(); thread2.join(); thread3.join(); thread5.join(); assertFalse(awaiter2.isInterrupted()); assertFalse(awaiter3.isInterrupted()); assertFalse(awaiter5.isInterrupted()); } @Test public void interruptedAwaiters() throws IOException, InterruptedException { final XnioWorker worker = xnio.createWorker(OptionMap.EMPTY); final TerminationAwaiter awaiter1 = new TerminationAwaiter(worker); final TerminationAwaiter awaiter2 = new TerminationAwaiter(worker, 3, TimeUnit.MINUTES); final Thread thread1 = new Thread(awaiter1); final Thread thread2 = new Thread(awaiter2); thread1.start(); thread2.start(); thread1.interrupt(); thread2.interrupt(); thread1.join(); thread2.join(); assertTrue(awaiter1.isInterrupted()); assertTrue(awaiter2.isInterrupted()); worker.shutdown(); } @Test public void invalidAcceptStream() throws IOException { final XnioWorker worker = xnio.createWorker(OptionMap.create(Options.WORKER_READ_THREADS, 0, Options.WORKER_WRITE_THREADS, 0)); assertNotNull(worker); IllegalArgumentException expected = null; try { worker.acceptStream(bindAddress, null, null, OptionMap.EMPTY); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { worker.acceptStream(bindAddress, null, null, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, false)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); expected = null; try { worker.acceptStream(bindAddress, null, null, OptionMap.create(Options.WORKER_ESTABLISH_WRITING, false)); } catch (IllegalArgumentException e) { expected = e; } assertNotNull(expected); } private static class TestChannelListener implements ChannelListener { private boolean invoked = false; private C channel = null; private CountDownLatch latch = new CountDownLatch(1); @Override public void handleEvent(C c) { invoked = true; channel = c; latch.countDown(); } public boolean isInvoked() { try { latch.await(); } catch (InterruptedException e) { e.printStackTrace(); } return invoked; } public boolean isInvokedYet() { return invoked; } public C getChannel() { return channel; } public void clear() { invoked = false; } } private static class TerminationTask implements Runnable { private boolean invoked = false; private final CountDownLatch countDown = new CountDownLatch(1); @Override public void run() { invoked = true; countDown.countDown(); } public boolean isInvoked() { try { countDown.await(); } catch (InterruptedException e) { throw new RuntimeException(e); } return invoked; } } private static class TerminationAwaiter implements Runnable { private final XnioWorker xnioWorker; private final long timeout; private final TimeUnit timeoutUnit; private boolean interrupted; public TerminationAwaiter (XnioWorker w, long t, TimeUnit tu) { xnioWorker = w;; timeout = t; timeoutUnit = tu; } public TerminationAwaiter(XnioWorker w) { this(w, -1, null); } public void run() { try { if (timeoutUnit == null) { xnioWorker.awaitTermination(); } else { xnioWorker.awaitTermination(timeout, timeoutUnit); } } catch (InterruptedException e) { interrupted = true; } } public boolean isInterrupted() { return interrupted; } } } xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/racecondition/000077500000000000000000000000001257016060700260745ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/test/java/org/xnio/nio/test/racecondition/NullHelper.java000066400000000000000000000030231257016060700310070ustar00rootroot00000000000000/* * JBoss, Home of Professional Open Source. * Copyright 2012, Red Hat, Inc., and individual contributors * as indicated by the @author tags. See the copyright.txt file in the * distribution for a full listing of individual contributors. * * This is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser General Public License as * published by the Free Software Foundation; either version 2.1 of * the License, or (at your option) any later version. * * This software is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this software; if not, write to the Free * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA * 02110-1301 USA, or see the FSF site: http://www.fsf.org. */ package org.xnio.nio.test.racecondition; import org.jboss.byteman.rule.Rule; import org.jboss.byteman.rule.helper.Helper; /** * A helper with a isNull facility. * TODO remove this helper * * @author Flavia Rainone * */ public class NullHelper extends Helper { protected NullHelper(Rule rule) { super(rule); } public boolean isNull(Object object) { return object == null; } public String toString() { return "NullHelper"; } } xnio-3.3.2.Final/nio-impl/src/test/resources/000077500000000000000000000000001257016060700210345ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/test/resources/keystore.jks000066400000000000000000000025151257016060700234150ustar00rootroot00000000000000certificatekey0AD700 +*¹q*GR,;3ee2J/|0 ң\/7?)ӳZW/|, 9~ԩo笍4f/#NwV (-y3U0N|.S? <|sR YlŮ6d%&&~x[^RL}\,rYHMe&I#?%MkU'gB* ;joc 6O% 'hWg@YCsd11&Iۀ42ҦhA{ }oXGOY[V ( |{7,%!hpDpÑivlʞfF|(3ٳ,1P{l?nY*|pI9vd.H#=we\ɺ`HWSfl "G(333 d\!;yA>aE y`AͥĬUБc5w'cKES"u[.q7(1@ٲ;a~=ꍹ}J]U-іtW@ oU ԊS_x I )ePFr;o U߰">zI8eԜ ^2!fGyw`s$cҕG9\X.509C0?0M0  *H 0d1 0 UJB1 0 UFoo1 0 UFoo10U  jboss.org10U  jboss.org10UJane Doe0 110530141639Z 110606141639Z0d1 0 UJB1 0 UFoo1 0 UFoo10U  jboss.org10U  jboss.org10UJane Doe00  *H 0EͦRԋHT`Vh= ^@4>(+mz*H*bsc'G!'L:\󤅎[!Oz9`B: @(McI^])i0  *H XAAKhq[0SNz@6JjA*3sg'w%>۵P?vK:1aX',(jUhlօCK[t K %m%n #logger.org.xnio.listener.level=INFO logger.org.xnio.ssl.level=DEBUG xnio-3.3.2.Final/nio-impl/src/test/resources/org/000077500000000000000000000000001257016060700216235ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/test/resources/org/xnio/000077500000000000000000000000001257016060700226005ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/test/resources/org/xnio/nio/000077500000000000000000000000001257016060700233655ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/test/resources/org/xnio/nio/test/000077500000000000000000000000001257016060700243445ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/test/resources/org/xnio/nio/test/racecondition/000077500000000000000000000000001257016060700271655ustar00rootroot00000000000000SetConnFullDuringAwaitTestCase000066400000000000000000000045431257016060700350260ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/test/resources/org/xnio/nio/test/racecondition# # JBoss, Home of Professional Open Source. # Copyright 2012, Red Hat, Inc., and individual contributors # as indicated by the @author tags. See the copyright.txt file in the # distribution for a full listing of individual contributors. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; either version 2.1 of # the License, or (at your option) any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this software; if not, write to the Free # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA, or see the FSF site: http://www.fsf.org. # RULE awaitAcceptable checks CONN_FULL is not set CLASS org.xnio.nio.NioTcpServer METHOD awaitAcceptable AFTER INVOKE org.xnio.nio.SelectorUtils.await IF incrementCounter("run 'awaitAcceptable checks CONN_FULL' not set once") == 1 DO debug("AwaitWritable checked that connection is not full, waiting for CONN_FULL to be set before performing last check"), signalWake("CONN_FULL not set is verified", true), waitFor("CONN_FULL is set"), debug("Proceeding with the last check for CONN_FULL") ENDRULE RULE clear counters CLASS org.xnio.nio.test.racecondition.SetConnFullDuringAwaitTestCase METHOD afterTest AT ENTRY IF TRUE DO debug("Clearing counters"), deleteCounter("run 'awaitAcceptable checks CONN_FULL' not set once"), deleteCounter("wait for waiter on first accept only") ENDRULE RULE NioTcpServer sets CONN_FULL CLASS org.xnio.nio.NioTcpServer METHOD accept HELPER org.xnio.nio.test.racecondition.NullHelper AT EXIT IF isNull($!) DO debug("Connection limit is reached, waking awaitAcceptable"), signalWake("CONN_FULL is set", true), debug("Proceeding...") ENDRULE RULE NioTcpServer accept CLASS org.xnio.nio.NioTcpServer METHOD accept HELPER org.xnio.nio.test.racecondition.NullHelper AT ENTRY IF incrementCounter("wait for waiter on first accept only") == 1 DO debug("Holding first accept..."), waitFor("CONN_FULL not set is verified") ENDRULE UnsetConnFullDuringAwaitTestCase000066400000000000000000000057051257016060700353720ustar00rootroot00000000000000xnio-3.3.2.Final/nio-impl/src/test/resources/org/xnio/nio/test/racecondition# # JBoss, Home of Professional Open Source. # Copyright 2012, Red Hat, Inc., and individual contributors # as indicated by the @author tags. See the copyright.txt file in the # distribution for a full listing of individual contributors. # # This is free software; you can redistribute it and/or modify it # under the terms of the GNU Lesser General Public License as # published by the Free Software Foundation; either version 2.1 of # the License, or (at your option) any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this software; if not, write to the Free # Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA # 02110-1301 USA, or see the FSF site: http://www.fsf.org. # RULE awaitAcceptable checks CONN_FULL is set CLASS org.xnio.nio.NioTcpServer METHOD awaitAcceptable AFTER INVOKE allAreSet 1 IF incrementCounter("run 'awaitAcceptable checks CONN_FULL' once") == 1 DO debug("AwaitWritable checked that connection is full, wait until it is no longer full before proceeding"), signalWake("CONN_FULL is verified", true), waitFor("channel closed"), debug("Proceeding with double check on CONN_FULL at awaitAcceptable") ENDRULE RULE plainAwait test calls close only after previous rule is executed CLASS org.xnio.nio.test.racecondition.UnsetConnFullDuringAwaitTestCase METHOD plainAwait AT INVOKE org.xnio.channels.ConnectedStreamChannel.close IF incrementCounter("run 'test calls close' once") == 1 DO debug("waiting for awaiter to check CONN_FULL is set before closing channels"), waitFor("CONN_FULL is verified"), debug("proceeding with closing channels") ENDRULE RULE timeoutAwait test calls close only after previous rule is executed CLASS org.xnio.nio.test.racecondition.UnsetConnFullDuringAwaitTestCase METHOD timeoutAwait AT INVOKE org.xnio.channels.ConnectedStreamChannel.close IF incrementCounter("run 'test calls close' once") == 1 DO debug("waiting for awaiter to check CONN_FULL is set before closing channels"), waitFor("CONN_FULL is verified"), debug("proceeding with closing channels") ENDRULE RULE channelClosed unsets CONN_FULL CLASS org.xnio.nio.NioTcpServer METHOD channelClosed AT EXIT IF incrementCounter("run 'channelClosed unsets CONN_FULL' once") == 1 DO debug("Channel closed, resuming awaitAcceptable"), signalWake("channel closed", true), debug("awaitAcceptable resumed. Proceeding...") ENDRULE RULE clearCounters CLASS org.xnio.nio.test.racecondition.UnsetConnFullDuringAwaitTestCase METHOD afterTest IF TRUE DO deleteCounter("run 'awaitAcceptable checks CONN_FULL' once"), deleteCounter("run 'test calls close' once"), deleteCounter("run 'channelClosed unsets CONN_FULL' once") ENDRULE xnio-3.3.2.Final/pom.xml000066400000000000000000000124771257016060700150600ustar00rootroot00000000000000 4.0.0 org.jboss jboss-parent 14 org.jboss.xnio xnio-all pom XNIO Parent POM 3.3.2.Final The aggregator POM of the XNIO project api nio-impl 2.1.4.1 3.1.4.GA 1.2.0.Final 1.5.2.Final 1.0.Final 2.17 4.11 2.6.0 org.jboss.xnio xnio-api ${project.version} org.jboss.xnio xnio-nio ${project.version} org.jboss.xnio compat-tool ${project.version} org.jboss.logging jboss-logging ${version.org.jboss.logging.jboss-logging} org.jboss.logging jboss-logging-processor ${version.org.jboss.logging.jboss-logging-tools} provided org.jboss.logging jboss-logging-annotations ${version.org.jboss.logging.jboss-logging-tools} provided org.jmock jmock ${version.jmock} org.jmock jmock-junit4 ${version.jmock} org.jboss.logmanager jboss-logmanager ${version.org.jboss.logmanager.jboss-logmanager} junit junit ${version.junit} org.jboss.byteman byteman ${byteman-version} test org.jboss.byteman byteman-bmunit ${byteman-version} test testng org.testng org.jboss.byteman byteman-install ${byteman-version} test