The Source for Java Technology Collaboration

Home » java.net Forums » GlassFish » GlassFish

Thread: Interrupting a running Servlet

Welcome, Guest Help
Login Login
Guest Settings Guest Settings
This question is answered. Helpful answers available: 2. Correct answers available: 1.

Reply to this Thread Reply to this Thread Search Forum Search Forum Back to Thread List Back to Thread List

Permlink Replies: 10 - Last Post: Apr 4, 2008 4:57 AM by: stylertim
stylertim

Posts: 233
Interrupting a running Servlet
Posted: Apr 1, 2008 6:39 AM
 
  Click to reply to this thread Reply

Hi folks!

I'd like to know if and how it's possible to interrupt a running servlet, or better how to tell the servlet to suddenly do something else while it is running. In my case I'm letting the servlet invoke methods of a server-side API written in C. I need to be able to stop the running process started by this API at any time during its execution. This can be done by a "stop"-method in the C-API.

The question is now: Can I just send another HttpRequest to the servlet to trigger the invokation of the "stop"-method or is there some other magic to deal with? I assume the servlet's running in a seperate thread, right? If so, how can I access this thread?

The servlet container is a Tomcat 6.0 alongside an Apache 2.x.

Thanks in advance!

- Thomas

writtmeyer

Posts: 71
Re: Interrupting a running Servlet
Posted: Apr 1, 2008 7:07 AM   in response to: stylertim
 
  Click to reply to this thread Reply

Well this is a glassfish forum, so you probably should post your question on tomcats user mailing list.

Nevertheless some remarks. Long lasting servlets are a bad idea - unless you use a NIO-based connector. GF has one and Tomcat 6 has one as well. But you really should use a NIO-based connector if your servlet really waits for the C-app to end. When using blocking connectors your are consuming valuable (and limited - thought the limit itself can be adjusted) threads.

You cannot "connect" back to a previous request. If this C-app can run more than once you need to transfer the PID back and forth and call the correct process in a completely unrelated servlet thread to stop. And you should be very careful to not cause a security nightmare with this design! If it can run only once on the machine there is no need to connect back to your other thread (or at least I cannot see why you want to do so). Just issue the stop-call and - voila - you're done. What am I missing here? And why is the first servlet waiting for the C-app to end in the first place?

There are also some other subtleties to consider: A browser can only open two connections to the same server at any given time (without using hacks). So if one is already a long-lasting request you must ensure that the second request is not long-lasting as well. Otherwise you cannot connect from this browser to your server until you restart your browser or your browser hits a timeout.

As already stated I recommend to contact the tomcat user mailing list. Otherwise it would be wise to give us some more background about the purpose of your app so that we can help you.

--
Wolfram Rittmeyer

whartung

Posts: 634
Re: Interrupting a running Servlet
Posted: Apr 1, 2008 10:19 AM   in response to: writtmeyer
 
  Click to reply to this thread Reply

writtmeyer is right, this isn't a simple problem.

You need a layer between your servlet are you C server.

Effectively you should be making requests to this C-Server service layer from your servlet, and those requests should not block your servlet (at least not for any meaningful amount of time).

The C-Server service layer can have a very simple API:

public interface CServerService {
    /* returns a process id token */
    public String startService(ServerArgs args);
    public void stopService(String processId);
    public ServerStatusResult getServiceStatus(String processId);
    public ServerResult getServiceResults(String processId);
}


Then in one servlet call, you can invoke the CServerService.startService method, and IT does whatever is necessary to invoke the C Server, including creating any threads for it to maintain the connection with the C Server, marshalling the data, creating any listeners that may be needed, etc.. It returns an ID (a string in my case, could be anything) that can be used later to identify the specific invocation of the service, and, as you can see, can be used to stop the service, get it's status (running, stopped, X% complete, whatever you may be tracking), and the results of the service call.

This removes the burden of managing the C Server connection from your servlet container (and puts it in your hands, where it belongs).

stylertim

Posts: 233
Re: Interrupting a running Servlet
Posted: Apr 2, 2008 6:08 AM   in response to: whartung
 
  Click to reply to this thread Reply

Hi!

First of all, thank you guys for your help. I realize this isn't an easy task and the one way we thought of to get around this was to simply put a file on the server which the C process is looking for. Quite dirty, I know.

The thing with the seperate C service looks very nice. Since I'm not that much of a JavaEE guy here's another problem: How do I dispatch HttpServletRequests from inside a client application? Up until now I have always invoked the servlet by calling the URL specified in the servlets url mapping. I want to be able to simply click a on button representing the corresponding function in the C DLL/SO.

I've checked in the API reference and looked at all the classes but so far I can't see how to get a hold of the necessary objects. Ok, connecting to an http server isn't that big a deal with the URL class but how to retrieve a ServletContext? I assume I'll especially need that class to get things going, correct?

Here's my current plan:

1. Establish a connection to the webserver

2. Invoke the servlet with a request indicating to start the C process manager
and retrieve the ServletContext so I can send further requests.

3. Get the interger value returned by the C methods back to the application via a ServletResponse when all stuff is done

Well, I might need a bit of help with this. :)

Thanks so much for your input so far!

- Thomas

writtmeyer

Posts: 71
Re: Interrupting a running Servlet
Posted: Apr 2, 2008 10:38 AM   in response to: stylertim
 
  Click to reply to this thread Reply

Well, to be honest, I still cannot figure out the design of your app. Which might be the cause for some misunderstandings.

As far as I've understood your requirements and question I recommend the following:

The IMHO easiest way to connect to a Webserver from within Java is by using the httpclient library of Apache (http://hc.apache.org/httpclient-3.x/).

The servlet may access the ServletContext (e.g. to get initialization parameters) but _not_ the client. You can send further requests whenever you like to do so. What would you like to use the ServletContext for? You could use one servlet to start the process (and you should take whartungs suggestion to your heart) and another to stop the process. Or one servlet for both actions which takes different parameters to trigger the respective actions.

An ajax request could, as you suggested in your first post, check whether the status of the processt has already changed (do not forget to use proper synchronization otherwise you might run into visibility issues) and return an appropriate response to the client. Given whartungs suggestion above this servlet would call the getServiceStatus(pid) method. If the C-app has returned in the meantime, the ServerStatusResult should contain the required returncode of your C-app.

--
Wolfram Rittmeyer

stylertim

Posts: 233
Re: Interrupting a running Servlet
Posted: Apr 2, 2008 11:37 AM   in response to: writtmeyer
 
  Click to reply to this thread Reply

Hi Wolfram!

Sorry for so much confusion.

Ok, to lift the fog a little I will explain the whole idea in detail, what I have and what I want. I will leave out the webserver and servlet container details.

I have:

a) a C-DSO residing on a webserver, which executes a process in a Linux Kernel with real time extensions. This process is to obtain a buch of values from a measurement device connected to the webserver. This may take a long time. But this isn't my part. All I care about is that the C-DSO HAS to be on the webserver!

b) a Java application or applet (not sure yet) which is able to visualize the data provided by the C process. Also it is able to start the measurement and stop it at any time.

I want:

...my application/applet to be able to start and stop the C process on the webserver. Nothing more. :)

Our first idea was to use servlets for this purpose. So far I've been able to invoke a servlet that calls the start method of the C-DSO. Directly by typing the servlet URL in the browser's address bar. But that's not what I need.

I thought of it this way:

I invoke the servlet from my application with request that informs it of what it should do. Than the servlet starts C-process in a seperate thread and stays active to listen to further requests, which might i.e. be a stop request. After the C-process has done what I want it should terminate, the thread in which it lived should terminate and finally the servlet should cease to be.

Is this approach totally nuts and overly complicated? As I mentioned before, I'm not really into JavaEE, still I have to get the job done.

Do you have any other suggestions on how to get there, maybe without servlets?

I'm ashamed I lack so much experience in this case. Sorry for torturing you! :D

- Thomas

writtmeyer

Posts: 71
Re: Interrupting a running Servlet
Posted: Apr 2, 2008 1:10 PM   in response to: stylertim
 
  Click to reply to this thread Reply

Well, the fog has cleared indeed ;-)

The approach needs some adjustment on the servlet part - but other than that I think it is reasonable.

I think two things have to be fleshed out in more detail: The way your webapp communicates with the C-app and the way your servlet(s) can interact.

Communication between webapp and C-app:
I do not have any experience with JNI but AFAIK there still are three possibilities:
->The C-app calls callback methods in the Java code via JNI. According to your post you do not have control over the library so this option might not be possible at all. If it is possible it would allow to get the results of all measurements made until a certain point of time even when the C-app hasn't completed all operations.
-> The C-app returns a result-object via JNI. The result of all measurements is only available at the end which according to your post might last for some while. I would try to avoid that if possible.
-> The C-app writes to a file and your Servlet(s) read from this file any results already available.

Servlet-interaction:
For simplicity reasons I assume that for each remote task your client wants to be executed on the webserver a dedicated servlet is used.
Your client-app calls (e.g. via the HttpClient library) the servlet on the webserver that starts the C-app. The servlet calls "startService()" in a seperate thread and returns immediately.
Your client-app polls the server (e.g. once every second) by calling a servlet that calls "getServiceStatus()". This method could either read the file (for the third option given above) and report back any measurements that already have been made or return a status that was set earlier by the callback methods. The results can be reported back in XML, CSV or whatever format you like. After sending this response the servlet is done and gone.
You client-app might also invoke a third servlet on the webserver to stop the C-app by invoking "stopService()". This servlet also returns immediately.

Now since you seem to be a servlet novice some infos about these. Each servlet can be invoked multiple times. Concurrently and in succession. So it would be possible for more than just one client to poll the server for results. _But_ because of this you also must assure that the C-app is started only once.
One request is totally unrelated to another request. Even two requests for the same servlet. To exchange data between servlets you can use the session or the application scope or (normally a bad idea) instance variables of your servlet. I think for what you've outlined here the application scope might be the best (which is pretty rare). Only thereby you could stop a process another client has started.

I hope this helps and we might be able to find a viable approach for your app.

stylertim

Posts: 233
Re: Interrupting a running Servlet
Posted: Apr 2, 2008 3:56 PM   in response to: writtmeyer
 
  Click to reply to this thread Reply

Yes, I think I get the idea.

Still I've got one question: How would I best implement the separate, independent service dealing with the C-App? I've been asking myself how this could be done and after several hours of reading I still haven't got the slightest idea. :)

Just to clarify, are we talking about a seperate process running outside the JVM of the servlet? Are we talking about a thread opened within the servlet? I'm not sure I see all through this cunning plan.

Maybe some information about the DSO implementation is helpful. I actually do have control over the invokation of the methods of the DSO. But I've no control over the internal implementation! There are three methods - start, stop, processData - which are to be linked by a java class and invoked by public native methods within this class. I need access to this object at any time!

I have no idea how I could access a separate process from within a java app running on the client side, much less how I could get the above object back to ivoke my native methods.

This matter is really drinving me over the edge. :)

- Thomas

writtmeyer

Posts: 71
Re: Interrupting a running Servlet
Posted: Apr 3, 2008 1:26 PM   in response to: stylertim
 
  Click to reply to this thread Reply

Thomas, a possible solution would be to use a seperate thread to actually start the native method. In the run()-method you could call the native code which according to my understanding lasts for quite a while. Of course the thread would have to have a reference to an object in the ServletContext (if you want to use the application scope) to which you can pass the result. The concrete implementation of CServerService seems to be a possible candidate for that. Now your implementation of whartung's interface would start the thread in the startService() method.

I think all other methods (check whether a result has already been set, return the result, stop the process) do not have the need for a seperate thread since they all return quickly.

From within your servlets you'd just call the necessary method of the CServerService which then starts a seperate thread if needed. All servlets return immediately. So you must poll for state changes and the actual result.

Thus your servlet indrectly starts the new thread. On behalf of your client, but the client only issues http requests to your servlet.

whartung

Posts: 634
Re: Interrupting a running Servlet
Posted: Apr 3, 2008 9:49 PM   in response to: writtmeyer
 
  Click to reply to this thread Reply

The beauty of UNIX like operating systems is that there's a zillion ways things can be done.

I'm not a fan of JNI for the simple reason that when things go wrong in pure Java, you basically tend to get an exception or something. When things go wrong with JNI, you tend to get a core dump which means a dead server.

I'm also not a big fan of forking the server to execute C programs, mostly because the servers tend to be LARGE and have an impact on the the system for the split second that the system is cloning the process to exec the new process. I've had large app servers fail to fork because there wasn't enough swap on the system to handle two copies of the system.

Mind, I don't see this application having that problem, but as a rule I resist forking the server if I can avoid it.

Which leads us to the next point: how can we trigger a remote process, and how can we do it easily?

Step one is to have a listener program, a daemon. But what does it listen to?

As was suggested, it could simply poll a directory looking for a file. That's simple and straightforward. It could use a socket. Open a socket, listen for traffic. This is trivial as well. inetd makes writing trivial socket servers, well, trivial. The detail is that a socket is a public resource -- anyone with the socket port number and able to route to it can talk to it. It's up to the application to judge whether the system sending data is authorized or not, and who wants to write that code? If this is inside behind your firewall, then this may be just fine. If it's not, then it gets more complicated and not worth the trouble.

On UNIX you have other sockets, they're called Unix Domain Sockets. These are actually limited to the system with the socket, they're not accessible on the network. Alas, you can't do this in Java, out of the box, Java has no support for Domain Sockets. (You can get a library that gives you this funcationality -- but again, there's the JNI stuff again.)

But, there's a 3rd, less common way to do this. And it's trivial as well.

On UNIX systems (Windows too, but they're different) there's a thing called a "Named Pipe". It's commonly referred to as a FIFO, First In First Out. Basically it's a little buffer in memory that two processes can use to talk with.

The beauty of it tho, specifically with Java, is that it operates just like a normal file, so Java (and anything else) can use them out of the box.

The way you use them is first you need to create one in the filesystem. This is done with the mkfifo command (it used to be the mknod command).
$ cd /tmp
$ mkfifo mypipe


At this point, it's just like a normal file, so you need to make sure permissions and ownership are correct.

Now, your listener process simply opens the file for read. This can be a C program, a Perl program, or, golly, even a Java program.

    public static void main(String[] args) throws Exception {
        FileReader fr = new FileReader("/tmp/mypipe");
        BufferedReader br = new BufferedReader(fr);
        
        String line = br.readLine();
        while(line != null) {
            System.out.println(line);
            line = br.readLine();
        }
        br.close();
        fr.close();
    }


Pretty simple. Take that code, plop it in a file, and run it. It'll just sit there. Then go to another terminal shell and type:
$ ls > /tmp/mypipe


And, shazam, two things will happen. One, the list of files in your directory will be printed out by your Java process, and, two, the java process will end.

When the input side of a pipe is closed, the output side inevitably gets closed as well (after the data is run through of course). The actual pipe, /tmp/mypipe, remains though.

But there's another catch here. Try the experiment again, only this time run the 'ls' command first, THEN the Java process. You'll notice that the 'ls' command waits for someone to open up the other end, just like the Java process did when it was waiting for input.

So what does all of this mean?

It means that you have available a very simple IPC mechanism, and that it's reasonably reliable. If you know someone is reliably going to be on the other end of the pipe, you can safely, blindly open the pipe up and start read or writing data to it.

Here's what you can do.

#!/bin/sh
#
# brain dead daemon
 
# loop until the cows come home
while [ 1 ]
do
    # get the command -- no, really, this works
    cmd=`cat /tmp/mypipe`
    if [ $cmd = "start" ]
    then
        echo "starting program"
        # start the program somehow
    fi
    if [ $cmd = "stop" ]
    then
        echo "stopping program"
        # stop the program somehow
    fi
    if [ $cmd = "exit" ]
    then
        echo "exiting daemon"
        # exit the daemon
        exit;
    fi
done


That shell script will run forever listening to that pipe to do your bidding. You can easily write this in C or anything else. Use the init.d scripts perhaps as inspiration, as they do this kind of thing all day long (start and stop servers).

In your Java code, open the pipe for output, (new FileOutputStream("/tmp/mypipe") or FileWriter("/tmp/mypipe")), print the command to it, and close it. Instant IPC.

Just make sure you synchronize your pipe writng code so only one thread talks to the pipe at a time.

The only downside to using simple code is that if for some reason the little daemon dies, the server will block waiting for the other end to open. There are all kinds of shenanigans and hocus pocus you can use to detect that, route around that, protect against that, but I'm betting your won't need them. Probably easier to have the daemon create and destroy the pipes when it starts up and shuts down, then the server will throw nasty (but readily detectable) File Not Found exceptions. There are other issues (just like with anything), but you really won't be running in to those for simple IPC like this.

If you want the CServer to talk back, start a thread, suck on a pipe (a different pipe, /tmp/myotherpipe), and use that to get commands back from the CServer to do what you will. Say the CServer can send back the file name it just created so your server can load it in to a DB or whatever.

The hi tech Java way of doing all this is to use JMS, JMS servers, clients, listeners, etc. Lot of code and complexity (lot of features too, but..). This is just a simpler model for a simpler task.

(Oh, I don't suggest /tmp for permanent pipes - lot of systems purge /tmp files on boot, or after they're a week old, and pipes are no exception...)

Good Luck...

stylertim

Posts: 233
Re: Interrupting a running Servlet
Posted: Apr 4, 2008 4:57 AM   in response to: whartung
 
  Click to reply to this thread Reply

Thank you guys so much!

I already played around with the servlets and threads and I'm very grateful for all your hard work responding to my annoying questions. :)

I guess, just out of curiousity, I'll try both approaches, the pipes and the sockets. This shall be interresting.

Thanks again!

- Thomas




 XML java.net RSS