This week's book giveaway is in the OCPJP forum. We're giving away four copies of OCA/OCP Java SE 7 Programmer I & II Study Guide and have Kathy Sierra & Bert Bates on-line! See this thread for details.
I've got a project using FrontMan, and most of it works just fine. I issue a command, the command is dispatched to a bean with @FrontmanCommand("step3")
which then uses a JSP view to show the form, etc. But for a trivial JSP, I'm getting the error:
The requested resource () is not available.
There is no error in the logs, in fact the logs show success
So the target exists, is found, yet it can't be shown, and the browser reports a rather useless error message
The dumb question that I gotta ask: does /WEB-INF/pages/tada.jsp exist?
Front Man reports that that's what the view path resolves to, but that doesn't mean that it knows that it actually exists. That's where Front Man thinks that it should exist based uppn what you've told it.
And, how are you transitioning from the action to the view? A forwardToView I am assuming?
Ah! There's the issue. You can't redirect to anything behind WEB-INF. A forward will take place completely on the server, forwarding the current request from the command to the view. This is the most common thing to do as it retains all the context of the request from the command to the view, most usefully, any scoped variables that are tacked onto the request by the command.
A redirect, on the other hand, sends the response back to the browser with instructions to cause a new request to the redirected URL. All context from the previous request is lost. In this case it is to a resource behind WEB-INF, which containers are forbidden to serve directly as a result of a URL.
Interesting note, when the browser shows the error, it displays the raw file path, rather than the context specific one:
Exactly. That is because the browser has issued a new request for the view, rather than getting the response from the command.
99.9999% of the time you want to forward to a view from its controller command.
Where I use redirect most is to utilize the PRG pattern, and redirect from a task command to the view controller/command for the view to be displayed (where a forward is used between the command and its view).
Man, I think I had this same bug a month ago. I gotta start learning....
Bear Bibeault wrote: Where I use redirect most is to utilize the PRG pattern, and redirect from a task command to the view controller/command for the view to be displayed (where a forward is used between the command and its view).
Imagine that you have a command that deletes a resource named /command/deleteXyz. When it is activated it calls the model classes necessary to delete an Xyz resource given an id (passed as a request param). Afterwards it forwards to a page that shows the message "Success! Go have a lovely beverage!"
Well, the URL sitting on the browser is still the delete command. if you hit refresh, it will invoke the command again. The model process will fail because the Xyz to be deleted doesn't exist anymore.
Under PRG this is avoided. Using PRG the scenario goes like this:
The delete URL is issued and activates the deleteXyz command.
The command delegates the delete process to the model as before. This task is known as a "task command" because its purpose is to perform some task.
A task command rarely forwards to a view -- that not only introduces the refresh issue, it also closely couples the task to a particular view, whereas there may be many paths to the same view. Rather...
The task command redirects to the page controller for the view it wants to present. A page controller is a command whose only pupose is to prepare the request for the page to be displayed. That way, it can be invoked from anywhere or any other task command.
The page controller forwards to the view after doing anything that the page needs in order to display (for example, fetching dynamic values to be displayed in a dropdown, etc)
That way, when refresh is hit, only the page controller and its view are executed. The delete command is part of a bygone request and will not be re-executed.
Your server-side code should always protect against some script-kiddie modifying values. But one approach is to not show client-visible values at all. Session scope keeps things on the server with no chance for substitution, but can be kinda messy to maintain. (Of course, session hijacking itself is a possibility unless you are running under SSL, which you should be if security is a concern.)
I usually just make sure that there are adequate checks in place so that any client-side shenanigans result in a stern message rather than unintended access.
Bear Bibeault wrote:Your server-side code should always protect against some script-kiddie modifying values. But one approach is to not show client-visible values at all.
I don't see how to do that if I have a simple "showview" command so I can implement the model/pattern. I need to be able to specify "what" view to show. And using a query string is bad for the reasons we know.
SSL does nothing if the user can simply change the URL/URI string, query paramters, etc. TLS is all about secure transmission from one trusted computer to another. I don't trust the user.
Pat Farrell wrote:Well, I may just not understand how you implement this. Do you use unique URLs for each view?
The idea of having twice as many "commands" is not appealing to me, at least at first look. Twice as many things to change when the PHB wants different sequences, etc.
Twice as many as what? And what needs changing?
Essentially I have a command URL for each thing that can occur in a web app. Some of those things are tasks: doThis, deleteThat, computeTheOtherThing. Some are to view things: viewThis, viewSomethingElse, viewSomeOtherThing. The former are "task commands" that are generally POSTed to, and the redirect (a la PRG) to a "view command" (aka "controller") to show a view.
Now, many views may not need a controller. Only the views that need some sort of action to take place before they can be displayed need a controller. For example, a form to edit an item. The values of the item need to be fetched from the DB in order for the view to pre-fill the form fields. But a login box may not need any prep.
For the views that need prep, a single entry point makes no sense as each will have their own needs. But for views that don't need a controller, I added a ViewBroker in Front Man 1.6 so that you can access views directly via URL without the need for a controller.
But yes, each view and each command have a unique URL.
Bear Bibeault wrote:Twice as many as what? And what needs changing?
Twice as many URLs as functional actions.
Assume you have Fee, Fie, Foe, and Fum commands.
Easy to setup FrontMan to have four beans, one for each. But if you want the PRG, you have the four "action" commands (beans) and four views (JSPs).
So you do Fee, it does its thing, and does a forwardToView for feeView.jsp. Same for all the rest. But this is not PRG, because if the user does a "refresh" on the view, it triggers the action command again.
To properly implement PRG, you need yet another layer that just displays the view. With it, you can refresh all you want and it just shows the view. So there are now two parts to the Fie command, the first part that does the actual Fie, and then a Fie-View, which has to be dispatched with a separate URL.. So for four commands, we have eight, or maybe 12 implementation parts. The parts are a lot alike, but there are still a lot of them.
The PHB is a Dilbertism, Pointy Haired Boss. Every project has one, its the PHB that changes stuff. They never change it before you write the code, they always change it just after you make it work. So any good system, one you won't hate after nine months, has to be immune to PHB changes. Or at least, easy to change when the PHB demand.
I had no problem building a simple test application in Stripes, and I've had no problem with FrontMan. But the point is not to learn how to build a simple application, its to build one that has lots of screens, commands, views, etc. So I'm hesitant to get excited about doubling the number of "things" that I have, even if they are simple.
You seem to be tying task commands to views, and that's not the way I envision things.
I see anything you can display as a "view", and each such view can be composed of either one or two parts: a JSP page, and an optional controller as necessary. Despite the fact that there may be two components, I see these as a single "thing" (a view) in a web app.
Decoupled from these are "task commands" that do something. These are usually what are submitted to by forms within the views. Each task command can redirect to any view (or view/controller pair) that it likes when it's done.
The view couplets and the task commands are completely decoupled and independent.
I've found this eliminates a lot of tearing out of hair that I already do not have.
And, I find that the loose coupling is an effective tool to deal with the PHB's because the decoupling makes things more flexible.