Package com.salas.bb.utils.ipc

Source Code of com.salas.bb.utils.ipc.IPC$SocketListener

// BlogBridge -- RSS feed reader, manager, and web based service
// Copyright (C) 2002-2006 by R. Pito Salas
//
// This program is free software; you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free Software Foundation;
// either version 2 of the License, or (at your option) any later version.
//
// This program 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License along with this program;
// if not, write to the Free Software Foundation, Inc., 59 Temple Place,
// Suite 330, Boston, MA 02111-1307 USA
//
// Contact: R. Pito Salas
// mailto:pitosalas@users.sourceforge.net
// More information: about BlogBridge
// http://www.blogbridge.com
// http://sourceforge.net/projects/blogbridge
//
// $Id: IPC.java,v 1.6 2007/02/14 09:46:22 spyromus Exp $
//

package com.salas.bb.utils.ipc;

import EDU.oswego.cs.dl.util.concurrent.CopyOnWriteArrayList;

import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.ByteBuffer;
import java.util.logging.Logger;
import java.util.logging.Level;
import java.util.List;
import java.util.Iterator;
import java.net.URL;
import java.net.MalformedURLException;
import java.text.MessageFormat;

import com.salas.bb.utils.StringUtils;

/**
* File-based IPC implementation.
*/
public class IPC
{
    private final static Logger LOG = Logger.getLogger(IPC.class.getName());

    private final File socketFile;
    private final FileChannel socketChannel;
    private final List listeners;

    private SocketListener socketListener;

    /**
     * Creates IPC channel for a given socket file. All the data in the file
     * is removed.
     *
     * @param socketFile socket file.
     *
     * @throws java.io.IOException in case when it's not possible to create a file.
     */
    public IPC(File socketFile)
        throws IOException
    {
        if (socketFile == null) throw new IllegalArgumentException("Socket file should be specified.");

        this.socketFile = socketFile;
        this.listeners = new CopyOnWriteArrayList();

        configureSocketFile();

        socketChannel = new FileInputStream(socketFile).getChannel();

        configureSocketListener();
    }

    /**
     * Initializes socket file.
     *
     * @throws IOException if failed to create the socket file.
     */
    private void configureSocketFile()
        throws IOException
    {
        socketFile.delete();
        socketFile.createNewFile();
        socketFile.deleteOnExit();
    }

    /**
     * Creates socket listener thread.
     */
    private void configureSocketListener()
    {
        socketListener = new SocketListener();
        socketListener.start();
    }

    /**
     * Closes active socket channel which lets the listener thread terminate.
     */
    public void close()
    {
        try
        {
            if (socketChannel != null && socketChannel.isOpen())
            {
                socketChannel.close();
                socketListener = null;
            }
        } catch (IOException e)
        {
            LOG.log(Level.WARNING, "Failed to close socket channel.", e);
        }
    }

    /**
     * Sends command using the given socket file.
     *
     * @param socketFile socket file.
     * @param cmd        command.
     * @param args       command arguments.
     *
     * @return <code>TRUE</code> if sent.
     */
    public static boolean sendCommand(File socketFile, String cmd, String[] args)
    {
        boolean sent = false;

        if (socketFile.exists() && !StringUtils.isEmpty(cmd) && args != null)
        {
            String command = cmd + " " + StringUtils.join(args, " ") + "\n";
            try
            {
                RandomAccessFile raf = new RandomAccessFile(socketFile, "rws");
                raf.seek(raf.length());
                raf.getChannel().write(ByteBuffer.wrap(command.getBytes()));
                raf.close();

                sent = true;
            } catch (IOException e)
            {
                LOG.log(Level.WARNING, "Failed to send IPC command.", e);
            }
        }

        return sent;
    }

    /**
     * Adds a listener to the list.
     *
     * @param l listener.
     */
    public void addListener(IIPCListener l)
    {
        if (!listeners.contains(l)) listeners.add(l);
    }

    /**
     * Removes a listener from the list.
     *
     * @param l listener.
     */
    public void removeListener(IIPCListener l)
    {
        listeners.remove(l);
    }

    /**
     * Fires subscribe to URL event.
     *
     * @param url URL.
     */
    public void fireSubscribe(URL url)
    {
        Iterator it = listeners.iterator();
        while (it.hasNext())
        {
            IIPCListener l = (IIPCListener)it.next();
            try
            {
                l.subscribe(url);
            } catch (Throwable e)
            {
                LOG.log(Level.SEVERE, "Unhandled exception", e);
            }
        }
    }

    /**
     * Invoked when new command string arrives.
     *
     * @param cmd command.
     */
    private void onCommand(String cmd)
    {
        // Collapse multi-spaces
        cmd = cmd.replaceAll("\\s+", " ").trim();

        // Break the command into pieces
        String[] chunks = cmd.split(" ");

        if (chunks.length > 0)
        {
            String op = chunks[0];

            if ("subscribe".equalsIgnoreCase(op))
            {
                if (chunks.length == 2)
                {
                    String arg = chunks[1];
                   
                    URL url = argToURL(arg);
                    if (url != null)
                    {
                        fireSubscribe(url);
                    } else
                    {
                        LOG.warning("Invalid URL '" + arg + "' for 'subscribe' command");
                    }
                } else
                {
                    LOG.warning(MessageFormat.format(
                        "Invalid number of arguments for ''subscribe'': {0} expected 1",
                        new Object[] { new Integer(chunks.length - 1) }));
                }
            }
        }
    }

    /**
     * Converts command-line argument into the URL if it's some valid URL or the path
     * to a file.
     *
     * @param arg argument.
     *
     * @return URL.
     */
    public static URL argToURL(String arg)
    {
        URL url = null;

        if (!StringUtils.isEmpty(arg))
        {
            arg = arg.trim();
            try
            {
                if (arg.matches("^(file|https?):.*"))
                {
                    url = new URL(arg);
                } else
                {
                    File f = new File(arg);
                    if (f.exists() && f.isFile()) url = f.toURI().toURL();
                }
            } catch (MalformedURLException e)
            {
                url = null;
            }
        }

        return url;
    }

    /**
     * Listener of socket commands.
     */
    private class SocketListener extends Thread
    {
        /** Time in ms to sleep between socket channel checks. */
        private static final int SLEEP_TIME = 1000;
        /** The size of a buffer for commands. */
        private static final int BUFFER_SIZE = 2048;

        /**
         * Initializes socket listener thread.
         */
        public SocketListener()
        {
            super("IPC Socket Listener");
            setDaemon(true);
        }

        public void run()
        {
            ByteBuffer buffer = ByteBuffer.allocate(BUFFER_SIZE);
            buffer.clear();
            int bytes;

            while (socketChannel != null && socketChannel.isOpen())
            {
                try
                {
                    bytes = socketChannel.read(buffer);
//                    socketChannel.truncate(0);

                    if (bytes != -1)
                    {
                        byte[] strb = new byte[bytes];
                        buffer.position(0);
                        buffer.get(strb, 0, bytes);
                        String str = new String(strb);
                        String[] cmds = str.split("\\n");

                        for (int i = 0; i < cmds.length; i++)
                        {
                            onCommand(cmds[i]);
                        }

                        buffer.clear();
                    } else Thread.sleep(SLEEP_TIME);

                } catch (IOException e)
                {
                    LOG.log(Level.SEVERE, "Failed to work with socket file.", e);
                } catch (InterruptedException e)
                {
                    LOG.warning("Interruption.");
                }
            }
        }
    }
}
TOP

Related Classes of com.salas.bb.utils.ipc.IPC$SocketListener

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.