Package org.apache.synapse.transport.pipe

Source Code of org.apache.synapse.transport.pipe.PipeEndpointListener

/*
*  Licensed to the Apache Software Foundation (ASF) under one
*  or more contributor license agreements.  See the NOTICE file
*  distributed with this work for additional information
*  regarding copyright ownership.  The ASF licenses this file
*  to you under the Apache License, Version 2.0 (the
*  "License"); you may not use this file except in compliance
*  with the License.  You may obtain a copy of the License at
*
*   http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing,
*  software distributed under the License is distributed on an
*   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
*  KIND, either express or implied.  See the License for the
*  specific language governing permissions and limitations
*  under the License.
*/
package org.apache.synapse.transport.pipe;

import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.concurrent.CountDownLatch;

import org.apache.axis2.transport.base.datagram.DatagramDispatcherCallback;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

/**
* {@link Runnable} that reads messages from a given UNIX pipe.
* <p>
* The pipe will be opened in read/write mode. There are several reasons to
* do this:
* <ul>
*   <li>Opening a pipe in read only mode blocks until the other end of the pipe is opened for writing
*       (see <a href="http://linux.die.net/man/7/fifo"><tt>man 7 fifo</tt></a>). Since there is no
*       way to cleanly stop a thread blocking in the constructor of {@link FileInputStream} we open
*       the pipe in read/write mode to avoid blocking.</li>
*   <li>A pipe opened in read only mode will be closed when the other end is closed. By opening the pipe
*       in read/write mode we avoid this. If we unexpectedly receive an end-of-file, we shut down the
*       listener. This avoids unexpected behavior if the file system object is not a pipe (there is
*       no reliable way in Java to determine this).</li>
*   <li>Read operations on the pipe are blocking. By opening the pipe in read/write mode we have a
*       simple way to wake up the listener thread to shut it down cleanly. However, since read/write
*       operations on a file channel can't be invoked concurrently from different threads,
*       we need to create two separate channels from the same file descriptor.</li>
* </ul>
*/
public class PipeEndpointListener implements Runnable {
    private static final Log log = LogFactory.getLog(PipeEndpointListener.class);
   
    private final PipeEndpoint endpoint;
    private final DatagramDispatcherCallback callback;
    private final RandomAccessFile pipe;
    private final FileChannel readChannel;
    private final FileChannel writeChannel;
    private final Object guard = new Object();
    private boolean running;
    private final CountDownLatch done = new CountDownLatch(1);
   
    public PipeEndpointListener(PipeEndpoint endpoint, DatagramDispatcherCallback callback) throws IOException {
        this.endpoint = endpoint;
        this.callback = callback;
        pipe = new RandomAccessFile(endpoint.getPipe(), "rw");
        FileDescriptor fd = pipe.getFD();
        readChannel = new FileInputStream(fd).getChannel();
        writeChannel = new FileOutputStream(fd).getChannel();
        if (log.isDebugEnabled()) {
            log.debug("Pipe " + endpoint.getPipe().getAbsolutePath() + " opened");
        }
    }

    public void run() {
        running = true;
        ByteBuffer readBuffer = ByteBuffer.allocate(1024);
        try {
            while (true) {
                ProtocolDecoder decoder;
                decoder = endpoint.getProtocol().createProtocolDecoder();
                while (true) {
                    while (decoder.inputRequired()) {
                        int c;
                        try {
                            c = readChannel.read(readBuffer);
                        } catch (IOException ex) {
                            log.error("Error while reading from pipe " + endpoint.getPipe().getAbsolutePath() + "; shutting down listener", ex);
                            return;
                        }
                        if (c == -1) {
                            log.error("Pipe " + endpoint.getPipe().getAbsolutePath() + " was unexpectedly closed; shutting down listener");
                            return;
                        }
                        synchronized (guard) {
                            if (!running) {
                                return;
                            }
                        }
                        decoder.decode(readBuffer.array(), 0, readBuffer.position());
                        readBuffer.rewind();
                    }
                    byte[] message = decoder.getNext();
                    callback.receive(endpoint, message, message.length, null);
                }
            }
        }
        finally {
            try {
                pipe.close();
                if (log.isDebugEnabled()) {
                    log.debug("Pipe " + endpoint.getPipe().getAbsolutePath() + " closed");
                }
            } catch (IOException ex) {
                log.warn("Error while closing pipe " + endpoint.getPipe().getAbsolutePath(), ex);
            }
            done.countDown();
        }
    }

    public void stop() throws IOException {
        if (log.isDebugEnabled()) {
            log.debug("Stopping listener for pipe " + endpoint.getPipe().getAbsolutePath() + " ...");
        }
        synchronized (guard) {
            running = false;
            writeChannel.write(ByteBuffer.allocate(1));
        }
        try {
            done.await();
        } catch (InterruptedException ex) {
            Thread.currentThread().interrupt();
        }
        if (log.isDebugEnabled()) {
            log.debug("Listener for pipe " + endpoint.getPipe().getAbsolutePath() + " stopped");
        }
    }
}
TOP

Related Classes of org.apache.synapse.transport.pipe.PipeEndpointListener

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.