Package com.avaje.ebeaninternal.server.cluster.mcast

Source Code of com.avaje.ebeaninternal.server.cluster.mcast.McastListener

/**
* Copyright (C) 2009 Authors
*
* This file is part of Ebean.
*
* Ebean 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.
* Ebean 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 Ebean; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 
*/
package com.avaje.ebeaninternal.server.cluster.mcast;

import java.io.ByteArrayInputStream;
import java.io.DataInput;
import java.io.DataInputStream;
import java.io.IOException;
import java.net.DatagramPacket;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MulticastSocket;

import com.avaje.ebean.config.GlobalProperties;
import com.avaje.ebeaninternal.api.SpiEbeanServer;
import com.avaje.ebeaninternal.server.cluster.Packet;
import com.avaje.ebeaninternal.server.cluster.PacketTransactionEvent;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
* Listens for Incoming packets.
*
* @author rbygrave
*/
public class McastListener implements Runnable {

    private static final Logger logger = LoggerFactory.getLogger(McastListener.class);

    private final McastClusterManager owner;
   
    private final McastPacketControl packetControl;
   
    private final MulticastSocket sock;

    private final Thread listenerThread;

    private final String localSenderHostPort;

    private final InetAddress group;

    private final boolean debugIgnore;

    private DatagramPacket pack;

    private byte[] receiveBuffer;

    private volatile boolean shutdown;
    private volatile boolean shutdownComplete;
   
    private long totalPacketsReceived;
    private long totalBytesReceived;
    private long totalTxnEventsReceived;
   
    public McastListener(McastClusterManager owner, McastPacketControl packetControl, int port, String address,
            int bufferSize, int timeout, String localSenderHostPort,
            boolean disableLoopback, int ttl, InetAddress mcastBindAddress) {

        this.debugIgnore = GlobalProperties.getBoolean("ebean.debug.mcast.ignore", false);

        this.owner = owner;
        this.packetControl = packetControl;
        this.localSenderHostPort = localSenderHostPort;
        this.receiveBuffer = new byte[bufferSize];
        this.listenerThread = new Thread(this, "EbeanClusterMcastListener");

        String msg = "Cluster Multicast Listening address["+address+"] port["+port+"] disableLoopback["+disableLoopback+"]";
        if (ttl >= 0){
            msg +=" ttl["+ttl+"]";
        }
        if (mcastBindAddress != null){
            msg += " mcastBindAddress["+mcastBindAddress+"]";
        }
        logger.info(msg);

        try {
            this.group = InetAddress.getByName(address);
            this.sock = new MulticastSocket(port);
            this.sock.setSoTimeout(timeout);

            if (disableLoopback){
                sock.setLoopbackMode(disableLoopback);
            }
           
            if (mcastBindAddress != null) {
                // bind to a specific interface
                sock.setInterface(mcastBindAddress);
            }
           
            if (ttl >= 0) {
                sock.setTimeToLive(ttl);
            }
            sock.setReuseAddress(true);
            pack = new DatagramPacket(receiveBuffer, receiveBuffer.length);
            sock.joinGroup(group);
           
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void startListening() {
        this.listenerThread.setDaemon(true);
        this.listenerThread.start();
       
        logger.info("Cluster Multicast Listener up and joined Group");
    }

    /**
     * Shutdown this listener.
     */
    public void shutdown() {
       
        shutdown = true;
        synchronized (listenerThread) {
            try {
                // wait max 20 seconds
                listenerThread.wait(20000);               
            } catch (InterruptedException e) {
                logger.info("InterruptedException:"+e);
            }
        }
       
        if (!shutdownComplete){
            String msg = "WARNING: Shutdown of McastListener did not complete?";
            System.err.println(msg);
            logger.warn(msg);
        }
       
        try {
            sock.leaveGroup(group);
        } catch (IOException e) {
            // send to syserr in case logging already shutdown
            e.printStackTrace();
            String msg = "Error leaving Multicast group";
            logger.info(msg, e);
        }
        try {
            sock.close();
        } catch (Exception e) {
            // send to syserr in case logging already shutdown
            e.printStackTrace();
            String msg = "Error closing Multicast socket";
            logger.info(msg, e);
        }
    }
   
    public void run() {
        while (!shutdown) {
            try {
                pack.setLength(receiveBuffer.length);
                sock.receive(pack);

                InetSocketAddress senderAddr = (InetSocketAddress)pack.getSocketAddress();

                String senderHostPort = senderAddr.getAddress().getHostAddress()+":"+senderAddr.getPort();                   
               
                if (senderHostPort.equals(localSenderHostPort)){
                    if (debugIgnore || logger.isDebugEnabled()){
                        logger.info("Ignoring message as sent by localSender: "+localSenderHostPort);
                    }
                } else {
                                              
                    byte[] data = pack.getData();
                   
                   
                    ByteArrayInputStream bi = new ByteArrayInputStream(data);
                    DataInputStream dataInput = new DataInputStream(bi);
                   
                    ++totalPacketsReceived;
                    totalBytesReceived += pack.getLength();
                   
                    Packet header = Packet.readHeader(dataInput);
                   
                    long packetId = header.getPacketId();
                    boolean ackMsg = packetId == 0;
                   
                    boolean processThisPacket = ackMsg || packetControl.isProcessPacket(senderHostPort, header.getPacketId());
                   
                    if (!processThisPacket){
                        if (debugIgnore || logger.isDebugEnabled()){
                            logger.info("Already processed packet: "+header.getPacketId()+" type:"+header.getPacketType()+" len:"+data.length);
                        }
                    } else {
                        if (logger.isTraceEnabled()){
                            logger.info("Incoming packet:"+header.getPacketId()+" type:"+header.getPacketType()+" len:"+data.length);
                        }   
                        processPacket(senderHostPort, header, dataInput);                           
                    }
                }
               
            } catch (java.net.SocketTimeoutException e) {
                if (logger.isDebugEnabled()) {
                    logger.debug("timeout", e);
                }
                packetControl.onListenerTimeout();
               
            } catch (IOException e) {
                logger.info("error ?", e);
            }
        }
       
        shutdownComplete = true;
       
        synchronized (listenerThread) {
            listenerThread.notifyAll();
        }
    }

    protected void processPacket(String senderHostPort, Packet header, DataInput dataInput) {
        try {
            switch (header.getPacketType()) {
            case Packet.TYPE_MESSAGES:
                packetControl.processMessagesPacket(senderHostPort, header, dataInput,
                        totalPacketsReceived, totalBytesReceived, totalTxnEventsReceived);
                break;
               
            case Packet.TYPE_TRANSEVENT:
                ++totalTxnEventsReceived;
                processTransactionEventPacket(header, dataInput);
                break;
               
            default:
                String msg = "Unknown Packet type:" + header.getPacketType();
                logger.error(msg);
                break;
            }
        } catch (IOException e) {
            // need to ask to get this packet resent...
            String msg = "Error reading Packet " + header.getPacketId() + " type:" + header.getPacketType();
            logger.error(msg, e);
        }
    }
   
    private void processTransactionEventPacket(Packet header, DataInput dataInput) throws IOException {

        SpiEbeanServer server = owner.getEbeanServer(header.getServerName());

        PacketTransactionEvent tranEventPacket = PacketTransactionEvent.forRead(header, server);
        tranEventPacket.read(dataInput);

        server.remoteTransactionEvent(tranEventPacket.getEvent());
    }


}
TOP

Related Classes of com.avaje.ebeaninternal.server.cluster.mcast.McastListener

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.