Is it possible to make web app proactive rather than reactive? - java

Web applications traditionally follow the request/response cycle, where a request is made by a user or another web app. However, I'm curious if it is possible to make a web app automatically initiate certain tasks upon it's deployment to a app server. For example, let's say we have a web app that retrieves and processes data. Is it possible to configure this app to automatically retrieve and process data when certain criteria are met, rather than needing a request from a user/another web app?

Yes it is using task schedulers like cron for example. Although one might argue, that such tasks no longer are a web application, but local applications unning on the server instead.

Have a look at Quartz Scheduler

If the data in your example are in files, then you can use a FileWatcher to monitor the folder and initiate some action when a new file lands there.
Here is one example of a very simple one, just to give you an idea of how it works:
package pilrcedit;
import java.io.*;
import java.util.*;
public class FileWatcher implements ChangeListener
{
private static final int FILE_MODIFIED=MODIFIED;
Hashtable files=new Hashtable();
ChangeListeners listeners=new ChangeListeners();
public FileWatcher()
{
Preferences.addChangeListener(this);
}
public void objectChanged(Object source,int id,Object data)
{
checkFiles();
}
private void checkFiles()
{
for(Enumeration e=files.keys();e.hasMoreElements();)
{
File f=(File)e.nextElement();
if (f.lastModified()!=((Long)files.get(f)).longValue())
{
files.put(f,new Long(f.lastModified()));
notifyListeners(f);
}
}
}
public void addFile(File f,ChangeListener listener)
{
files.put(f,new Long(f.lastModified()));
listeners.add(f,listener);
}
public void removeFile(File f,ChangeListener listener)
{
listeners.remove(f,listener);
}
public void notifyListeners(File f)
{
listeners.fireObjectChanged(f,this,FILE_MODIFIED,f);
}
}

You can include that in the deploy process itself. Or include that initial request to the webpage in the deploy process.

Since you mentioned you want to do certain things during the deployment I think you can use spring here to perform certain tasks or load something in memory (cache) during deployment. For example in the application context xml you can have this:-
<bean id="someCache" class="com.my.company.MyCache"
init-method="load">
<!-- <property> as needed -->
</bean>
MyCache class could be something like below:-
class MyCache{
public void load() {
//do your deployment work
}
}

Related

Appropriate way to implement a cli Application which also uses the service profile with Micronaut

I've no problem in creating a REST Server or a Picocli CLI Application.
But what if I want to have both in one Application?
The thing is, I want to have an Application which provides some business logic via REST Server (no problem there), but in some other cases I want to trigger the business logic via CLI without starting the HTTP Server (eg. for CI/CD).
I'm not sure if I run into problems if I start the app via
PicocliRunner.run(Application.class, args) and if a specific argument is given run the Server with Micronaut.run(Application.class);, since they create a different context.
Does anyone know a proper way to achieve this?
This is how I solved it:
import io.micronaut.configuration.picocli.PicocliRunner;
import io.micronaut.runtime.Micronaut;
import picocli.CommandLine.Command;
import picocli.CommandLine.Parameters;
#Command(
name = "RestAndCliExample",
description = "...",
mixinStandardHelpOptions = true
)
public class Application implements Runnable {
private enum Mode {serve, run}
#Parameters(index = "0", description = "Execution mode: ${COMPLETION-CANDIDATES}")
private Mode mode;
public static void main(String[] args) throws Exception {
args = new String[]{"run"};
PicocliRunner.run(Application.class, args);
}
public void run() {
if (Mode.serve.equals(mode)) {
// Start REST API
Micronaut.run(Application.class);
} else {
// TODO run code directly
}
}
}
One way to accomplish this is to #Inject the ApplicationContext into your #Command-annotated class. This allows your command to use the same application context instead of needing to start a separate one.
Then, in your run method, you can start the REST server by obtaining the EmbeddedServer from the application context and calling start on it, or you can execute the functionality directly without the REST server.
See also this answer for more detail: https://stackoverflow.com/a/56751733/1446916

Listening to class reload in Java

For performance reasons, I have a class that stores a Map whose key is a Class<?> and its value is function of that class's fields. The map is populated during code execution according to the type of the calling object. The above is a generalization/simplification
public class Cache {
private static final Map<Class<?>, String> fieldsList = ...;
//Synchronization omitted for brevity
public String getHqlFor(Class<?> entity){
if (!fieldsList.containsKey(entity))
fieldsList.put(entity,createHql(entity));
return fieldsList.get(entity);
}
}
During development, thanks to the help of Jrebel, I often make modifications to classes by changing entire properties or just their names. I can continue development just fine. However, if I already put a value into the cache it will be stale forever.
What I am asking here is if it is possible to intercept the event that a class in the classpath has changed. Very broad... But my specific problem is very simple: since I have such a need only during development, I just want to wipe that cache in case any class in my classpath changes.
How can I accomplish this? I don't need to do anything special than intercepting the event and simply wiping the cache
JRebel has a plugin API that you can use to trigger code on class reloads. The tutorial complete with example application and plugin available here: https://manuals.zeroturnaround.com/jrebel/advanced/custom.html
The JRebel plugin is a self-contained jar built against the JRebel SDK, which is attached to the running application via the JVM argument -Drebel.plugins=/path/to/my-plugin.jar. The JRebel agent attached to the application will load and start plugins from this argument.
If the application is not started with the JRebel agent, the plugin is simply not loaded.
In your example you want to register a ClassEventListener that will clear the Cache.fieldsList map. As it is a private field, you need to access it via reflection or add a get/clear method via a ClassBytecodeProcessor
public class MyPlugin implements Plugin {
void preinit() {
ReloaderFactory.getInstance().addClassReloadListener(new ClassEventListenerAdapter(0) {
#Override
public void onClassEvent(int eventType, Class<?> klass) throws Exception {
Cache.clear();
}
});
}
// ... other methods ...
}
And to clear the map
public class CacheCBP extends JavassistClassBytecodeProcessor {
public void process(ClassPool cp, ClassLoader cl, CtClass ctClass) {
ctClass.addMethod(CtMethod.make("public static void clear() { fieldsList.clear(); }", ctClass));
}
}
However a better option is to only clear/recalculate the single class entry on class reload if possible. The example didn't display whether the info computed from one class depended on superclass infos, but if this is true, the JRebel SDK has methods to register a reload listener on the class hierarchy as well.
There is an existing class ClassValue which already does the job for you:
public class Cache {
private final ClassValue<String> backend = new ClassValue<String>() {
#Override
protected String computeValue(Class<?> entity) {
return createHql(entity);
}
};
public String getHqlFor(Class<?> entity){
return backend.get(entity);
}
}
When you call get, it will call computeValue if this is the first call for this specific Class argument or return the already existing value otherwise. It does already care thread safety and for allowing classes to get garbage collected. You don’t need to know when class unloading actually happens.

How would I go about this? Different projects communicating? C#

Okay, I'm not sure how to go about explaining this, nor how to do it, but I will try to explain what I want step-by-step.
I want to make an API that contains, for example an EntitySpawnEvent object. It might look something like this:
namespace ExampleAPI
{
class EntitySpawnEvent
{
private bool cancelled;
private Entity entity;
public EntitySpawnEvent(Entity entity)
{
this.entity = entity;
this.cancelled = false;
}
public void SetCancelled(bool cancelled)
{
this.cancelled = cancelled;
}
public bool IsCancelled()
{
return this.cancelled;
}
}
}
Then I have I will have a server that uses this API. This server will also load plugins that also uses the API. The server might be something like this:
using System.Generics;
using ExampleAPI;
namespace ExampleServer
{
class Server
{
private List<Plugin> plugins;
public OnEnable()
{
LoadPlugins();
}
private void LoadPlugins()
{
// Loop through all "plugins" in the "/plugins" folder.
// Add them all to the list of plugins.
}
}
}
Then later when the server wants to spawn an entity, it throws the event to all plugins, the plugins can manipulate the event's information. For example, whether or not to cancel the event. The plugin's event listener could look something like this:
using ExampleAPI;
namespace ExamplePlugin
{
class Plugin : EventListener
{
public void onEntitySpawn(EntitySpawnEvent event)
{
event.SetCancelled(true);
}
}
}
And the server would throw it something like this:
using ExampleAPI;
namespace ExampleServer
{
class ExampleEventThrower
{
private Server server;
public ExampleEventThrower(Server server)
{
this.server = server;
SpawnEntity();
}
void SpawnEntity()
{
EntitySpawnEvent event = new EntitySpawnEvent(new Entity()); // Entity would also be part of the API
foreach (Plugin plugin in server.GetPlugins())
{
plugin.onEntitySpawn(event); // Here the plugin could manipulate the values of the EntitySpawnEvent
}
if (!event.IsCancelled())
{
// Spawn entity
}
}
}
}
Of course these are just extremely basic code examples, but they should help explain what I want.
Basically, what I want to know and do is the following:
I have an exported Server.
The Server have a /plugins folder
The user can make their own plugins using the API, export them and put them in the /plugins folder
The Server would load the plugin and let it modify all the events and such.
My key question is, how should the plugins be exported and loaded, so they can manipulate the events and such? Do I export them as DDLs? I have no idea.
I guess it's sort of similar to the way Bukkit works, but there everything's in Java and you just export it is a .jar file.
Any help would be greatly appreciated. Thanks!
So few things to take a look at...
It sounds like you want to have plugins run off of an interface that you know about, and load the plugins at runtime.
This should help you build the DLLs:
http://msdn.microsoft.com/en-us/library/3707x96z.aspx
This should help load the DLL dynamically at runtime:
Can I load a .NET assembly at runtime and instantiate a type knowing only the name?

Cannot call method in red5 server from AS3 Flash CS6

Okay, this had been making me very mad. I've followed almost 8 tutorials all over the Internet and in the end, I got my Red5 server instance working. Good for me! But when I'm calling my Java methods in my Red5 apps from my AS3 apps, in the 'Console' window in Eclipse, I got this error :
[ERROR] [NioProcessor-1] org.red5.server.service.ServiceInvoker - Method getTheName with parameters [] not found in org.red5.core.Application#17e5fde
Here's my Application.java file.
package org.red5.core;
import org.red5.server.adapter.ApplicationAdapter;
import org.red5.server.api.IConnection;
import org.red5.server.api.IScope;
import org.red5.server.api.service.ServiceUtils;
/**
* Sample application that uses the client manager.
*
* #author The Red5 Project (red5#osflash.org)
*/
public class Application extends ApplicationAdapter {
/** {#inheritDoc} */
#Override
public boolean connect(IConnection conn, IScope scope, Object[] params) {
return true;
}
/** {#inheritDoc} */
#Override
public void disconnect(IConnection conn, IScope scope) {
super.disconnect(conn, scope);
}
public String getTheName() { return "MyName!"; }
}
And here's my AS3 code. I just put this on the Timeline.
var nc:NetConnection = new NetConnection();
nc.connect("http://localhost/Mintium/RoomHere", "SomeUsernameHere");
nc.addEventListener(NetStatusEvent.NET_STATUS, onNetStatus);
nc.objectEncoding = ObjectEncoding.AMF0;
function onNetStatus(e:NetStatusEvent):void
{
switch (e.info.code)
{
case "NetConnection.Connect.Success" :
trace("connected");
nc.call("getTheName", new Responder(getName_result, getName_error));
break;
}
}
function getName_result(res:Object):void { append("Name : " + res.toString()); }
function getName_error(res:Object):void { append(res.toString()); }
Its been a week I've been trying to figure it out and my dateline is next month. If this stuff is not solved, I'm gonna fail my assessment. Please help me with my problems. Thank you very much.
Sorry I did not see this 2 months ago, I could have helped you pass your assessment. Nevertheless, I think I can answer this question, having had a similar problem calling Red5 services.
The key to solving this problem is in those parts of Red5 that utilize the Spring Framework. In your project, there should be a file called red5-web.xml that resides in the Server project's WEB-INF folder. This file contains some Bean dependencies used by Red5's Spring components. This is not mentioned in the tutorials that I read, or even in most of the (rather sparse and distributed) red5 programming documentation.
What you have to do is add a bean entry for your method in that file. In your case, the entry should look like this:
<bean id="getTheName.service" class="org.red5.core.Application" />
Note my use of the name of your function, with ".service" appended. I do not understand why, but you need the ".service" appended in order for Red5 to find your function. You need to add a similar entry for every class whose functions you want to use as services.
Of course, I based everything I said above on the fact that you put the service into the Application class -- something which I never do. if you read the red5-web.xml file, you will see that there is already an entry for that class, because it is already injected through Spring as the class that acts as an "endpoint" for processing requests over the web. I do not know if using the Application class as an endpoint and a provider of services is a good idea (it violates "separation of concerns" in OOP and may cause problems with Spring).
What I usually do is add a separate class in the org.red5.core package (or any other package you might want) that acts to deliver the desired service, then put an entry into red5-web.xml that injects the class and its method. So, for your project, lets assume you have a class called NameProvider in the org.red5.core package:
public class NameProvider
{
public NameProvider() {}
public String getTheName() { return("MyName!"); }
}
then you add the following entry to your red5-web.xml file:
<bean id="getTheName.service" class="org.red5.core.NameProvider" />
That should make everything work.
I hope this helps you in the future, or anyone else having this problem. I just wish I'd seen this question sooner.

Simple java based workflow manager / data workflow with ability to start ext. application, call web services etc

First of all, if there is already such a question like mine on the stackoverflow, sorry for that, but I haven't managed to find it. Actually I don't know what tags could I use to search for a solution which I need.
Basically, I need a tool/software which can manage a data(objects) flow using several tools/actions during the whole process. Of course one of the existing BPM/workflow platform tool can probably do that, but they seem to be too complicated for my requirements.
I have a "static" data model built with JPA/Hibernate. Then I need to change that static model in order to use different processing functions over it. That function could be some java classes, web service or external application (which support batch mode). After that I need to catch the output from these functions and make some visualisations, draw some charts etc.
I can assume that all these processing functions have access to the static model and they can change it to that specific one so there is no need to pass input to them. On the other hand the output of them should be caught by the main "workflow manager".
One more thing, the whole process should run automatically without any user interactions (maybe it will change in the future, but look and present for now). Before process starts, administrator should define which "processing function" is used and that's it.
And another thing... the best would be if the whole process was triggered when database state was changed, but it is not crucial, I can start it for example by calling a web service.
The question is: should I use one of the existing BPM/Workflow tool such as jBPM or Activiti, write a simple "workflow manager" on my own or use an existing tool which is much simpler then jBPM/Activiti (is there any?). Of course I prefer the easiest approach...
Thanks a lot for any feedback.
Apache Camel is an open source integration framework which will help you in this.
You can use Apache Camel to build your own simple workflow manager, where each process implements Processor. Your data can passed through processors using camel Exchange. Check out camel examples for more information.
For information on how to write custom processor, please read here.
You can add Processors to a Camel RouteBuilder dynamically, schedule it using Quartz Scheduler etc., which will more or less address all your requirements.
Here is good introduction to Camel : http://www.kai-waehner.de/blog/2012/05/04/apache-camel-tutorial-introduction/
A simple implementation of Workflow Manager using Camel:
WorkflowManager.java
import org.apache.camel.builder.RouteBuilder;
import org.apache.camel.impl.DefaultCamelContext;
public class WorkflowManager {
DefaultCamelContext camelContext;
public WorkflowManager() {
camelContext = new DefaultCamelContext();
RouteBuilder routeBuilder = new RouteBuilder() {
#Override
public void configure() throws Exception {
from("timer:schedule?period=1s&daemon=true").process(new ProcessOne()).process(new ProcessTwo());
}
};
try {
camelContext.addRoutes(routeBuilder);
} catch (Exception e) {
e.printStackTrace();
}
}
public void start() throws Exception {
camelContext.start();
}
public void stop() throws Exception {
camelContext.stop();
}
public static void main(String[] args) {
WorkflowManager workflowManager = new WorkflowManager();
try {
workflowManager.start();
while(true) {
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
ProcessOne.java
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
public class ProcessOne implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("In ProcessOne");
}
}
ProcessTwo.java
import org.apache.camel.Exchange;
import org.apache.camel.Processor;
public class ProcessTwo implements Processor {
#Override
public void process(Exchange exchange) throws Exception {
System.out.println("In ProcessTwo");
}
}
I used Camel version 2.9.0 to compile this code. Please note that I've used an infinite loop in main method to keep the main thread alive.
This code will run a route having ProcessOne and ProcessTwo, with a period of 1 second. You can see the period in from(...) method where I add processors to route builder. Hence, this route will run repeatedly. Also, I am not trying to flow any data. You can use exchange in the process method of each processor to flow data.
Output will be:
In ProcessOne
In ProcessTwo
In ProcessOne
In ProcessTwo
You can use camel components to make your WorkflowManager robust.

Categories