All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.xnio.conduits.Conduits Maven / Gradle / Ivy

Go to download

This artifact provides a single jar that contains all classes required to use remote EJB and JMS, including all dependencies. It is intended for use by those not using maven, maven users should just import the EJB and JMS BOM's instead (shaded JAR's cause lots of problems with maven, as it is very easy to inadvertently end up with different versions on classes on the class path).

There is a newer version: 34.0.0.Final
Show newest version
/*
 * 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); } } }); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy