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

org.jgroups.protocols.FORK 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: 33.0.2.Final
Show newest version
package org.jgroups.protocols;

import org.jgroups.Event;
import org.jgroups.Header;
import org.jgroups.Message;
import org.jgroups.annotations.*;
import org.jgroups.conf.ClassConfigurator;
import org.jgroups.conf.ConfiguratorFactory;
import org.jgroups.conf.ProtocolConfiguration;
import org.jgroups.fork.ForkConfig;
import org.jgroups.fork.ForkProtocol;
import org.jgroups.fork.ForkProtocolStack;
import org.jgroups.fork.UnknownForkHandler;
import org.jgroups.stack.Configurator;
import org.jgroups.stack.Protocol;
import org.jgroups.stack.ProtocolStack;
import org.jgroups.util.Bits;
import org.jgroups.util.MessageBatch;
import org.jgroups.util.Util;
import org.w3c.dom.Node;

import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessControlException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

/**
 * The FORK protocol; multiplexes messages to different forks in a stack (https://issues.jboss.org/browse/JGRP-1613).
 * See doc/design/FORK.txt for details
 * @author Bela Ban
 * @since  3.4
 */
@XmlInclude(schema="fork-stacks.xsd",type=XmlInclude.Type.IMPORT,namespace="fork",alias="fork")
@XmlElement(name="fork-stacks",type="fork:ForkStacksType")
@MBean(description="Implementation of FORK protocol")
public class FORK extends Protocol {
    public static short ID=ClassConfigurator.getProtocolId(FORK.class);

    @Property(description="Points to an XML file defining the fork-stacks, which will be created at initialization. " +
      "Ignored if null")
    protected String config;

    private UnknownForkHandler unknownForkHandler = new UnknownForkHandler() {
        @Override
        public Object handleUnknownForkStack(Message message, String forkStackId) {
            log.warn("fork-stack for id=%s not found; discarding message", forkStackId);
            return null;
        }

        @Override
        public Object handleUnknownForkChannel(Message message, String forkChannelId) {
            log.warn("fork-channel for id=%s not found; discarding message", forkChannelId);
            return null;
        }
    };

    // mappings between fork-stack-ids and fork-stacks (bottom-most protocol)
    protected final ConcurrentMap fork_stacks=new ConcurrentHashMap<>();

    public void setUnknownForkHandler(UnknownForkHandler unknownForkHandler) {
        this.unknownForkHandler = unknownForkHandler;
    }

    public UnknownForkHandler getUnknownForkHandler() {
        return this.unknownForkHandler;
    }

    public Protocol get(String fork_stack_id)                        {return fork_stacks.get(fork_stack_id);}
    public Protocol putIfAbsent(String fork_stack_id, Protocol prot) {return fork_stacks.put(fork_stack_id, prot);}
    public void     remove(String fork_stack_id)                     {fork_stacks.remove(fork_stack_id);}

    @ManagedAttribute(description="Number of fork-stacks")
    public int getForkStacks() {return fork_stacks.size();}

    public static ForkProtocolStack getForkStack(Protocol prot) {
        while(prot != null && !(prot instanceof ForkProtocolStack))
            prot=prot.getUpProtocol();
        return prot instanceof ForkProtocolStack? (ForkProtocolStack)prot : null;
    }

    public void init() throws Exception {
        super.init();
        if(config != null)
            createForkStacks(config);
    }

    public Object up(Event evt) {
        switch(evt.getType()) {
            case Event.MSG:
                Message msg=(Message)evt.getArg();
                ForkHeader hdr=(ForkHeader)msg.getHeader(id);
                if(hdr == null)
                    break;
                if(hdr.fork_stack_id == null)
                    throw new IllegalArgumentException("header has a null fork_stack_id");
                Protocol bottom_prot=get(hdr.fork_stack_id);
                return bottom_prot != null? bottom_prot.up(evt) : this.unknownForkHandler.handleUnknownForkStack(msg, hdr.fork_stack_id);

            case Event.VIEW_CHANGE:
                for(Protocol bottom: fork_stacks.values())
                    bottom.up(evt);
                break;
        }
        return up_prot.up(evt);
    }

    public void up(MessageBatch batch) {
        // Sort fork messages by fork-stack-id
        Map> map=new HashMap<>();
        for(Message msg: batch) {
            ForkHeader hdr=(ForkHeader)msg.getHeader(id);
            if(hdr != null) {
                batch.remove(msg);
                List list=map.get(hdr.fork_stack_id);
                if(list == null) {
                    list=new ArrayList<>();
                    map.put(hdr.fork_stack_id, list);
                }
                list.add(msg);
            }
        }

        // Now pass fork messages up, batched by fork-stack-id
        for(Map.Entry> entry: map.entrySet()) {
            String fork_stack_id=entry.getKey();
            List list=entry.getValue();
            Protocol bottom_prot=get(fork_stack_id);
            if(bottom_prot == null)
                continue;
            MessageBatch mb=new MessageBatch(batch.dest(), batch.sender(), batch.clusterName(), batch.multicast(), list);
            try {
                bottom_prot.up(mb);
            }
            catch(Throwable t) {
                log.error("failed passing up batch", t);
            }
        }

        if(!batch.isEmpty())
            up_prot.up(batch);
    }


    protected void createForkStacks(String config) throws Exception {
        InputStream in=getForkStream(config);
        if(in == null)
            throw new FileNotFoundException("fork stacks config " + config + " not found");
        Map> protocols=ForkConfig.parse(in);
        createForkStacks(protocols);
    }

    protected void createForkStacks(Map> protocols) throws Exception {
        for(Map.Entry> entry: protocols.entrySet()) {
            String fork_stack_id=entry.getKey();
            if(get(fork_stack_id) != null)
                continue;

            List prots=createProtocols(null,entry.getValue());
            createForkStack(fork_stack_id, prots, false);
        }
    }

    public void parse(Node node) throws Exception {
        Map> protocols=ForkConfig.parse(node);
        createForkStacks(protocols);
    }

    /**
     * Returns the fork stack for fork_stack_id (if exitstent), or creates a new fork-stack from protocols and adds it
     * into the hashmap of fork-stack (key is fork_stack_id).
     * Method init() will be called on each protocol, from bottom to top.
     * @param fork_stack_id The key under which the new fork-stack should be added to the fork-stacks hashmap
     * @param protocols A list of protocols from bottom to top to be inserted. They will be sandwiched
     *                  between ForkProtocolStack (top) and ForkProtocol (bottom). The list can be empty (or null) in
     *                  which case we won't create any protocols, but still have a separate fork-stack inserted.
     * @param initialize If false, the ref count 'inits' will not get incremented and init() won't be called. This is
     *                   needed when creating a fork stack from an XML config inside of the FORK protocol. The protocols
     *                   in the fork stack will only get initialized on the first ForkChannel creation
     * @return The new {@link ForkProtocolStack}, or the existing stack (if present)
     */
    public synchronized ProtocolStack createForkStack(String fork_stack_id, List protocols, boolean initialize) throws Exception {
        Protocol bottom;
        if((bottom=get(fork_stack_id)) != null) {
            ForkProtocolStack retval=getForkStack(bottom);
            return initialize? retval.incrInits() : retval;
        }

        List prots=new ArrayList<>();
        prots.add(bottom=new ForkProtocol(fork_stack_id).setDownProtocol(this)); // add a ForkProtocol as bottom protocol
        if(protocols != null)
            prots.addAll(protocols);

        ForkProtocolStack fork_stack=(ForkProtocolStack)new ForkProtocolStack(getUnknownForkHandler(), prots, fork_stack_id).setChannel(this.stack.getChannel());
        fork_stack.init();
        if(initialize)
            fork_stack.incrInits();
        fork_stacks.put(fork_stack_id, bottom);
        return fork_stack;
    }



    /** Creates a fork-stack from the configuration, initializes all protocols (setting values),
     * sets the protocol stack as top protocol, connects the protocols and calls init() on them. Returns
     * the protocols in a list, from bottom to top */
    protected static List createProtocols(ProtocolStack stack, List protocol_configs) throws Exception {
        return Configurator.createProtocols(protocol_configs,stack);
    }

    public static InputStream getForkStream(String config) throws IOException {
        InputStream configStream = null;

        try {
            configStream=new FileInputStream(config);
        }
        catch(FileNotFoundException | AccessControlException fnfe) { // catching ACE fixes http://jira.jboss.com/jira/browse/JGRP-94
        }

        // Check to see if the properties string is a URL.
        if(configStream == null) {
            try {
                configStream=new URL(config).openStream();
            }
            catch (MalformedURLException mre) {
            }
        }

        // Check to see if the properties string is the name of a resource, e.g. udp.xml.
        if(configStream == null)
            configStream=Util.getResourceAsStream(config, ConfiguratorFactory.class);
        return configStream;
    }


    public static class ForkHeader extends Header {
        protected String fork_stack_id, fork_channel_id;

        public ForkHeader() {
        }

        public ForkHeader(String fork_stack_id, String fork_channel_id) {
            this.fork_stack_id=fork_stack_id;
            this.fork_channel_id=fork_channel_id;
        }

        public String getForkStackId() {
            return fork_stack_id;
        }

        public void setForkStackId(String fork_stack_id) {
            this.fork_stack_id=fork_stack_id;
        }

        public String getForkChannelId() {
            return fork_channel_id;
        }

        public void setForkChannelId(String fork_channel_id) {
            this.fork_channel_id=fork_channel_id;
        }

        public int size() {return Util.size(fork_stack_id) + Util.size(fork_channel_id);}

        public void writeTo(DataOutput out) throws Exception {
            Bits.writeString(fork_stack_id,out);
            Bits.writeString(fork_channel_id,out);
        }

        public void readFrom(DataInput in) throws Exception {
            fork_stack_id=Bits.readString(in);
            fork_channel_id=Bits.readString(in);
        }

        public String toString() {return fork_stack_id + ":" + fork_channel_id;}
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy