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

org.jgroups.blocks.MessageDispatcher 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: 34.0.0.Final
Show newest version

package org.jgroups.blocks;

import org.jgroups.*;
import org.jgroups.logging.Log;
import org.jgroups.logging.LogFactory;
import org.jgroups.protocols.TP;
import org.jgroups.protocols.relay.SiteAddress;
import org.jgroups.stack.Protocol;
import org.jgroups.stack.StateTransferInfo;
import org.jgroups.util.*;

import java.io.*;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeoutException;
import java.util.stream.Stream;


/**
 * Provides synchronous and asynchronous message sending with request-response
 * correlation; i.e., matching responses with the original request.
 * It also offers push-style message reception (by internally using the PullPushAdapter).
 * 

* Channels are simple patterns to asynchronously send a receive messages. * However, a significant number of communication patterns in group communication * require synchronous communication. For example, a sender would like to send a * message to the group and wait for all responses. Or another application would * like to send a message to the group and wait only until the majority of the * receivers have sent a response, or until a timeout occurred. MessageDispatcher * offers a combination of the above pattern with other patterns. *

* Used on top of channel to implement group requests. Client's {@code handle()} * method is called when request is received. Is the equivalent of RpcProtocol on * the application instead of protocol level. * * @author Bela Ban */ public class MessageDispatcher implements RequestHandler, Closeable, ChannelListener { protected JChannel channel; protected RequestCorrelator corr; protected Receiver receiver; protected RequestHandler req_handler; protected boolean async_dispatching; /** When enabled, responses are handled by the common ForkJoinPool (https://issues.redhat.com/browse/JGRP-2644) */ protected boolean async_rsp_handling=!Util.virtualThreadsAvailable(); protected boolean wrap_exceptions; protected ProtocolAdapter prot_adapter; protected volatile Collection

members=new HashSet<>(); protected Address local_addr; protected final Log log=LogFactory.getLog(MessageDispatcher.class); @SuppressWarnings("rawtypes") protected static final RspList empty_rsplist; @SuppressWarnings("rawtypes") protected static final GroupRequest empty_group_request; static { empty_rsplist=new RspList<>(); empty_group_request=new GroupRequest<>(null, Collections.emptyList(), RequestOptions.SYNC()); empty_group_request.complete(empty_rsplist); } public MessageDispatcher() { } public MessageDispatcher(JChannel channel) { this.channel=channel; prot_adapter=new ProtocolAdapter(); if(channel != null) { channel.addChannelListener(this); local_addr=channel.getAddress(); installUpHandler(prot_adapter, true); } start(); } public MessageDispatcher(JChannel channel, RequestHandler req_handler) { this(channel); setRequestHandler(req_handler); } public JChannel getChannel() {return channel;} public RequestCorrelator getCorrelator() {return corr;} public RequestCorrelator correlator() {return corr;} public boolean getAsyncDispatching() {return async_dispatching;} public boolean asyncDispatching() {return async_dispatching;} public boolean asyncRspHandling() {return async_rsp_handling;} public MessageDispatcher asyncRspHandling(boolean f) {async_rsp_handling=f; if(corr != null) corr.asyncRspHandling(async_rsp_handling); return this;} public boolean getWrapExceptions() {return wrap_exceptions;} public boolean wrapExceptions() {return wrap_exceptions;} public UpHandler getProtocolAdapter() {return prot_adapter;} public UpHandler protocolAdapter() {return prot_adapter;} public RpcStats rpcStats() {return corr.rpc_stats;} public X setChannel(JChannel ch) { if(ch == null) return (X)this; this.channel=ch; if(ch != null) { local_addr=channel.getAddress(); ch.addChannelListener(this); } if(prot_adapter == null) prot_adapter=new ProtocolAdapter(); // Don't force installing the UpHandler so subclasses can use this method return installUpHandler(prot_adapter, false); } public X setCorrelator(RequestCorrelator c) {return correlator(c);} public X correlator(RequestCorrelator c) { if(c == null) return (X)this; stop(); this.corr=c; corr.asyncDispatching(this.async_dispatching).asyncRspHandling(async_rsp_handling) .wrapExceptions(this.wrap_exceptions); start(); return (X)this; } public X setReceiver(Receiver r) { this.receiver=r; return (X)this; } public X setRequestHandler(RequestHandler rh) { req_handler=rh; if(corr != null) corr.setRequestHandler(rh); return (X)this; } public X setAsynDispatching(boolean flag) {return asyncDispatching(flag);} public X asyncDispatching(boolean flag) { async_dispatching=flag; if(corr != null) corr.asyncDispatching(flag); return (X)this; } public X setWrapExceptions(boolean flag) {return wrapExceptions(flag);} public X wrapExceptions(boolean flag) { wrap_exceptions=flag; if(corr != null) corr.wrapExceptions(flag); return (X)this; } protected X setMembers(List
new_mbrs) { if(new_mbrs != null) members=new HashSet<>(new_mbrs); // volatile write - seen by a subsequent read return (X)this; } public X start() { if(corr == null) corr=createRequestCorrelator(prot_adapter, this, local_addr) .asyncDispatching(async_dispatching).asyncRspHandling(async_rsp_handling) .wrapExceptions(this.wrap_exceptions); corr.start(); if(channel != null) { List
tmp_mbrs=channel.getView() != null ? channel.getView().getMembers() : null; setMembers(tmp_mbrs); if(channel instanceof JChannel) { TP transport=channel.getProtocolStack().getTransport(); corr.registerProbeHandler(transport); } } return (X)this; } protected static RequestCorrelator createRequestCorrelator(Protocol transport, RequestHandler handler, Address local_addr) { return new RequestCorrelator(transport, handler, local_addr); } @Override public void close() throws IOException {stop();} public X stop() { if(corr != null) { corr.stop(); if(channel instanceof JChannel) { TP transport=channel.getProtocolStack().getTransport(); corr.unregisterProbeHandler(transport); } } return (X)this; } /** * Sets the given UpHandler as the UpHandler for the channel. If the relevant handler is already installed, * the {@code canReplace} controls whether this method replaces it (after logging a WARN) or simply * leaves {@code handler} uninstalled.

* Passing {@code false} as the {@code canReplace} value allows callers to use this method to install defaults * without concern about inadvertently overriding * * @param handler the UpHandler to install * @param canReplace {@code true} if an existing Channel upHandler can be replaced; {@code false} * if this method shouldn't install */ protected X installUpHandler(UpHandler handler, boolean canReplace) { UpHandler existing = channel.getUpHandler(); if (existing == null) channel.setUpHandler(handler); else if(canReplace) { log.warn("Channel already has an up handler installed (%s) but now it is being overridden", existing); channel.setUpHandler(handler); } return (X)this; } /** * Sends a message to all members and expects responses from members in dests (if non-null). * @param dests A list of group members from which to expect responses (if the call is blocking). * @param msg The message to be sent * @param opts A set of options that govern the call. See {@link org.jgroups.blocks.RequestOptions} for details * @return RspList A list of Rsp elements, or null if the RPC is asynchronous * @throws Exception If the request cannot be sent * @since 2.9 */ public RspList castMessage(final Collection

dests, Message msg, RequestOptions opts) throws Exception { GroupRequest req=cast(dests, msg, opts, true); return req != null? req.getNow(null) : null; } /** * Sends a message to all members and expects responses from members in dests (if non-null). * @param dests A list of group members from which to expect responses (if the call is blocking). * @param msg The message to be sent * @param opts A set of options that govern the call. See {@link org.jgroups.blocks.RequestOptions} for details * @return CompletableFuture A future from which the results (RspList) can be retrieved, or null if the request * was sent asynchronously * @throws Exception If the request cannot be sent */ public CompletableFuture> castMessageWithFuture(final Collection
dests, Message msg, RequestOptions opts) throws Exception { return cast(dests, msg, opts,false); } protected GroupRequest cast(final Collection
dests, Message msg, RequestOptions options, boolean block_for_results) throws Exception { if(options == null) { log.warn("request options were null, using default of sync"); options=RequestOptions.SYNC(); } List
real_dests; // we need to clone because we don't want to modify the original if(dests != null) real_dests=dests.stream().filter(dest -> dest instanceof SiteAddress || this.members.contains(dest)) .collect(ArrayList::new, (list,dest) -> {if(!list.contains(dest)) list.add(dest);}, (l,r) -> {}); else real_dests=new ArrayList<>(members); // Remove the local member from the target destination set if we should not deliver our own message JChannel tmp=channel; if((tmp != null && tmp.getDiscardOwnMessages()) || options.transientFlagSet(Message.TransientFlag.DONT_LOOPBACK)) { if(local_addr == null) local_addr=tmp != null? tmp.getAddress() : null; real_dests.remove(local_addr); } if(options.hasExclusionList()) Stream.of(options.exclusionList()).forEach(real_dests::remove); if(real_dests.isEmpty()) { log.trace("destination list is empty, won't send message"); return empty_group_request; } if(options.mode() == ResponseMode.GET_NONE) { corr.sendMulticastRequest(real_dests, msg, null, options); return null; } GroupRequest req=new GroupRequest<>(corr, real_dests, options); req.execute(msg, block_for_results); return req; } /** * Sends a unicast message and - depending on the options - returns a result * @param msg the payload to send * @param opts the options to be used * @return T the result. Null if the call is asynchronous (non-blocking) or if the response is null * @throws Exception If there was problem sending the request, processing it at the receiver, or processing * it at the sender. * @throws TimeoutException If the call didn't succeed within the timeout defined in options (if set) */ public T sendMessage(Message msg, RequestOptions opts) throws Exception { UnicastRequest req=_sendMessage(msg, opts); return req != null? req.execute(msg, true) : null; } /** * Sends a unicast message to the target defined by msg.getDest() and returns a future * @param msg the payload to send * @param opts the options * @return CompletableFuture A future from which the result can be fetched, or null if the call was asynchronous * @throws Exception If there was problem sending the request, processing it at the receiver, or processing * it at the sender. {@link java.util.concurrent.Future#get()} will throw this exception */ public CompletableFuture sendMessageWithFuture(Message msg, RequestOptions opts) throws Exception { UnicastRequest req=_sendMessage(msg, opts); if(req != null) req.execute(msg, false); return req; } /* ------------------------ RequestHandler Interface ---------------------- */ @Override public Object handle(Message msg) throws Exception { if(req_handler != null) return req_handler.handle(msg); return null; } @Override public void handle(Message request, Response response) throws Exception { if(req_handler != null) { if(async_dispatching) req_handler.handle(request, response); else { Object retval=req_handler.handle(request); if(response != null) response.send(retval, false); } return; } Object retval=handle(request); if(response != null) response.send(retval, false); } /* ------------------ End of RequestHandler Interface----------------- */ protected UnicastRequest _sendMessage(Message msg, RequestOptions opts) throws Exception { Address dest=msg.getDest(); if(dest == null) throw new IllegalArgumentException("message destination is null, cannot send message"); if(opts == null) { log.warn("request options were null, using default of sync"); opts=RequestOptions.SYNC(); } // invoke an async RPC directly and return null, without creating a UnicastRequest instance if(opts.mode() == ResponseMode.GET_NONE) { corr.sendUnicastRequest(msg, null, opts); return null; } return new UnicastRequest<>(corr, dest, opts); } protected Object handleUpEvent(Event evt) throws Exception { switch(evt.getType()) { case Event.GET_APPLSTATE: // reply with GET_APPLSTATE_OK byte[] tmp_state=null; if(receiver != null) { ByteArrayOutputStream output=new ByteArrayOutputStream(1024); if(getState(output)) tmp_state=output.toByteArray(); } return new StateTransferInfo(null, 0L, tmp_state); case Event.GET_STATE_OK: if(receiver != null) { StateTransferResult result=evt.getArg(); if(result.hasBuffer()) { ByteArrayInputStream input=new ByteArrayInputStream(result.getBuffer()); setState(input); } } break; case Event.STATE_TRANSFER_OUTPUTSTREAM: OutputStream os=evt.getArg(); getState(os); break; case Event.STATE_TRANSFER_INPUTSTREAM: InputStream is=evt.getArg(); setState(is); break; case Event.VIEW_CHANGE: View v=evt.getArg(); List
new_mbrs=v.getMembers(); setMembers(new_mbrs); if(receiver != null) receiver.viewAccepted(v); break; case Event.BLOCK: if(receiver != null) receiver.block(); break; case Event.UNBLOCK: if(receiver != null) receiver.unblock(); break; } return null; } protected boolean getState(OutputStream out) throws Exception { if(receiver == null || out == null) return false; try { receiver.getState(out); return true; } catch(UnsupportedOperationException un) { return false; } } protected boolean setState(InputStream in) throws Exception { if(receiver == null || in == null) return false; try { receiver.setState(in); return true; } catch(UnsupportedOperationException un) { return false; } } public void channelDisconnected(JChannel channel) { stop(); } public void channelClosed(JChannel channel) { stop(); } class ProtocolAdapter extends Protocol implements UpHandler { /* ------------------------- Protocol Interface --------------------------- */ @Override public String getName() { return "MessageDispatcher"; } public T setAddress(Address addr) { local_addr=addr; MessageDispatcher.this.local_addr=addr; if(corr != null) corr.setLocalAddress(addr); return (T)this; } public UpHandler setLocalAddress(Address a) { setAddress(a); return this; } /** * Called by channel (we registered before) when event is received. This is the UpHandler interface. */ @Override public Object up(Event evt) { if(corr != null && !corr.receive(evt)) { try { return handleUpEvent(evt); } catch(Throwable t) { throw new RuntimeException(t); } } return null; } public Object up(Message msg) { if(corr != null) corr.receiveMessage(msg); return null; } public void up(MessageBatch batch) { if(corr == null) return; corr.receiveMessageBatch(batch); } @Override public Object down(Event evt) { return channel != null? channel.down(evt) : null; } public Object down(Message msg) { if(channel != null) { if(!(channel.isConnected() || channel.isConnecting())) { // return null; throw new IllegalStateException("channel is not connected"); } return channel.down(msg); } return null; } /* ----------------------- End of Protocol Interface ------------------------ */ } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy