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 Jakarta Enterprise Beans and Jakarta Messaging, including all dependencies. It is intended for use by those not using maven, maven users should just import the Jakarta Enterprise Beans and Jakarta Messaging 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: 35.0.0.Beta1
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);}

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

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

    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, boolean replace_existing) 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, replace_existing);
    }

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

            ProtocolStack  fork_prot_stack=new ForkProtocolStack(this.unknownForkHandler);
            List prots=createProtocols(fork_prot_stack,entry.getValue());
            createForkStack(fork_stack_id, fork_prot_stack, replace_existing, prots);
        }
    }

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

    /**
     * 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 stack The protocol stack under which to create the protocols
     * @param replace_existing If true, and existing fork-stack is simply replaced (de-initializing it first).
     *                         Otherwise, if the stack already exists, the new fork-stack will not be created.
     * @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.
     * @return The bottom-most protocol of the new stack, or the existing stack (if present)
     */
    public Protocol createForkStack(String fork_stack_id, final ProtocolStack stack, boolean replace_existing,
                                    List protocols) throws Exception {
        Protocol bottom;
        if((bottom=get(fork_stack_id)) != null && !replace_existing) {
            log.warn("fork-stack %s is already present, won't replace it", fork_stack_id);
            return bottom;
        }

        Protocol current=stack;                          // top
        if(protocols != null && !protocols.isEmpty()) {
            for(int i=protocols.size()-1; i >= 0; i--) {
                Protocol prot=protocols.get(i);
                current.setDownProtocol(prot);
                prot.setUpProtocol(current);
                current=prot;
            }
        }

        bottom=new ForkProtocol(fork_stack_id); // bottom
        current.setDownProtocol(bottom);
        bottom.setUpProtocol(current);
        bottom.setDownProtocol(this);
        stack.topProtocol(stack.getDownProtocol()).bottomProtocol(bottom);
        fork_stacks.put(fork_stack_id, bottom);

        // call init() on the created protocols, from bottom to top
        //current=bottom;
        while(current != null && !(current instanceof ProtocolStack)) {
            current.init();
            current=current.getUpProtocol();
        }
        return bottom;
    }



    /** 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 fnfe) {
        }
        catch(AccessControlException access_ex) { // 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 - 2025 Weber Informatics LLC | Privacy Policy