Migrating an application to a service mode [java/groovy] - java

I've got an application written in groovy. It takes some cmd args and returns previously formatted response. As system grew, it appeared that it is required to run this app extremely frequently (like 80 times in 5 mins) which leads to certain performance issues. In particular it creates all its objects over and over again which leads to filling up to 60MB RAM in one run (can be easily calculated how severely ROM/swap is used).
I want to migrate it to a service running mode which will simply take certain params and return formatted output. But:
App is always triggered by a bat/sh script (this can't be changed)
Both script and app are on the same host server
So, I'm wondering how it would be better to perform the communication of a script and a service?
P.S.: Sorry that I didn't mention, it's a standalone app, it will never use a server or anything like that as it appears to be redundant. Solution should be as simple as possible and extremely lightweight.
Example: The simplest thing I can think of by now is never to migrate it (I know it's contradictory ;)) and simply introduce a DB where all thee result will be stored and an app will have it's own schedule of when to trigger. Whenever it is triggered with any params, it should simply search the latest result in DB and return it. Easy, light, fast, and working. :)

For enterprise environments I would suggest a JavaEE application with EJB running in an application server. For your requirements this might be an overkill. A simple solution can be:
Service: Implement a RMI server with a local RMI registry. Calculations will be done here.
Script: Connect to the RMI server, invoke a method at the RMI server and display the result.
RMI Server
public class RmiServer extends UnicastRemoteObject implements RmiInterface
{
private static final long serialVersionUID = 1L;
public RmiServer() throws RemoteException
{
super();
}
public String random() throws RemoteException
{
return "Helo World! "+(new Random()).nextInt(100);
}
public static void main(String[] args) throws RemoteException, MalformedURLException
{
LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
Naming.rebind("myServer", new RmiServer());
}
}
RMI Client
RmiInterface server = (RmiInterface)Naming.lookup("//127.0.0.1/myServer");
System.out.println(server.random());
RMI Interface
public interface RmiInterface extends Remote
{
public String random() throws RemoteException;
}

Related

Is there a way to get a two-way connection from client-browser to server application simulating a shell?

Problem
Very short: I want to create Spring Shell, but as a web application.
I want to create a web-application (preferably using Spring Boot), where the frontend (ReactJS) looks like a terminal (or shell), and the backend processes inputted commands. Look at https://codepen.io/AndrewBarfield/pen/qEqWMq. I want to build a full web app for something that looks like that.
I want to build a framework, so that I can develop backend commands without knowing anything about the frontend/web application structure. I basically want to instantiate a "Terminal" object, where I give some kind of input-stream and output-stream. This way I can program this Terminal based on my given interfaces and structure, without the need of setting up all kind of front-end stuff.
A good summary of the question would be: how to send all keyboard inputs to the backend, and how to send all output to the frontend?
The reason I want to create a web application, is because I want it to be available online.
What I tried
I think the way of reaching this is using websockets. I have created a small web application using this (https://developer.okta.com/blog/2018/09/25/spring-webflux-websockets-react) tutorial, without the security part. The websocket part is almost suitable, I just cannot get an "input" and "output" stream-like object.
#Controller
public class WebSocketController {
private SimpMessagingTemplate simpMessagingTemplate;
#Autowired
public WebSocketController(SimpMessagingTemplate simpMessagingTemplate) {
this.simpMessagingTemplate = simpMessagingTemplate;
}
#MessageMapping("/queue")
#SendToUser("/topic/greetings")
public Greeting greeting(HelloMessage message, #Header(name = "simpSessionId") String sessionId) throws Exception {
System.out.println(sessionId);
// Do some command parsing or whatever.
String output = "You inputted:" + HtmlUtils.htmlEscape(message.getName());
return new Greeting(output);
}
private MessageHeaders createHeaders(String sessionId) {
SimpMessageHeaderAccessor headerAccessor = SimpMessageHeaderAccessor.create(SimpMessageType.MESSAGE);
headerAccessor.setSessionId(sessionId);
return headerAccessor.getMessageHeaders();
}
Now with this code, you can parse a command. However, it doesn't keep any "state". I don't know how it works with states and websockets.
I saw you had this Spring Sessions + WebSockets (https://docs.spring.io/spring-session/docs/current/reference/html5/guides/boot-websocket.html), but this is not really what I want.
I can send a message from the backend to the frontend by using this code:
simpMessagingTemplate.convertAndSendToUser(sessionId, "/topic/greetings", "hey", createHeaders(sessionId));
However, I want my terminal to be able to wait for input commands from the user. Seems like a stretch, but does anybody know how to achieve this?
What I sort of want
I basically want other people to program to this interface:
public interface ITerminal {
void setInputStream(Object someKindOfWrapperForTheInput);
void setOutputStream(Object someWrapperOfSimpMessagingTemplate);
void start();
}
When somebody opens the web application, they get a dedicated terminal object (so a single connection per user). Whever somebody enters a command in the frontend application, I want it to be received by the terminal object, processed, and response outputted to the frontend.
Reasons for doing this
I really like creating command-line applications, and I don't like building frontend stuff. I work as a software engineer for a company where we build a web application, where I mostly program backend stuff. All the frontend part is done by other people (lucky for me!). However, I like doing some projects at home, and this seemed cool.
If you have any thoughts or ideas on how to approach this, just give an answer! I am interested in the solution, using the SpringBoot framework is not a requirement. I ask this question using Spring Boot and ReactJS, because I have already built applications with that. A lot has been figured out already, and I think this probably exists as well.
The only requirement is that I can achieve this with Java on a tomcat-server. The rest is optional :)
Unclear?
I tried my best to make my story clear, but I am not sure if my purpose of what I want to achieve is clear. However, I don't know how to formulate it in such a way you understand. If you have any suggestions or questions, dont hesitate to comment!
If the only thing you want is a Live Spring shell that shows up in the browser it's fairly simple, all you need is to expose a standard WebSocket via the WebSocketConfigurer, then add a WebSocketHandler that executes the command and then returns the resulting String as a TextMessage.
Firstly the Socket configuration that allows clients to connect to the 'cli' endpoint
#Configuration
#EnableWebSocket
public class WebSocketConfiguration implements WebSocketConfigurer {
#Override
public void registerWebSocketHandlers(WebSocketHandlerRegistry registry) {
registry.addHandler(cliHandler(), "/cli").setAllowedOrigins("*");
}
#Bean
public CLIWebSocketHandler cliHandler() {
return new CLIWebSocketHandler();
}
}
Then the WebSocketHandler that executes the command. I recommend that for every #ShellMethod you specify the return type as String, don't use logging or System writes as they won't be returned during the evaluation.
#Component
public class CLIWebSocketHandler extends TextWebSocketHandler {
#Autowired
private Shell shell;
#Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
String result = shell.evaluate(() -> message.getPayload()).toString();
session.sendMessage(new TextMessage(result));
}
}
You can use an extension like Simple WebSocket Client to test it, by going to ws://localhost:port/cli
This is the most basic solution, adding features like security should be easy after this. Notice that I don't use STOMP, because you probably want to isolate users. But it can work alongside STOMP based endpoints, so you can have pub-sub functionality for other parts of the project.
From the question I sense that answer you'd like is something that involved Input and OutputStreams. You could possibly look into redirecting the output of Spring Shell to a different stream then have them forwarded to the sessions but it's probably much more complicated and has other trade-offs. It's simpler to just return a String as the result, it looks better in print outs anyway.

How can I create multiple servers with Java RMI?

I need:
A client, which communicates with the front-end, which communicates with 3 file servers.
How should I go about doing this? It needs to use RMI as distributed systems.
I also need to monitor all three file servers.
From what I understand, I need to establish an RMI registry, but how do I establish three concurrent servers within one registry?
Okay, so am I right in thinking i'd have the following: A server interface, a server implementation, and a master server which creates the three servers (with unique names) and finally a client?
The 'master server' needs to create a Registry on its own localhost, bind itself to the Registry so the slave servers can find it, and export a remote interface that lets the servers register themselves with it.
The master server must do the binding to this Registry on behalf of the slaves, as you can't bind to a remote Registry. But in fact the slaves don't need to be bound to the Registry at all, only registered with the master.
The master needs to export a second remote interface that provides the API to the client, which provides the upload API and whose implementation performs the balancing act. I would keep this interface separate from the interface used by the slaves, both for security reasons and for simplicity: you don't need clients trying to be slaves, or worrying about what the slave-relevant methods in the remote interface are.
All these servers and registries can run on port 1099.
The slaves are presumably multiple instances of the same service, so they all use a common remote interface. This interface provides the upload-to-slave API, and it also needs to allow each slave to provide the knowledge about how full each slave is, possibly as a return value from the upload method, or else as a query method.
Quick sketch:
public interface UploadMaster extends Remote
{
void upload(String name, byte[] contents) throws IOException, RemoteException;
}
public interface LoadBalancingMaster extends Remote
{
void register(Slave slave) throws RemoteException;
void unregister(Slave slave) throws RemoteException;
}
public interface Slave extends Remote
{
/** #return the number of files now uploaded to this slave. */
int upload(String name, byte[] contents) throws IOException, RemoteException;
int getFileCount() throws RemoteException;
}
I hope this is homework. RMI is a poor choice for file transfer, as it bundles up the entire argument list into memory at both ends, rather than providing a streaming interface.

Sharing object among threads vs Creating the object for each thread

I am required to make a client-server application as my project submission for university finals.
I have figured out how I would be writing the server but I am kinda confused with this situation I am facing.
So the server is said to support only one defined protocol (represented by a Protocol interface) and would serve to the clients that speaks using that rule only. To test the functionality of the server, I have wrote an implementation that supports the HTTP Protocol so that I can quickly test the server from browser, but there is one thing that is really confusing me.
I have defined the server as:
public interface Server {
// Methods...
public void start() throws Exception;
public Protocol getProtocol();
}
The base implementation of server does this:
public class StandardServer implements Server {
/* Implementations */
public synchronized final void start() throws Exception {
try {
while (true) {
Socket socket = serverSocket.accept();
// Use the protocol to handle the request
getProtocol().handshake(socket);
}
} catch (IOException ex) {
logger.error(ex);
}
}
}
I am confused that is it really required to do this, as I am certain that there are better ways to do this.
What I have considered so far is:
Synchronize the getProtocol() method.
Make the implementation of Protocol a thread and then use it to handle requests.
Spawn a thread when the client connects and pass-in the protocol object to that thread.
What would be the good ways to do this, considering that the server would be getting a decent amount of requests per second?
Any source code help/reference would be highly appreciated.
P.S:
I am not implementing an HTTP Server.
There would be multiple implementations of Server

Camel only sends the message on startup, then stops

I have hopefully a trivial problem. I wrote super short 'program' for Apache Camel to read the context.xml and then do as it is told:
public class CamelBridge {
public static void main(String[] args) throws Exception {
ApplicationContext context = new FileSystemXmlApplicationContext("camelContext.xml");
}
}
I connect between two JMS queues. The program works, but just when I start it. Then it stops sending messages. If I restart- it sends them all again. Is there something oviously wrong that I am missing here?
Edit:
I have updated my Main, but it does not help:
public class Bridge {
private Main main;
public static void main(String[] args) throws Exception {
Bridge bridge = new Bridge ();
bridge.boot();
}
public void boot() throws Exception{
main = new Main();
main.enableHangupSupport();
main.setApplicationContextUri("camelContext.xml");
main.run();
}
}
Edit 2
I think I found the issue (not the solution). After enabling tracing, I found the error message which reads:
jms cannot find object in dispatcher with id --some id--
And after some more digging I found that this is connected clientLeasePeriod in the remoting file. Any idea if it is possible to fix this kind of problem on Camel side?
You have to prevent JVM from finishing
Check this example: http://camel.apache.org/running-camel-standalone-and-have-it-keep-running.html
Provided you app contains only Main and xml file which configures Camel's context then context will be destroyed (so your routes destroyed as well). Even if different context run JMS implementation on same JVM. Sergey link should help you.
If you want just make it work to test things, add while(true) as a last line of your main. Note this is not the best approach :).
I realised that the problem was with the server on which the program was installed. The server thought that it resides on a public network, rather than private network (Windows Server 2012). After changing the network to private, the process worked correctly.
Note- the Camel did not give any errors regarding this, so this can be difficult to spot.

Pass Remote object in method to RMI server?

I have an RMI client that connects to some RMI server just to let it know it can use this new client.
Can I pass directly some Remote object so that:
serverRemoteObject.registerClient(theClientRemoteObjectTheServerShouldUse);
will actually give the server some object he can use without connecting to my client?
The following question says it is possible, but no real example was given:
Is it possible to use RMI bidirectional between two classes?
Andrew
Yes, you can. This is how exactly callbacks work in case of RMI. You send across an object to the server and when the server invokes a method on your object, it would be executed in the "client" JVM as opposed to on the server. Look into UnicastRemoteObject.export method for export any object which implements the Remote interface as a remote object which can be passed to your server.
interface UpdateListener extends Remote {
public void handleUpdate(Object update) throws RemoteException;
}
class UpdateListenerImpl implements UpdateListener {
public void handleUpdate(Object update) throws RemoteException {
// do something
}
}
//somewhere in your client code
final UpdateListener listener = new UpdateListenerImpl();
UnicastRemoteObject.export(listener);

Categories

Resources