aspose file tools*
The moose likes OO, Patterns, UML and Refactoring and the fly likes Front Controller and Commands Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Engineering » OO, Patterns, UML and Refactoring
Bookmark "Front Controller and Commands" Watch "Front Controller and Commands" New topic
Author

Front Controller and Commands

Tony Baines
Greenhorn

Joined: Aug 11, 2003
Posts: 15
Dear all,
I've spent some time browsing, but I haven't been able to find a recognised solution to this one.
Our J2EE app uses a controller to manage Command beans, but some of the operations are quite long running so the controller is waiting for the bean's execute() method to return. At the moment we're getting around it by implementing SingleThreadModel - but I know that's frowned upon as a design decision, and I believe deprecated in the latest spec (?).
The approach I'm considering is to have an instance of a new Threaded manager class which would be instantiated by the controller, started and forgotten about. My concerns are the question of multi-threading in a J2EE environment - is it OK if it's not in a Servlet or EJB?, and the lack of info on other peoples experiences.
Cheers
Tony
[ August 11, 2003: Message edited by: Tony Baines ]
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
I don't understand how using the SingleThreadedModel helps, so I guess I don't understand your question.
Could you please elaborate?


The soul is dyed the color of its thoughts. Think only on those things that are in line with your principles and can bear the light of day. The content of your character is your choice. Day by day, what you do is who you become. Your integrity is your destiny - it is the light that guides your way. - Heraclitus
Frank Carver
Sheriff

Joined: Jan 07, 1999
Posts: 6920
Hi Tony! Welcome to the Ranch.
Can you clear up a bit more of what you are aiming for from this (re)design?
From your description of the existing system it sounds like the controller calls your commands and does not return/include/forward the results until processing is completed. i.e. a "synchronous" design.
From your description of your planned system, it sounds like you intend to hand off processing to a separate, multi-threaded, unit and then return/include/forward something while it is potentially still processing. i.e. an "asynchronous" design.
Is this the intention of this proposed change? If so, how do you propose to handle the return of possibly incomplete results, and how do you propose to fetch the final results once completed? I know these aren't directly in answer to your original question, but they do affect the solution.
If your main aim is just to show a "work in progress" screen during long processing, then the trick I use is to send a page containing an immediate meta-redirect to the request which performs the potentially long-running real work. The user then sits looking at this "sorry, still busy" screen rather than the screen the operation was launched from. This conveniently helps to prevent click-twice-syndrome.
If your aim is to allow long processing to be abandoned or cancelled by the user there are also other approaches (such as an object with some sort of "abort" method placed in the session and callable from another parallel servlet).
If your intention is simply to prevent multiple instances of the long processing being started at the same time, some sort of status flag stored in the application context and clecked by the command before it starts would seem a simpler solution.
Can you give any more hints about why you chose to use SingleThreadModel in the first place?
I think the reason that explicitly multi-threaded code is rare in J2EE environments is that a servlet container already provides a flexible and powerful multi-threaded environment for you to use, unless you tie its feet together by using things like SingleThreadModel.
Has any of this helped?


Read about me at frankcarver.me ~ Raspberry Alpha Omega ~ Frank's Punchbarrel Blog
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
If the problem really is providing some feedback before the long-lasting task got completed, the following article might also be of interest: http://www.onjava.com/pub/a/onjava/2003/06/11/jsp_progressbars.html
But as I don't see how the SingleThreadedModel should have helped in that situation at all, I have the feeling that the main issue is something else...
Tony Baines
Greenhorn

Joined: Aug 11, 2003
Posts: 15
I don't know if this makes it any clearer (or if it will format well)

The Controller is blocked from handling any further requests until the Business Delegate returns the results from the Integration tier. To get around the bottleneck we flag that the Controller servlet implements SingleThreadedModel, which means that the Web container will instantiate multiple instances of the Servlet but ensure that only a single request is made at a time to any given instance.
The solution I tried to outline above would introduce a manager class per request which would be started by the controller. The controller is then free to service the next request, and the manager takes care of waiting for the bean to finish its execute().
[ August 11, 2003: Message edited by: Tony Baines ]
Frank Carver
Sheriff

Joined: Jan 07, 1999
Posts: 6920
The Controller is blocked from handling any further requests until the Business Delegate returns the results from the Integration tier.
Can you exdplain in what way this is "blocked"? Is it because of some sort of policy imposed by the back-end business process? Is it because of some framework you are using for the command dispatch?
Consider the following very simple dummy implementation
(untested, compile at your own risk!)
This naively seems capable of processing and/or blocking long commands without resorting to SingleThreadModel. Can you help explain what extra constraints you have that would prevent (for example) the Thread.sleep(5000) being replaced with your business processing?
To get around the bottleneck we flag that the Controller servlet implements SingleThreadedModel, which means that the Web container will instantiate multiple instances of the Servlet but ensure that only a single request is made at a time to any given instance.
But all this really says is that the container sometimes has the overhead of creating and initializing a whole new servlet for each request rather than reusing an existing precreated instance. It will still let the business logic be called more than once at the same time. Can you explain again which part of the system is imposing this "bottleneck"?
[ August 11, 2003: Message edited by: Frank Carver ]
Lasse Koskela
author
Sheriff

Joined: Jan 23, 2002
Posts: 11962
    
    5
Reminder: SingleThreadModel is deprecated as of J2EE 1.4 with no replacement...


Author of Test Driven (2007) and Effective Unit Testing (2013) [Blog] [HowToAskQuestionsOnJavaRanch]
Tony Baines
Greenhorn

Joined: Aug 11, 2003
Posts: 15
Perhaps the missing information is that the results of the command.process() are accessed by the JSP? If I understand your approach correctly, there would have to be an additional 'watcher' of commands to wait for them to complete and manage the forwarding to the JSP.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Tony Baines:
Perhaps the missing information is that the results of the command.process() are accessed by the JSP? If I understand your approach correctly, there would have to be an additional 'watcher' of commands to wait for them to complete and manage the forwarding to the JSP.

The way I read it, the forwarding does already happen *after* the command completed - the call to the command is synchronous.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Frank Carver:

As an aside, this code isn't threadsafe. The busy variable needs to be declared volatile, or *every* access to it should be synchronized - otherwise it isn't guaranteed to be updated to values given to it in other threads.
Tony Baines
Greenhorn

Joined: Aug 11, 2003
Posts: 15
Originally posted by Ilja Preuss:

The way I read it, the forwarding does already happen *after* the command completed - the call to the command is synchronous.

Which is what I've been trying to say (perhaps not very concisely). My understanding of Frank's code is that, if the results of process() are required, I would have to have a scheme for managing unfinished commands and forwarding the appropriate request to their associated JSPs once the command.process() completed.
[ August 12, 2003: Message edited by: Tony Baines ]
Tony Baines
Greenhorn

Joined: Aug 11, 2003
Posts: 15
Re-reading Frank's original reply
Originally posted by Frank Carver:

If your main aim is just to show a "work in progress" screen during long processing, then the trick I use is to send a page containing an immediate meta-redirect to the request which performs the potentially long-running real work. The user then sits looking at this "sorry, still busy" screen rather than the screen the operation was launched from. This conveniently helps to prevent click-twice-syndrome.

The 'Busy Screen' JSP would fulfil the function (with the help of appropriate logic) of waiting and rechecking the state of the command, but wouldn't the Command have to be a Thread?.
Frank Carver
Sheriff

Joined: Jan 07, 1999
Posts: 6920
The 'Busy Screen' JSP would fulfil the function (with the help of appropriate logic) of waiting and rechecking the state of the command, but wouldn't the Command have to be a Thread?.
Nope. You just let the browser do it, it's what they do anyway.
If you make the "busy page" something like:

The browser will show it and then wait. That's the simplest way.
If you are worried that the browser might "time out" because the processing takes too long, replace the 0 with (say) 5 for 5 seconds, and have "longprocessing.jsp" return the above if still going, or the answer if finished. That way the browser will keep retrying every five seconds.
Does this make sense?
Tony Baines
Greenhorn

Joined: Aug 11, 2003
Posts: 15
I was suggesting using the reloading JSP to poll the Command instance to see if it were done yet. It would mean passing the Command and the address of the JSP to redirect to once complete to the 'Busy Page', but I still believe that the Command would have to be threaded e.g.

with appropriate subclassing etc. for individual Commands. The Controller servlet could start() the Command, and redirect the request to the 'Busy Page' - which would poll the Command instance every reload to see if it were done, finally redirecting to the 'proper' JSP.
Am I over-complicating?
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Tony Baines:
I was suggesting using the reloading JSP to poll the Command instance to see if it were done yet.

The reloading JSP is only necessary if you are getting browser timeouts. As the SingleThreadedModel would hardly solve such a problem, I am still wondering wether we are talking about the same problem...
So, tell us again, what is the problem with "the controller waiting for the bean's execute() method to return"?
Tony Baines
Greenhorn

Joined: Aug 11, 2003
Posts: 15
Originally posted by Ilja Preuss:

So, tell us again, what is the problem with "the controller waiting for the bean's execute() method to return"?

The controller is unable to service another HTTP request until it has been freed. Implementing the SingleThreadModel ensures one request at a time (since my code is not designed to be Thread-safe), and provides other instances of the the controller servlet to service requests in parallel.
All my more recent posts have been discussion points for the redesigned version, which will hopefully have no need for the messiness of SingleThreadModel.
Ilja Preuss
author
Sheriff

Joined: Jul 11, 2001
Posts: 14112
Originally posted by Tony Baines:

The controller is unable to service another HTTP request until it has been freed.

OK. Why? And how does a wait page solve that problem?
Tony Baines
Greenhorn

Joined: Aug 11, 2003
Posts: 15
[Existing implementation] Because the handling code in the controller servlet creates a command-bean, populates it via setters, calls an execute() method (which may be long running), waits for it to finish, calls getters if required, puts it into the request scope and then forwards the HTTP request on to the JSP that will use the bean to display data.
The forward cannot happen in the current scheme until the data that the command-bean collects is available.
[Possible way forward] Making the command-bean into a Runnable, and just start()ing it in the controller (which means the controller gets the flow of control back almost immediately) is only useful if there is something to check on how the long-running execute() method is doing, and to forward the HTTP request to the destination JSP when it is ready.
Frank Carver
Sheriff

Joined: Jan 07, 1999
Posts: 6920
I think we're getting somewhere. You seem to be implying that your "command bean" is not re-entrant (which is reasonable for a bean, but very unusual for a command object). Your approach to preventing the bean being reused while it is still operating is to prevent the whole controller accepting any more commands using SingleThreadModel.
The upshot of this is that when your controller is busy with a long command, it's not even allowed to execute a completely different one in parallel. Instead, the servlet container is forced to create and initialise a whole new controller and all its command-bean creation code. This seems quite a clumsy and heavyweight solution.
It seems reasonable for the user requesting the long operation to wait for it to finish, but surely other users should not be penalised.
Is there any particular reason why your "command bean" is not re-entrant? Does the command really need to be a bean, configured with getters and setters, or could it be true re-entrant command object, with (for example) your existing code creating and configuring a bean to pass in as an argument object to the command's "execute" method?
e.g.
Old "command bean" code:

New "true command" code:

If this is really too difficult, can you explain why you can't just create a new command bean for each request, instead of a whole new controller?
Tony Baines
Greenhorn

Joined: Aug 11, 2003
Posts: 15
We do seem to be getting closer to a common undertanding. THe terminology we use within the project is that a state is represented by a StateBean and optionally a JSP.
The controller servlet creates an instance of the appropriate StateBean subclass for a given state (determined by the previous state and an 'action'). The definition for a state is an XML document that defines prerequisite data for that state (built up through preceeding states) which a helper class retrieves from storage and calls setters for, and the data that will be available after any processing of that state (for consumption by subsequent states and/or the JSP associated with the state) via getters.
So, we are creating a new command-bean (StateBean) for each request, and I am trying to move away from the SingleThreadModel, but I would obviously prefer to avoid large structural changes (e.g. the Struts approach of introducing a servlet into the mix of JSP+bean = state). My preferred line of attack is to make the StateBeans Runnable, so that the controller simply start()s and forgets them - handing on mangement to a reusable JSP which is parameterised to know about the start()ed bean and to manage the flow of control on to the next JSP or State as appropraite. Does anyone have any comments on whether there are major flaws to this approach?
Frank Carver
Sheriff

Joined: Jan 07, 1999
Posts: 6920
So, we are creating a new command-bean (StateBean) for each request, and I am trying to move away from the SingleThreadModel
Oh. You've lost me again. If you are creating a new StateBean for each request, then it's can't be the StateBean which is causing the re-entrancy problem. To come up with a way to get this working we really need to know which part of your design is not re-entrant. Maybe if you could tell us what happens if you just remove the SingleThreadModel. What breaks? And how?
but I would obviously prefer to avoid large structural changes (e.g. the Struts approach
Of course. Your existing design seems fundamentally sound, except for the use of SingleThreadModel, and I'm sure there's an elegant fix for that hiding in here somewhere.
Tony Baines
Greenhorn

Joined: Aug 11, 2003
Posts: 15
The code that is not re-entrant is the controller servlet - probably. Perhaps this is just a gap in my understanding of multi-threading issues.
The code from the controller servlet in question is

My belief was that race-conditions could occur where the stateManager instance was over-written by a subsequent request - we switched to SingleThreadModel in response to faults where multiple requests were coming in close together (e.g. where multiple report views were being generated from a single request). What is ticking my hindbrain at the moment is that the call stack should take care of local per-thread instances, and if so I ought to go looking for other causes (e.g. the StateBean instance used to be placed in the session with a fixed name, though it's now in the request). :roll:
How does that sound? Is the code above safely re-entrant because each new request will have it's own StateManager instance, and doesn't use any class attributes - or is this the problem I started off believing it was?
[ August 13, 2003: Message edited by: Tony Baines ]
Frank Carver
Sheriff

Joined: Jan 07, 1999
Posts: 6920
What is ticking my hindbrain at the moment is that the call stack should take care of local per-thread instances, and if so I ought to go looking for other causes (e.g. the StateBean instance used to be placed in the session with a fixed name, though it's now in the request).
Yup. That code looks fine (unless the code being executed uses some shared resource like a dodgy connection pool or a shared result cache). I get the strong feeling that your current use of SingleThreadModel is a case of Grandma's Ham.
I guess what you really need to do is deveise some sort of test case (maybe using a site-pounding tool, or setting up a never-terminating command which you can try manually) to see if the original problem has actually been fixed.
Tony Baines
Greenhorn

Joined: Aug 11, 2003
Posts: 15
Nice story . I'll try just ripping out the SingleThreadModel, I've got just the use-case to exercise it and I'll let you all know how it goes
Tony Baines
Greenhorn

Joined: Aug 11, 2003
Posts: 15
Success! A non-problem after all, but it's improved my understanding, and cleaned up our implementation.
Thanks to all who responded, and especially to Frank.
Frank Carver
Sheriff

Joined: Jan 07, 1999
Posts: 6920
Cool. Glad to help.
 
Consider Paul's rocket mass heater.
 
subject: Front Controller and Commands