Play 2.4-Java - Actor Message Protocol best practice - java

I was reading documentation on Akka actors implementation in Playframework,
https://www.playframework.com/documentation/2.4.x/JavaAkka
One of the paragraphs talk about message class best practice as following:
"Another best practice shown here is that the messages that HelloActor sends and receives are defined as static inner classes of another class calledHelloActorProtocol:"
Can some one please elaborate and explain this best practice and what are the benefits of this pattern? Why message should be defined as static nested class of other class?
Thank you in advance!

I believe the main idea behind this is to isolate the scope of messages sent to a specific actor. Having typed protocols helps cut down on sending an unexpected Protocol (or message) to the actor. Keeping them in one class is a nice way to capture all the actions related to that specific domain, like EmployeeProtocol helps enforce EmployeeActor to receive expected messages. However, you still have the responsibility to send them correctly:
Here is our controller call to the EmployeeActor using the protocol:
public class EmployeeController extends Controller {
return Promise.wrap(ask(employeeActorRef,
new GetCurrentEmployees(), 5000))
.map(response -> ok((JsonNode)response));
}
}
EmployeeActor processes its messages based on the received protocol:
public class EmployeeActor extends UntypedActor {
#Override
public void onReceive(Object message) throws Exception {
if (message instanceof GetCurrentEmployees) {
//do things related to this task
} else if (message instanceof CreateNewEmployee) {
//do things related to this task
} else if (message instanceof RemoveEmployee) {
//do things related to this task
}
}
}
Here protocols are defined for actions on the employee and can hold typed fields so we know what to expect. The fact that we use static final fields in the protocol will enforce immutability of the messages:
public class EmployeeProtocol {
public static class GetCurrentEmployees {}
public static class CreateNewEmployee {
private final String name;
public CreateNewEmployee(String name) {
this.name = name;
}
//getter
}
public static class RemoveEmployee {
public final String uuidToRemove;
public RemoveEmployee(String uuidToRemove) {
this.uuidToRemove = uuidToRemove;
}
//getter
}
}
Akka-Typed is being developed in akka scala which can be used to send messages of only a specific type so that if you attempt to send an incorrect message type the compiler will complain. Akka-typed - http://doc.akka.io/docs/akka/snapshot/scala/typed.html#typed-scala
Maybe they wanted us to use this best practice because we'll be able to make it type safe in the future... There was also mention of this coming to java here in this podcast: https://www.typesafe.com/resources/video/akka-2-4-plus-new-commercial-features-in-typesafe-reactive-platform

Related

When many Akka Actors send messages to one actor, how to cleanly handle inheritance of inner Command classes

In akka-typed, the convention is to create Behavior classes with static inner classes that represent the messages that they receive. Heres a simple example
public class HTTPCaller extends AbstractBehavior<HTTPCaller.MakeRequest> {
public interface Command {}
// this is the message the HTTPCaller receives
public static final class MakeRequest implements Command {
public final String query;
public final ActorRef<Response> replyTo;
public MakeRequest(String query, ActorRef<Response> replyTo) {
this.query = query;
this.replyTo = replyTo;
}
}
// this is the response message
public static final class Response implement Command {
public final String result;
public Response(String result) {
this.result = result;
}
}
public static Behavior<Command> create() {
return Behaviors.setup(HTTPCaller::new);
}
private HTTPCaller(ActorContext<Command> context) {
super(context);
}
#Override
public Receive<Command> createReceive() {
return newReceiveBuilder()
.onMessage(MakeRequest.class, this::onMakeRequest).build();
}
private Behavior<MakeRequest> onMakeRequest(MakeRequest message) {
String result = // make HTTP request here using message.query
message.replyTo.tell(new Response(result));
return Behaviors.same();
}
}
Let's say that 20 other actors send MakeRequest messages to the single HTTPCaller actor. Now, each of these other actors have inner classes that implement their own Command. Since MakeRequest is being used by all 20 classes it must be a subtype of all 20 of those actors' Command inner interface.
This is not ideal. I'm wondering what the Akka way of getting around this is.
There's no requirement that a message (e.g. a command) which an actor sends (except for messages to itself...) have to conform to that actor's incoming message type. The commands sent to the HTTPCaller actor only have to (and in this case only do) extend HTTPCaller.Command.
So imagine that we have something like
public class SomeOtherActor extends AbstractBehavior<SomeOtherActor.Command> {
public interface Command;
// yada yada yada
ActorRef<HTTPCaller.Command> httpCallerActor = ...
httpCallerActor.tell(new HTTPCaller.MakeRequest("someQuery", getContext().getSystem().ignoreRef());
}
In general, when defining messages which are sent in reply, those are not going to extend the message type of the sending actor. In HTTPCaller, for instance, Response probably shouldn't implements Command: it can be a standalone class (alternatively, if it is something that might be received by the HTTPCaller actor, it should be handled in the receive builder).
My code above does bring up one question: if Response is to be received by SomeOtherActor, how can it extend SomeOtherActor.Command?
The solution there is message adaptation: a function to convert a Response to a SomeOtherActorCommand. For example
// in SomeOtherActor
// the simplest possible adaptation:
public static final class ResponseFromHTTPCaller implements Command {
public final String result;
public ResponseFromHTTPCaller(HTTPCaller.Response response) {
result = response.result;
}
// at some point before telling the httpCallerActor...
// apologies if the Java lambda syntax is messed up...
ActorRef<HTTPCaller.Response> httpCallerResponseRef =
getContext().messageAdapter(
HTTPCaller.Response.class,
(response) -> { new ResponseFromHTTPCaller(response) }
);
httpCallerActor.tell(new HTTPCaller.MakeRequest("someQuery", httpCallerResponseRef);
There is also the ask pattern, which is more useful for one-shot interactions between actors where there's a timeout.

Is there a design pattern that supports injections of several abstract class implementations and conditionally uses one of the injected beans

I am on a project using Java and Spring Boot that processes several different message types from the same queue. Each message gets processed conditionally based on the message type, using an implementation of MessageProcessingService abstract class for each message type.
As of now, we have 5 different message types coming into the same consumer. We are using the same queue because we leverage group policies in JMS, and each message type has the same business key as the group policy.
So what we end up with is that every time a requirement requires receiving a new message type, we add a new implementation of a MessageProcessingService and another dependency to the consumer object. I want to find a better strategy to selectively choose the message processing
Here is an example similar to what we are doing. I do not guarantee the syntax is compilable or syntactically perfect, just demonstrating the problem. Notice all the messages resolve around a person
Consumer:
#Component
public class PersonMessageConsumer {
private MessageProcessingService<HeightUpdate> heightUpdateMessageProcessingService;
private MessageProcessingService<WeightUpdate> weightUpdateMessageProcessingService;
private MessageProcessingService<NameUpdate> nameUpdateMessageProcessingService;
private MessageProcessingService<ShowSizeUpdate> shoeSizeUpdateMessageProcessingService;
public PersonMessageConsumer(
MessageProcessingService<HeightUpdate> heightUpdateMessageProcessingService,
MessageProcessingService<WeightUpdate> weightUpdateMessageProcessingService,
MessageProcessingService<NameUpdate> nameUpdateMessageProcessingService,
MessageProcessingService<ShowSizeUpdate> shoeSizeUpdateMessageProcessingService) {
this.heightUpdateMessageProcessingService = heightUpdateMessageProcessingService;
this.weightUpdateMessageProcessingService = weightUpdateMessageProcessingService;
this.nameUpdateMessageProcessingService = nameUpdateMessageProcessingService;
this.shoeSizeUpdateMessageProcessingService = shoeSizeUpdateMessageProcessingService;
}
#JmsListener(destination = "${queueName}")
public void receiveMessage(TextMessage message) {
String messageType = message.getHeader("MessageType");
switch (messageType) {
case "HeightUpdate":
heightUpdateMessageProcessingService.processMessage(message.getText());
return;
case "WeightUpdate":
weightUpdateMessageProcessingServivce.processMessage(message.getText());
return;
// And other message types
default:
throw new UnknownMessageTypeException(messageType);
}
}
Message POJO example
public class HeightUpdate implements PersonMessage {
#Getter
#Setter
private int height;
}
PersonMessage interface
public interface PersonMessage {
int getPersonId();
}
MessageProcessingService
public abstract class MessageProcessingService<T extends PersonMessage> {
public void processMessage(String messageText) {
//Common message processing, we do some more involved work here but just as a simple example
T message = new ObjectMapper.readValue(messageText, getClassType());
Person person = personRepository.load(message.getPersonId());
Person originalPerson = person.deepCopy();
processMessageLogic(person, message);
if (originalPerson.isDifferentFrom(person)) {
personRespository.update(person);
}
}
protected abstract void processMessageLogic(Person person, T message);
protected abstract Class getClassType();
}
Abstract class implementation example
#Service("heightUpdateMessageProcessingService")
public class HeightUpdateMessageProcessingService extends MessageProcessingService<HeightUpdate> {
#Override
protected void processMessageLogic(Person person, HeightUpdate update) {
person.setHeight(update.getHeight());
}
#Override
protected Class getMessageType() {
return HeightUpdate.getClass();
}
}
So my question is whether or not there is a better design pattern or way of coding this in java and spring that is a little easier to clean and maintain and keeps SOLID principles in mind
Add an abstract method in the MessageProcessingService to return the messageType that each concrete implementation can handle.
Rather than wiring each individual service into PersonMessageConsumer, wire in a List<MessageProcessingService> so that you get all of them at once.
Transform that List into a Map<String, MessageProcessingService>, using the messageType as the key.
Replace the switch statement by looking up the appropriate service in the Map and then invoking its processMessage method.
In the future you can add new instances of MessageProcessingService without having to edit PersonMessageConsumer because Spring will automatically add those new instances to the List<MessageProcessingService> that you wire in.

"if" statement vs OO Design

I have enum say ErrorCodes that
public enum ErrorCodes {
INVALID_LOGIN(100),
INVALID_PASSWORD(101),
SESSION_EXPIRED(102) ...;
private int errorCode;
private ErrorCodes(int error){
this.errorCode = error;
} //setter and getter and other codes
}
now I check my exception error codes with this error codes. I don't want to write if this do this, if this do this. How I can solve this problem (writing 10+ if blocks)
Is there any design patter to that situation ?
Thanks
Either you do it with a if-statement or a switch, or you just implement the logic in question into the ErrorCode somehow.
In an OO fashion it all depends on how you want the application or system react to the error code. Lets say you just want it to output somekind of dialog:
public doSomethingWithError() {
ErrorCodes e = getError();
// the source of error, or originator, returns the enum
switch(e) {
case ErrorCodes.INVALID_LOGIN:
prompt('Invalid Login');
case ErrorCodes.INVALID_PASSWORD:
prompt('Invalid password');
// and so on
}
}
We could instead create an ErrorHandler class that does this instead:
// We'll implement this using OO instead
public doSomethingWithError() {
ErrorHandler e = getError();
// the originator now returns an ErrorHandler object instead
e.handleMessage();
}
// We will need the following abstract class:
public abstract class ErrorHandler {
// Lets say we have a prompter class that prompts the message
private Prompter prompter = new Prompter();
public final void handleMessage() {
String message = this.getMessage();
prompter.prompt(message);
}
// This needs to be implemented in subclasses because
// handleMessage() method is using it.
public abstract String getMessage();
}
// And you'll have the following implementations, e.g.
// for invalid logins:
public final class InvalidLoginHandler() {
public final String getMessage() {
return "Invalid login";
}
}
// E.g. for invalid password:
public final class InvalidPasswordHandler() {
public final String getMessage() {
return "Invalid password";
}
}
The former solution is easy to implement, but becomes difficult to maintain as the code grows larger. The latter solution is more complex, (aka. Template Method pattern following the Open-Closed Principle) but enables you to add more methods into the ErrorHandler when you need it (such as restoring resources or whatever). You can also implement this with the Strategy pattern.
You won't get away completely with the conditional statements, but in the latter the conditional is pushed to the part of the code where the error is originated. That way you won't have double maintenance on conditional statements both at the originator and the error handling code.
EDIT:
See this answer by Michael Borgwardt and this answer by oksayt for how to implement methods on Java Enums if you want to do that instead.
Java enums are very powerful and allow per-instance method implementations:
public enum ErrorCode {
INVALID_LOGIN {
public void handleError() {
// do something
}
},
INVALID_PASSWORD {
public void handleError() {
// do something else
}
},
SESSION_EXPIRED {
public void handleError() {
// do something else again
}
};
public abstract void handleError();
}
Then you can simply call errorCode.handleError();. However, it is questionable whether an ErrorCode enum is really the right place for that logic.
As pointed out by Spoike, using polymorphism to pick the right error handling method is an option. This approach basically defers the 10+ if blocks to the JVM's virtual method lookup, by defining a class hierarchy.
But before going for a full-blown class hierarchy, also consider using enum methods. This option works well if what you plan to do in each case is fairly similar.
For example, if you want to return a different error message for each ErrorCode, you can simply do this:
// Note singular name for enum
public enum ErrorCode {
INVALID_LOGIN(100, "Your login is invalid"),
INVALID_PASSWORD(101, "Your password is invalid"),
SESSION_EXPIRED(102, "Your session has expired");
private final int code;
private final String
private ErrorCode(int code, String message){
this.code = code;
this.message = message;
}
public String getMessage() {
return message;
}
}
Then your error handling code becomes just:
ErrorCode errorCode = getErrorCode();
prompt(errorCode.getMessage());
One drawback of this approach is that if you want to add additional cases, you'll need to modify the enum itself, whereas with a class hierarchy you can add new cases without modifying existing code.
I believe the best you can do is implementing the strategy pattern. This way you won't have to change existing classes when adding new enums but will still be able to extend them. (Open-Closed-Principle).
Search for Strategy Pattern and Open Closed Principle.
You can create a map of error codes(Integer) against enum types
Edit
In this solution, once the map is prepared, you can look up an error code in the map and thus will not require if..else look ups.
E.g.
Map<Integer, ErrorCodes> errorMap = new HashMap<Integer, ErrorCodes>();
for (ErrorCodes error : ErrorCodes.values()) {
errorMap.put(error.getCode(), error);
}
Now when you want to check an error code coming from your aplpication, all you need to do is,
ErrorCodes error = errorMap.get(erro_code_from_application);
Thus removing the need for all the if..else.
You just need to set up the map in a way that adding error codes doesn't require changes in other code. Preparation of the map is one time activity and can be linked to a database, property file etc during the initialization of your application
In my opinion there is nothing wrong with ErrorCodes as enums and a switch statement to dispatch error handling. Enums and switch fit together really well.
However, maybe you find the following insteresting (kind of over-design), see an Example
or "Double dispatching" on Wikipedia.
Assumed requirements:
Error-handling should be encapsulated in an own class
Error-handling should be replacable
Type safety: Whenever an error is added, you are forced to add error handling at each error-handler implementation. It is not possible to "forget" an error in one (of maybe many) switch statments.
The code:
//Inteface for type-safe error handler
interface ErrorHandler {
void handleInvalidLoginError(InvalidLoginError error);
void handleInvalidPasswordError(InvalidLoginError error);
//One method must be added for each kind error. No chance to "forget" one.
}
//The error hierachy
public class AbstractError(Exception) {
private int code;
abstract public void handle(ErrorHandler);
}
public class InvalidLoginError(AbstractError) {
private String additionalStuff;
public void handle(ErrorHandler handler) {
handler.handleInvalidLoginError(this);
}
public String getAdditionalStuff();
}
public class InvalidPasswordError(AbstractError) {
private int code;
public void handle(ErrorHandler handler) {
handler.handleInvalidPasswordError(this);
}
}
//Test class
public class Test {
public void test() {
//Create an error handler instance.
ErrorHandler handler = new LoggingErrorHandler();
try {
doSomething();//throws AbstractError
}
catch (AbstractError e) {
e.handle(handler);
}
}
}

Avoiding instanceof when checking a message type

I have the following situation where a client class executes different behavior based on the type of message it receives. I'm wondering if there is a better way of doing this since I don't like the instanceof and the if statements.
One thing I thought of doing was pulling the methods out of the client class and putting them into the messages. I would put a method like process() in the IMessage interface and then put the message specific behavior in each of the concrete message types. This would make the client simple because it would just call message.process() rather than checking types. However, the only problem with this is that the behavior contained in the conditionals has to do with operations on data contained within the Client class. Thus, if I did implement a process method in the concrete message classes I would have to pass it the client and I don't know if this really makes sense either.
public class Client {
messageReceived(IMessage message) {
if(message instanceof concreteMessageA) {
concreteMessageA msg = (concreteMessageA)message;
//do concreteMessageA operations
}
}
if (message instanceof concreteMessageB) {
concreteMessageb msg = (concreteMessageB)message;
//do concreteMessageB operations
}
}
The simple way to avoid instanceof testing is to dispatch polymorphicly; e.g.
public class Client {
void messageReceived(IMessage message) {
message.doOperations(this);
}
}
where each message class defines an appropriate doOperations(Client client) method.
EDIT: second solution which better matches the requirements.
An alternative that replaces a sequence of 'instanceof' tests with a switch statement is:
public class Client {
void messageReceived(IMessage message) {
switch (message.getMessageType()) {
case TYPE_A:
// process type A
break;
case TYPE_B:
...
}
}
}
Each IMessage class needs to define an int getMessageType() method to return the appropriate code. Enums work just as well ints, and are more more elegant, IMO.
One option here is a handler chain. You have a chain of handlers, each of which can handle a message (if applicable) and then consume it, meaning it won't be passed further down the chain. First you define the Handler interface:
public interface Handler {
void handle(IMessage msg);
}
And then the handler chain logic looks like:
List<Handler> handlers = //...
for (Handler h : handlers) {
if (!e.isConsumed()) h.handle(e);
}
Then each handler can decide to handle / consume an event:
public class MessageAHandler implements Handler {
public void handle(IMessage msg) {
if (msg instanceof MessageA) {
//process message
//consume event
msg.consume();
}
}
}
Of course, this doesn't get rid of the instanceofs - but it does mean you don't have a huge if-elseif-else-if-instanceof block, which can be unreadable
What type of message system are you using?
Many have options to add a filter to the handlers based on message header or content. If this is supported, you simply create a handler with a filter based on message type, then your code is nice and clean without the need for instanceof or checking type (since the messaging system already checked it for you).
I know you can do this in JMS or the OSGi event service.
Since you are using JMS, you can basically do the following to register your listeners. This will create a listener for each unique message type.
String filterMsg1 = "JMSType='messageType1'";
String filterMsg2 = "JMSType='messageType2'";
// Create a receiver using this filter
Receiver receiverType1 = session.createReceiver(queue, filterMsg1);
Receiver receiverType2 = session.createReceiver(queue, filterMsg2);
receiverType1.setMessageHandler(messageType1Handler);
receiverType2.setMessageHandler(messageType2Handler);
Now each handler will receive the specific message type only (no instanceof or if-then), assuming of course that the sender sets the type via calls to setJMSType() on the outgoing message.
This method is built into message, but you can of course create your own header property and filter on that instead as well.
//Message.java
abstract class Message{
public abstract void doOperations();
}
//MessageA.java
class MessageA extends Message{
public void doOperations(){
//do concreteMessageA operations ;
}
}
//MessageB.java
class MessageB extends Message {
public void doOperations(){
//do concreteMessageB operations
}
}
//MessageExample.java
class MessageExample{
public static void main(String[] args) {
doSmth(new MessageA());
}
public static void doSmth(Message message) {
message.doOperations() ;
}
}
A Java 8 solution that uses double dispatch. Doesn't get rid of instanceof completely but does only require one check per message instead of an if-elseif chain.
public interface Message extends Consumer<Consumer<Message>> {};
public interface MessageA extends Message {
#Override
default void accept(Consumer<Message> consumer) {
if(consumer instanceof MessageAReceiver){
((MessageAReceiver)consumer).accept(this);
} else {
Message.super.accept(this);
}
}
}
public interface MessageAReceiver extends Consumer<Message>{
void accept(MessageA message);
}
With JMS 2.0 you can use:
consumer.receiveBody(String.class)
For more information you can refer here:

How to nest Spring JMS MessageConverters

I'd like to write a MessageConverter class that can wrap another MessageConverter. This MessageConverter would call the child converter, which is assumed to generate a TextMessage. It would take the payload and GZIP compress it, creating a BytesMessage which is ultimately returned to the sender.
The problem is in writing fromMessage(). I can convert the payload back into the string, but then I want to create a "dummy" TextMessage to stuff the string into to then pass to the child MessageConverter's fromMessage() method. There I'm hitting a brick wall because I can't create a TextMessage without a JMS session object, and it appears that there is no way at all to get a session in this context.
I could create additional properties to wire up more stuff to this class, but it doesn't look like I can easily even obtain a session from a JMSTemplate object, and I can't imagine what else I'd need to have.
I am on the verge of creating a private TextMessage implementation within this code just for the purpose of wrapping a string for the child MessageConverter. That class will require tons of dummy methods to flesh out the Interface, and all of that typing makes baby Jesus cry.
Can anyone suggest a better way?
Do you really wanna wrap MessageConverter instances inside other MessageConverter instances? The whole point of a MessageConverter is to turn a Message into something else (that is not a JMS Message). Its not really designed to chain them (each step making a fake JMS message).
Why not just introduce your own interface
interface MessageBodyConverter {
/** return a converted body of the original message */
Object convert(Object body, Message originalMessage);
}
You then can create a MessageConverter invoking one of these (which can then nest as deep as you like)
class MyMessageConverter implements MessageConverter {
private final MessageBodyConverter converter;
public Object fromMessage(Message message) {
if (message instanceof ObjectMessage) {
return converter.convert(objectMessage.getObject(), message);
...
}
}
You can then chain those MessageBodyConverter objects as deep as you like - plus you have access to the original JMS message (to get headers and so forth) without having to try create pseudo (probably not JMS compliant) implementations of Message?
So I did, in fact, make one of these:
private static class FakeTextMessage implements TextMessage {
public FakeTextMessage(Message m) { this.childMessage = m; }
private String text;
private Message childMessage;
public void setText(String t) { this.text = t; }
public String getText() { return this.text; }
// All the rest of the methods are simply pass-through
// implementations of the rest of the interface, handing off to the child message.
public void acknowledge() throws JMSException { this.childMessage.acknowledge(); }
public void clearBody() throws JMSException { this.childMessage.clearBody(); }
public void clearProperties() throws JMSException { this.childMessage.clearProperties(); }
public Enumeration getPropertyNames() throws JMSException { return this.childMessage.getPropertyNames(); }
public boolean propertyExists(String pn) throws JMSException { return this.childMessage.propertyExists(pn); }
// and so on and so on
}
Makes me long for Objective C. How is THAT possible? :)

Categories