Socket-based Message Factory - java

I'm looking for some ideas on implementing a basic message factory that reads a header from an input stream and creates the appropriate message type based on the type defined in the message header.
So I have something like (roughly.. and I'm willing to change the design if a better paradigm is presented here)
class MessageHeader {
public String type;
}
class MessageA extends Message {
public static final String MESSAGE_TYPE = "MSGA";
public MessageA (DataInputStream din) {
var1 = din.readInt ();
var2 = din.readInt ()
// etc
}
}
and I essentially want to do something like this:
MessageHeader header = ... read in from stream.
if (header.type == MessageA.MESSAGE_TYPE) {
return new MessageA (din);
} else if (header.type == MessageB.MESSAGE_TYPE) {
return new MessageB (din);
}
Although this scheme works I feel like there could be a better method using a Map and an Interface somehow...
public interface MessageCreator {
public Message create (DataInputStream);
}
Map <String, MessageCreater> factory = new Map <String, MessageCreator> ();
factory.put (MessageTypeA.MESSAGE_TYPE, new MessageCreator () {
public Message create (DataInputStream din) {
return new MessageA (din); }});
...
// Read message header
Message createdMessage = Map.get (header.type).create (din);
But then whenever I want to use the message I have to use instanceof and cast to the correct subclass.
Is there a 3rd (better?) option? Maybe there's a way to accomplish this using templates. Any help is appreciated. Thanks
Edit: I guess it's important to note I want to "dispatch" the message to a function. So essentially I really want to do this:
MessageHeader header = ... read in from stream.
if (header.type == MessageA.MESSAGE_TYPE) {
handleMessageA (new MessageA (din));
} else if (header.type == MessageB.MESSAGE_TYPE) {
handleMessageB (new MessageB (din))
}
So a pattern that incorporates the factory and a dispatch would be perfect

How about letting the guy who creates the messages actually dispatch to a handler.
So you'd add a handler interface like this:
public interface MessageHandler {
void handleTypeA(MessageA message);
void handleTypeB(MessageB message);
}
Then you'd have a dispatcher which is basically the same thing as your MessageCreator, except it calls the correct method on the handler instead of returning the message object.
public interface MessageDispatcher {
void createAndDispatch(DataInputStream input, MessageHandler handler);
}
The implementation is then almost identical to the first code snippet you posted:
public void createAndDispatch(DataInputStream input, MessageHandler handler) {
MessageHeader header = ... read in from stream.
if (header.type == MessageA.MESSAGE_TYPE) {
handler.handleTypeA(new MessageA (din));
} else if (header.type == MessageB.MESSAGE_TYPE) {
handler.handleTypeB(new MessageB (din));
}
}
Now you only have the one spot in the code where you have to do a switch or if/else if and after that everything is specifically typed and there's no more casting.

Related

Using RxJava for request response layer with WebSockets

I'm trying to implement a request -> response layer on top of websockets in Java. I recently stumbled across RxJava, which seems like a nice library to use for this. Down below is my current approach for handling the request response flow (unimportant code omitted for readability)
public class SimpleServer extends WebSocketServer {
Gson gson = new Gson();
Map<String, Function<JsonObject, Void>> requests = new HashMap<>();
private static int count = 0;
public SimpleServer(InetSocketAddress address) {
super(address);
}
#Override
public void onMessage(WebSocket conn, String message) {
String type = ...;
JsonObject payload = ...;
if (type.equals("response")) {
Request request = requests.get(requestId).apply(payload);
}
}
public Single<JsonObject> request(String action) {
requests.put(Integer.toString(count++), response -> {
source.onSuccess(response);
return null;
});
broadcast(...);
}
}
Is this a viable solution or is there a better way? I was thinking if there was a way to use RxJava for both ways, i.e. the request would listen to an "onMessage" observable or something along those lines.
All help will be greatly appreciated.
You can use RxJava for communication in both ways. Let's start with a simpler one – receiving messages. I recommend you use BehaviorRelay what behaves both like Observer and Consumer. You can both listen for emitted values and produce values – messages in our case. A simple implementation might look like this:
public class SimpleServer extends WebSocketServer {
private BehaviorRelay<String> receivedMessages = BehaviorRelay.create();
public SimpleServer(InetSocketAddress address) {
super(address);
}
#Override
public void onMessage(WebSocket conn, String message) {
receivedMessages.accept(message); // "sends" value to the relay
}
public Observable<String> getReceivedMessagesRx() {
return receivedMessages.hide(); // Cast Relay to Observable
}
//...
You can now call function getReceivedMessagesRx() and subscribe for incoming messages.
Now the more interesting part – sending messages. Let's assume, you have some Observable, what produces messages you want to send:
// ...
private Disposable senderDisposable = Disposables.disposed(); // (1)
public void setMessagesSender(Observable<String> messagesToSend) { // (2)
senderDisposable = messagesToSend.subscribe(message -> {
broadcast(message);
}, throwable -> {
// handle broadcast error
});
}
public void clear() { // (3)
senderDisposable.dispose();
}
}
What happens here:
Create Disposable which holds a reference to running observer of the messages to be sent.
Subscribe to passed Observable what emits every time you want to send a message. This function is meant to be called only once. If you want to call it multiple times, handle the disposal of previous sender or use CompositeDisposable to store multiple disposables.
When you are done working with your server, do not forget to dispose messages sender.

how to avoid switch statement?

I'm trying to learn client/server in java
until now i got the basics.
here how to accept and serve out many clients
public class Server {
ServerSocket serverSocket;
public void startServer() throws IOException {
serverSocket= new ServerSocket(2000);
while (true){
Socket s= serverSocket.accept();
new ClientRequestUploadFile(s).start(); //here is the first option.
}
}
}
Now suppose i have too many type of options the client can request.
the code will be as follow :
public void startServer() throws IOException {
serverSocket= new ServerSocket(2000);
while (true){
Socket s= serverSocket.accept();
DataInputStream clientStream= new DataInputStream(s.getInputStream());
String requestName=clientStream.readUTF();
switch (requestName){
case "ClientRequestUploadFile": new ClientRequestUploadFileHandler(s).start();break;
case "clientRequestCalculator": new clientRequestCalculatorHandler(s).start();break;
case "clientRequestDownloadFile": new clientRequestDownloadFileHandler(s).start();break;
}
}
}
if there 100 of options,is there any way to avoid switch statement(design-patterns maybe)?
keep in mind that may occur new option in the future.
This seems like an example where something like the Command pattern would be appropriate.
Basically, you want a way to map a given command (in this case, a String), into executing the appropriate behavior.
The simplest way to do this would be to create a Command interface like so:
interface Command {
void execute();
}
Then you can create a Map<String, Command> that holds your commands and maps each incoming String into some helper class that implements Command and does the thing you want to happen when you see that command. Then you would use it something like:
commandMap.get(requestName).execute();
This will, however, require a bit of on-the-fly setup at program startup to build the Map with the command strings and the Command objects. This is a very dynamic way of setting up the mapping, which may be a good or bad thing depending on how often your command set changes.
If your commands are more static, a more elegant way to set this up would be to use an enum to define the various commands and their behaviours. Here's a fairly simple and generic example of how you could do that:
public class CommandPatternExample {
public static void main(String[] args) throws Exception {
CommandEnum.valueOf("A").execute(); // run command "A"
CommandEnum.valueOf("B").execute(); // run command "B"
CommandEnum.valueOf("C").execute(); // IllegalArgumentException
}
interface Command {
void execute();
}
enum CommandEnum implements Command {
A {
#Override
public void execute() {
System.out.println("Running command A");
}
},
B {
#Override
public void execute() {
System.out.println("Running command B");
}
};
}
}
As pointed out in the comments, there's no way to get around having the command to helper object mapping somewhere in your code. The main thing is to not have it in your business logic, which makes the method hard to read, but rather in its own class somewhere.
So what you have is a large-ish switch block that in the end start()s some piece of code. The recommended way is to use existing interfaces, so that would be a Runnable (containing a void method with no parameters, just like your start()).
If you refactor the whole block out into a method, it would have two inputs: the Socket and the the requestName - so its signature would look like this:
Runnable getRequestCommand(Socket s, String request)
which would contain your switch block and returned something like
if ("ClientRequestUploadFile".equals(request)) {
return new ClientRequestUploadFileHandler(s);
}
// etc
Again using preexisting interfaces, this is a BiFunction<Socket, String, Runnable> (it requires the request string and the socket as input and returns the handler runnable).
Now you can split each individual case and create such a function:
BiFunction<Socket, String, Runnable> upload = (s, req) -> {
return "ClientRequestUploadFile".equals(req)
? new ClientRequestUploadFileHandler(s)
: null;
}
If you do the same for the other cases and store these in a Collection<BiFunction<Socket, String, Runnable>> (let's call it handlers), your getRequestCommand() method above looks like
Runnable requestHandler = null;
for (BiFunction<Socket, String, Runnable> handler : handlers) {
requestHandler = handler.apply(s, request);
if (requestHandler != null) { break; } // found the match
}
return requestHandler;
Now your switch actually also starts the created Runnable, so you can also if (requestHandler != null) { requestHandler.run(); } here and not return it back to the caller. As a single line, this is handlers.stream().map(h -> h.apply(s, request)).findFirst(Objects::nonNull).ifPresent(Runnable::run).
Anyway, now you're stuck with creating all the BiFunction<>s in the original class, but you can externalize them, eg. to an enum.
enum RequestHandler {
FILE_UPLOAD("ClientRequestUploadFile", ClientRequestUploadFileHandler::new),
CALCULATE("clientRequestCalculator", ClientRequestCalculatorHandler::new),
// ...
;
// the String that needs to match to execute this handler
private String request;
// creates the runnable if the request string matches
private Function<Socket, Runnable> createRunnable;
private RequestHandler(String r, Function<Socket, Runnable> f) {
request = r; createRunnable = f;
}
// and this is your handler method
static void runOnRequestMatch(Socket socket, String request) {
for (RequestHandler handler : values()) {
Runnable requestHandler = request.equals(handler.request)
? handler.createRunnable.apply(socket)
: null;
if (requestHandler != null) {
requestHandler.run();
break;
}
}
}
}
And in your client code, you'd get
// ...
Socket s= serverSocket.accept();
DataInputStream clientStream= new DataInputStream(s.getInputStream());
String requestName=clientStream.readUTF();
RequestHandler.runOnRequestMatch(s, requestName);
Now you've ended up with far more code than before, but the handling itself is removed from the class accepting the socket, so better single responsibility; this allows you to add functionality by adding a value to the enum without needing to touch your original code.
A simpler version would be to create the functions collection in a method by simply doing
Collection<BiFunction<Socket,String,Runnable>> createMappings() {
return Arrays.asList(
createMapping("ClientRequestUploadFile", ClientRequestUploadFileHandler::new),
createMapping("clientRequestCalculator", ClientRequestCalculatorHandler::new),
);
}
private BiFunction<Socket,String,Runnable> createmapping(String req, Function<Socket, Runnable> create) {
return (s, r) -> req.equals(r) ? create.apply(s) : null;
}

Apache Camel creating Consumer component

I'm newbie to Apache Camel. In hp nonstop there is a Receiver that receives events generated by event manager assume like a stream. My goal is to setup a consumer end point which receives the incoming message and process it through Camel.
Another end point I simply need to write it in logs. From my study I understood that for Consumer end point I need to create own component and configuration would be like
from("myComp:receive").to("log:net.javaforge.blog.camel?level=INFO")
Here is my code snippet which receives message from event system.
Receive receive = com.tandem.ext.guardian.Receive.getInstance();
byte[] maxMsg = new byte[500]; // holds largest possible request
short errorReturn = 0;
do { // read messages from $receive until last close
try {
countRead = receive.read(maxMsg, maxMsg.length);
String receivedMessage=new String(maxMsg, "UTF-8");
//Here I need to handover receivedMessage to camel
} catch (ReceiveNoOpeners ex) {
moreOpeners = false;
} catch(Exception e) {
moreOpeners = false;
}
} while (moreOpeners);
Can someone guide with some hints how to make this as a Consumer.
The 10'000 feet view is this:
You need to start out with implementing a component. The easiest way to get started is to extend org.apache.camel.impl.DefaultComponent. The only thing you have to do is override DefaultComponent::createEndpoint(..). Quite obviously what it does is create your endpoint.
So the next thing you need is to implement your endpoint. Extend org.apache.camel.impl.DefaultEndpoint for this. Override at the minimum DefaultEndpoint::createConsumer(Processor) to create your own consumer.
Last but not least you need to implement the consumer. Again, best ist to extend org.apache.camel.impl.DefaultConsumer. The consumer is where your code has to go that generates your messages. Through the constructor you receive a reference to your endpoint. Use the endpoint reference to create a new Exchange, populate it and send it on its way along the route. Something along the lines of
Exchange ex = endpoint.createExchange(ExchangePattern.InOnly);
setMyMessageHeaders(ex.getIn(), myMessagemetaData);
setMyMessageBody(ex.getIn(), myMessage);
getAsyncProcessor().process(ex, new AsyncCallback() {
#Override
public void done(boolean doneSync) {
LOG.debug("Mssage was processed " + (doneSync ? "synchronously" : "asynchronously"));
}
});
I recommend you pick a simple component (DirectComponent ?) as an example to follow.
Herewith adding my own consumer component may help someone.
public class MessageConsumer extends DefaultConsumer {
private final MessageEndpoint endpoint;
private boolean moreOpeners = true;
public MessageConsumer(MessageEndpoint endpoint, Processor processor) {
super(endpoint, processor);
this.endpoint = endpoint;
}
#Override
protected void doStart() throws Exception {
int countRead=0; // number of bytes read
do {
countRead++;
String msg = String.valueOf(countRead)+" "+System.currentTimeMillis();
Exchange ex = endpoint.createExchange(ExchangePattern.InOnly);
ex.getIn().setBody(msg);
getAsyncProcessor().process(ex, new AsyncCallback() {
#Override
public void done(boolean doneSync) {
log.info("Mssage was processed " + (doneSync ? "synchronously" : "asynchronously"));
}
});
// This is an echo server so echo request back to requester
} while (moreOpeners);
}
#Override
protected void doStop() throws Exception {
moreOpeners = false;
log.debug("Message processor is shutdown");
}
}

What security issues come from calling methods with reflection?

I'm working on a project that has hosts and clients, and where hosts can send commands to clients (via sockets).
I'm determined that using JSON to communicate works the best.
For example:
{
"method" : "toasty",
"params" : ["hello world", true]
}
In this example, when this JSON string is sent to the client, it will be processed and a suitable method within the client will be run as such:
public abstract class ClientProcessor {
public abstract void toasty(String s, boolean bool);
public abstract void shutdown(int timer);
private Method[] methods = getClass().getDeclaredMethods();
public void process(String data) {
try {
JSONObject json = new JSONObject(data);
String methodName = (String) json.get("method");
if (methodName.equals("process"))
return;
for (int i = 0; i < methods.length; i++)
if (methods[i].getName().equals(methodName)) {
JSONArray arr = json.getJSONArray("params");
int length = arr.length();
Object[] args = new Object[length];
for (int i2 = 0; i2 < length; i2++)
args[i2] = arr.get(i2);
methods[i].invoke(this, args);
return;
}
} catch (Exception e) {}
}
}
And using the ClientProcessor:
public class Client extends ClientProcessor {
#Override
public void toasty(String s, boolean bool) {
//make toast here
}
#Override
public void shutdown(int timer) {
//shutdown system within timer
}
public void processJSON(String json) {
process(json);
}
}
The JSON is sent by the server to the client, but the server could be modified to send different JSONs.
My questions are:
Is this a safe way of running methods by processing JSON?
Is there a better way to do this? I'm thinking that using reflection is terribly slow.
There's a 100 and 1 ways you can process a JSON message so that some processing occurs, but they'll all boil down to:
parse message
map message to method
invoke method
send response
While you could use a reflective call (performance-wise it would be fine for most cases) to invoke a method, that, imho, would be a little too open - a malicious client could for example crash your system by issuing wait calls.
Reflection also opens you up to having to correctly map the parameters, which is more complicated than the code you've shown in your question.
So don't use Reflection.
Would you could do is define a simple interface, implementations of which would understand how to process the parameters and have your processor (more commonly referred to as a Controller) invoke that, something like this:
public interface ServiceCall
{
public JsonObject invoke(JsonArray params) throws ServiceCallException;
}
public class ServiceProcessor
{
private static final Map<String, ServiceCall> SERVICE_CALLS = new HashMap<>();
static
{
SERVICE_CALLS.put("toasty", new ToastCall());
}
public String process(String messageStr)
{
try
{
JsonObject message = Json.createReader(new StringReader(messageStr)).readObject();
if (message.containsKey("method"))
{
String method = message.getString("method");
ServiceCall serviceCall = SERVICE_CALLS.get(method);
if (serviceCall != null)
{
return serviceCall.invoke(message.getJsonArray("params")).toString();
}
else
{
return fail("Unknown method: " + method);
}
}
else
{
return fail("Invalid message: no method specified");
}
}
catch (Exception e)
{
return fail(e.message);
}
}
private String fail(String message)
{
return Json.createObjectBuilder()
.add("status", "failed")
.add("message", message)
.build()
.toString();
}
private static class ToastCall implements ServiceCall
{
public JsonObject invoke(JsonArray params) throws ServiceCallException
{
//make toast here
}
}
}
Map method names to int constants and just switch(case) on these constants to invoke appropriate method.
"toasty" : 1
"shutdown": 2
switch()
case 1: toasty()
case 2: shutdown()
I believe you are trying to convert JSON string to Java object and vice versa... if that is the requirement then this would not be the right approach...
Try any open source API like Gson...
it is the API by Google for conversin of Java to JSON and vice versa.
Please check ...
https://google-gson.googlecode.com/svn/trunk/gson/docs/javadocs/com/google/gson/Gson.html
Let me know if you have any further questions...

Apache Camel: How to test for instance of Set<CustomObject>

Does anyone know how to test for different types of Collection in a route?
// This processor returns a Collection of 2 Sets
// 1. Set<GoodMessage>
// 2. Set<BadMessage>
.process(new MyGoodBadMessageProcessor())
// Split the result List
.split(body()).choice()
// How do you test for a Set<GoodMessage>??
.when(body().isInstanceOf(Set<GoodMessage>)
.to("direct:good")
.otherwise()
.to("direct:bad")
.endChoice()
Background: (In case someone can see a better way of doing this) I have a Processor that currently works as follows:
#Override
public void process(Exchange exchange) throws Exception {
Message message = exchange.getIn();
Set<UnknownMessage> unknownMessages = message.getBody(Set.class);
Set<GoodMessage> goodMessages = new HashSet<GoodMessage>();
for(UnknownMessage msg: unknownMessages) {
// Simplified logic here
if (msg.isGood()) {
goodMessages.add(msg.getGoodMessage());
}
}
message.setBody(goodMessages);
}
I'd like to update this as to now include the BadMessage(s) for reporting:
#Override
public void process(Exchange exchange) throws Exception {
Message message = exchange.getIn();
Set<UnknownMessage> unknownMessages = message.getBody(Set.class);
Set<GoodMessage> goodMessages = new HashSet<GoodMessage>();
Set<BadMessage> badMessages = new HashSet<BadMessage>();
List result = new ArrayList();
for(UnknownMessage msg: unknownMessages) {
// Simplified logic here
if (msg.isGood()) {
goodMessages.add(msg.getGoodMessage());
} else {
badMessages.add(msg.getBadMessage());
}
}
result.add(goodMessages)
result.add(badMessages)
message.setBody(result);
}
You cannot get the type of collection in this way (nothing to do with camel).
The way you've updated your process method does not need creating a different end point for bad messages.
One possible way to send this to a different end point based on message type is add a processor before the choice which inspects the type of the message and adds a header. Your choice statement can then work based on this header.
The following Predicate would work, although might give incorrect results when the Set is empty :/
Public class IsGoodMessage implements Predicate {
#Override
public boolean matches(Exchange exchange) {
Message message = exchange.getIn();
Set unknownSet = message.getBody(Set.class);
for (Object o : unknownSet) {
if (o instanceof GoodMessage) {
return true;
} else {
return false;
}
}
return false;
}
}
This helped:
How do I find out what type each object is in a ArrayList<Object>?
UPDATE: After some further reading, a better way to do this is to use a Header/Property to help distinguish the message type.
STEP 1: Update Processor to produce a Map that identifies different message types.
"GOOD_MSGS" -> List<GoodMessage>
"BAD_MSGS" -> List<BadMessage>
STEP 2: Create a splitter bean that splits this Map and then creates a header using the key of Map from the previous step.
(see "splitMessage" here http://camel.apache.org/splitter.html)
STEP 3: In the route use these headers to route the messages accordingly

Categories

Resources