I hava an app on JSF where I upload a file. Very basic. The question is, is there a way to launch (or keep executing) another java program when I reach the last page of my app? That is:
UploadFile.xhtml -> receiveFile.java -> Thanks.xhtml (user will close this the browser) -> another program make some processing on the recently uploaded file (even if user shutsdown the PC)
I thought using a daemon program that keeps checking if a new file arrived, but I want to know if there's a way to keep executing things even if the user closes the browser.
Thanks.
Certainly the best way to do this is to have a scheduler that will look for certain files every x time interval and do something with it within a thread.
Advice, make sure you shut down the scheduler on context unload. Here is an example on how to use a SchedulerService.
You would want to do something like in a context listener.
ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1);
Runnable handler = new Runnable() {
public void run() {
// handle file
}
};
scheduler.scheduleAtFixedRate(handler, 10, 10, SECONDS);
Firstly, after receiving file from client, even when client had closed their browser, file is now on the server, and you can process it free (not depend on client now) :-D
As your question, you want to launch something right after page closed. How about using annotation #PreDestroy or #PostContructor with bean scope #ViewScoped in JSF?
(in my mind, you can do this right after receiving file uploaded from client)
A reliable way to implement this would be is to have some form of meta data saved in the database after the file upload is done.
And a separate listener like Quartz to read the meta data periodically and do the post processing.
The same metadata can contain more status flags for that meta data to avoid conflicts during file processing.
Again this would depend upon the complexity of your rrquirements.
Related
I am developing a Java web application using Spring.
What I would like to do is that after the user gets to a page, the code starts running a function every 10 seconds, keeping track on the time the last action was performed.
I tried to do so with a Scheduler but it starts running immediately - and not only after the user gets to a page.
#Scheduled(fixedRate = 60000)
public void run(String param) {
//just an example of action to be performed repeatedly
System.out.println("Previously performed action was " + new SimpleDateFormat("dd/MM/yyyy HH:mm:ss").format(previousActionTime)) + " with " + param);
//update previousActionTime
previousActionTime.setSeconds(previousActionTime.getSeconds() + 10);
}
Moreover I don't know what it is a convenient way to store the time when the last action automated action was performed.
The scheduler should be somehow activated when browsing to the page:
#RequestMapping(value = "/hellopage", method = { RequestMethod.POST, RequestMethod.GET })
public String hellopage(HttpServletRequest request, HttpServletResponse response) {
// Activate scheduler
run(request.getParameter("param1"))
...
}
The scheduler (or whatever performs the automated actions) should stop as soon as the user gets again to the same web page triggering the automated actions and should run in background not blocking any other code from execution (to be precise, I cannot simply put a while loop with Sys.sleep in the function mapped to the page URL request why the page should do other things)
Any help?
Consider using ScheduledExecutorService.scheduleAtFixedRate for this as the Spring scheduler are independent of any users' request (which you have already observed and noted in question).
You may use shutdownNow to terminate the scheduler once the users' session is no longer valid / a new request is received. To achieve this you could maintain cache of previous executor(s) with user id (or any relevant information) to identify the instance which should be invalidated.
As an alternative you could use Timer and TimerTask if more fine grained control is required (however not recommended as noted here)
There are two common ways of achieving this.
The first is to run your timer client-side, in JavaScript, and then runs an AJAX/websocket/whatever call. This has many advantages - once the user navigates away from your site, the timer will stop, and you're not tying up server-side resources so your application will scale much more cleanly. This is by far the cleanest solution if your timer is linked to a single user.
The second is to use a message queue; pop a message on the queue and have an asynchronous process checking those messages, ideally aggregating multiple client sessions in a single database request. You need to figure out how to detect sessions timing out and remove the message from the message queue.
This approach is best when your timer is looking at information that's not tightly connected to the current user.
I was wondering if anyone would know if I could use the watch service in a FileInboundChannelAdapter along with a LastModifiedFileListFilter?
The sample code below is giving me fairly inconsistent results. Sometimes the file just sits in the folder and remains unprocessed.
I suspect that the watch service might be incompatible with the LastModifiedFileListFilter. For e.g.
If the LastModifiedFileListfilter is set to look for files at least 5
seconds old, and the poller is set to poll every 10 seconds.
At the 9th second, a file could be created in the watched folder.
At 10 seconds the poller queries the watch service to find out what
changed in the past 10 seconds.
It finds the newly created file.
The newly created has a last modified time of -1 second, so it
does not process it.
At 20 seconds, the poller queries the watch
service a second time, this time it does not see the unprocessed
file as it was created more than 10 seconds ago.
Would anyone else have any experience with this? Would there be a recommended way to get around this issue and allow me to verify that the file has been fully written before proceeding?
#Bean
public IntegrationFlow ftpInputFileWatcher()
{
return IntegrationFlows.from(ftpInboundFolder(), filePoller())
.handle()
/*abbreviated*/
.get();
}
private FileInboundChannelAdapterSpec ftpInboundFolder() {
LastModifiedFileListFilter lastModifiedFileListFilter = new LastModifiedFileListFilter();
lastModifiedFileListFilter.setAge(5);
return Files.inboundAdapter(inboundFolder)
.preventDuplicates(false)
.useWatchService(true)
.filter(fileAgeFilterToPreventPrematurePickup());
}
protected Consumer<SourcePollingChannelAdapterSpec> filePoller(){
return poller -> poller.poller((Function<PollerFactory, PollerSpec>) p -> p.fixedRate(2000));
}
Thanks!
Yeah, that's good catch!
Right they are not compatible. The WatchService is event-based and store files from the events into the internal queue. When the poller triggers its action, it polls files from that queue and applies its filters. Since LastModifiedFileListFilter discards the file and there is no any events for it any more, we won't see that file again.
Please, raise a JIRA on the matter and we'll think how to be .
Meanwhile as a workaround do not use WatchService for this kind of logic.
I'm trying to implement excel export for some amount of data. After 5 minutes I receive a 504 Gateway timeout. In the backend the process continues with its work.
For the whole service to finish, I need approximately 15 minutes. Is there anything I can do to prevent this? I dont have access to the servers in production.
The app is Spring boot with Oracle database. I'm using POI for this export.
One common way to handle these kinds of problems is to have the first request start the process in the background, and when the file has been generated, download the results from another place. The first request finishes immediately, and the user can then check another view to see if the file has been generated, and download the results.
You can export the data in smaller chunks. Run a test with say 10K records, make a note of the id of the last record and repeat the export starting at the next record. If 10K finishes quickly, then try 50K. If you have a timer that might come in handy. Good luck.
I had the same situation where the timeout of the network calls wasn't in our hand, so I guess you have something where it is 5 mins to receive the 1st byte and then the timeout is gone.
My solution was, let's assume you have a controller and a query layer to talk to the database. In this case, you make your process in the Async way. The call to this controller should just trigger that async execution and return the success status immediately, without waiting. Here execution will happen in the background. Futures can be used here as they are async and you can also handle the result once completed by using callback methods of Future.
You can implement using Future and callback methods in java8 like below:
Futures.addCallback(
exportData,
new FutureCallback<String>() {
public void onSuccess(String message) {
System.out.println(message);
}
public void onFailure(Throwable thrown) {
thrown.getCause();
}
},
service)
and in Scala like:
val result = Future {
exportData(data)
}
result.onComplete {
case Success(message) => println(s"Got the callback result:
$message")
case Failure(e) => e.printStackTrace
}
Objective: generate excel report.
i call a controller(JAVA) after clicking submit button from UI. After that, i populate data using procedure and do manipulation in service layer.which takes a long time, due to which i get gateway timeout error on UI (there is some amount of load on server).
So, now i was planning to call controller from UI and tell the user that excel report will be emailed to you, such that user wont wait on that screen for report.
You can do asynchronous task using spring with #Async annotation. for more detail you can have a look section 25.5.2 in spring.
Once user submits request from UI, just make an entry in database from your controller and give message to user saying "We have received your request and excel will be emailed to you".
Now in background there is job which is running, you can write this job at server side using Thread or better use Spring Batch. This job will do following
1) This will be continuously running thread, which will check is there any new entry from UI in this table, by some flag or so you can find this.
2) This job will generate excel file and email to customer
3) Once file is emailed, update flag = false in database, so that next time this job will take only flag = false records for next time processing.
Create a java program that would populate your excel sheet and rest of the things. Then in your servlet use
Process p=Runtime.getRuntime().exec(/*run your java program */);
this would create a parallel process and your servlet will end
How does async JMS work? I've below sample code:
public class JmsAdapter implements MessageListener, ExceptionListener
{
private ConnectionFactory connFactory = null;
private Connection conn = null;
private Session session = null;
public void receiveMessages()
{
try
{
this.session = this.conn.createSession(true, Session.SESSION_TRANSACTED);
this.conn.setExceptionListener(this);
Destination destination = this.session.createQueue("SOME_QUEUE_NAME");
this.consumer = this.session.createConsumer(destination);
this.consumer.setMessageListener(this);
this.conn.start();
}
catch (JMSException e)
{
//Handle JMS Exceptions Here
}
}
#Override
public void onMessage(Message message)
{
try
{
//Do Message Processing Here
//Message sucessfully processed... Go ahead and commit the transaction.
this.session.commit();
}
catch(SomeApplicationException e)
{
//Message processing failed.
//Do whatever you need to do here for the exception.
//NOTE: You may need to check the redelivery count of this message first
//and just commit it after it fails a predefined number of times (Make sure you
//store it somewhere if you don't want to lose it). This way you're process isn't
//handling the same failed message over and over again.
this.session.rollback()
}
}
}
But I'm new to Java & JMS. I'll probably consume messages in onMessage method. But I don't know how does it work exactly.
Do I need to add main method in JmsAdapter class? After adding main method, do I need to create a jar & then run the jar as "java -jar abc.jar"?
Any help is much appreciated.
UPDATE: What I want to know is that if I add main method, should I simply call receiveMessages() in main? And then after running, will the listener keep on running? And if there are messages, will it retrieve automatically in onMessage method?
Also, if the listener is continuously listening, doesn't it take CPU??? In case of threads, when we create a thread & put it in sleep, the CPU utilization is zero, how doe it work in case of listener?
Note: I've only Tomcat server & I'll not be using any jms server. I'm not sure if listener needs any specific jms server such as JBoss? But in any case, please assume that I'll not be having anything except tomcat.
Thanks!
You need to learn to walk before you start trying to run.
Read / do a tutorial on Java programming. This should explain (among other things) how to compile and run a Java program from the command line.
Read / do a tutorial on JMS.
Read the Oracle material on how to create an executable JAR file.
Figure out what it is you are trying to do ... and design your application.
Looking at what you've shown and told us:
You could add a main method to that class, but to make an executable JAR file, you've got to create your JAR file with a manifest entry that specifies the name of the class with the main method.
There's a lot more that you have to do before that code will work:
add code to (at least) log the exceptions that you are catching
add code to process the messages
add code to initialize the connection factory and connection objects
And like I said above, you probably need some kind of design ... so that you don't end up with everything in a "kitchen sink" class.
if I add main method, should I simply call receiveMessages() in main?
That is one approach. But like I said, you really need to design your application.
And then after running, will the listener keep on running?
It is not entirely clear. It should keep running as long as the main thread is alive, but it is not immediately obvious what happens when your main method returns. (It depends on whether the JMS threads are created as daemon threads, and that's not specified.)
And if there are messages, will it retrieve automatically in onMessage method?
It would appear that each message is retrieved (read from the socket) before your onMessage method is called.
Also, if the listener is continuously listening, doesn't it take CPU???
Not if it is implemented properly.
In case of threads, when we create a thread & put it in sleep, the CPU utilization is zero, how doe it work in case of listener?
At a certain level, a listener thread will make a system call that waits for data to arrive on a network socket. I don't know how it is exactly implemented, but this could be as simple as an read() call on the network socket's InoutStream. No CPU is used by a thread while it waits in a blocking system call.
This link looks like a pretty good place with examples using Oracle AQ. There's an examples section that tells you how to setup the examples and run them. Hopefully this can help.
Link to Oracle Advanced Queueing