Sure, Raghuram.

Caution: long post!

It seems every project I've ever seen has an actor called "vendor", so I'll use that as an example. ;)

Typically these use cases are required:

Add a new vendor account to the system
Remove an existing vendor account from the system
Edit an existing vendor's account details
Find a vendor account using a unique ID
Find a vendor account using some combination of criteria other than unique ID
Retrieve all account details for a vendor


In other words, for each actor, you have the typical 'CRUD' use cases, where 'R' might be complex enough to require several of its own sub-use cases (different ways of viewing, searching).

So, translated to URI tokens that make some sense to an end user:

add
delete
edit
search
view

Now let's make them specific to the actor at hand, and make them into full-fledged "action" or "command" URIs (Note: I use path mapping, not extension mapping. Extension mapping changes this whole discussion.)

/vendor/add
/vendor/delete
/vendor/edit
/vendor/search
/vendor/view

But wait, if you've done this before, you know there (typically) are actually two "commands" associated with each use case. If someone wants to add a new vendor to the system, first he must visit some "add" screen, which might contain not much more than a blank form. Then after he submits the form, the application must process his input, and he must visit some "result" screen, that lets him know whether his data made it into the system as a permanent record (this result screen might actually be the equivalent of another "view" action with the data processing and feedback sort of "piggybacking" on the navigation; for example, /viewadd --> submit, process, /viewdetails -- but any way you look at it, it's normally two HTTP requests to get it all done). You can refer to these as "setup" and "execute" actions, respectively. So now we have:

/vendor/viewadd (show the blank form)
/vendor/executeadd (process the completed form)
/vendor/viewsearch
/vendor/executesearch
. . .

You might think at this point that the perfect pattern is not going to hold up. For example, to "view" details of a vendor account, you only need one action, not two. But it depends on how you look at it. If you have a "search" screen, or even a simple list of all vendors, you sort of have your "/viewview", if you will. Once a single vendor is selected, you have your "/executeview". Also, you might not think of separate /viewdelete and /executedelete actions. Rather, you might think only of /executedelete. But, if you have a "confirm" screen (even if it's just a JavaScript popup that says, "Are you sure you want to delete?"), you could think of that as /viewdelete -- so the pattern can hold up if you squint a little. Also you should remember, to hell with the pattern if it doesn't suit you.

So you can literally organize your JSPs this way, according to actor:

web/vendor/add_or_update.jsp
web/vendor/view_details.jsp
web/someOtherActor/add_or_update.jsp

. . . and so on. Notice the shared page for add and edit (aka "update"). Typically the form is the same, or close to the same, for each of the two usecases. So why not parameterize that form and reuse it, if you can? Rick Reumann's site ( www.*reumann*.net/do/struts/main ) might be of some help on this topic. I know that some of his posts to this list will. In your controller configuration, both /vendor/viewadd and /vendor/viewedit would map to the same JSP (add_or_update.jsp).

So now we have the trailing end of our action URIs, but we still need the leading end. That part consists of the application context path (if any), and the controller Servlet path (if any). I say "if any" because the default context and default Servlet mapping (both the equivalent of "/") might suffice. But I like to use an explicit controller Servlet path, such as "/services", because it allows me to delegate other Servlets to "controlling" other things besides the services proper -- such as the dispensing of images (again, if you use extension mapping, you might never have had to consider this).

So if your controller is mapped to "/services*" or "/services/*", then action URIs that you want to route through the controller Servlet look like this:

<app context>/services/vendor/viewadd

And other URIs (that won't be routed to the controller, might be routed to another Servlet or might just be served directly) might look like this:

<app context>/images/vendor/rainy_day.gif.

I always liked that song by Oscar the Grouch, "Let a Frown Be Your Umbrella (on a rainy, rainy day . . . )". Remember how, on the old Mac OS, Oscar lived in the desktop garbage can?

Finally, restricting access to *.jsp in your web-resource-collection element of web.xml can force your users to use the controller Servlet-relative action URIs and prevent them from accessing JSPs directly.

Also, I solved the problem that led to this post by putting an init-param in web.xml called "controllerPath". I set its value as an application scope attribute in a plug-in class. Now I can create controller-relative hyperlinks like this, using the JSTL-like tags:

<html:link page="${controllerPath}/vendor/home">home</html:link>

If someone wants to use extension mapping, I just set controllerPath to be the empty String.

Now, what I want to know is, what flies out the window when I decide to learn JSF? I'm afraid to look. ;) By the time I learn JSF, someone will have developed a "CRUD IDE" that builds your entire app in five minutes, based on actor names and a CSS stylesheet. In a few years, we will have highly-paid "stack trace" experts. The average "corporate developer" will see a stack trace and run for the hills, having always thought they were a myth. The manager will have to call in a stack trace expert, who will, at the rate of $700 per hour, begin to explain to all the remaining developers what a "stack" is . . .

But seriously, hope this helps a newbie or two. Criticism is always welcome!

Erik






Raghuram Kanadam wrote:

If you had the time Erik would you explain your method of arranging JSPs by the actor, seemed a beautiful approach.

-----Original Message-----
From: Erik Weber [mailto:[EMAIL PROTECTED]
Sent: Thursday, July 22, 2004 1:16 AM
To: Struts Users Mailing List
Subject: Re: Tag question


Sorry if this post repeats -- I find that occasionally they are not making it . . .




Jim, "actor" is precisely what I meant!

It goes /context/controller/actor/usecase (in my case)

Sorry I didn't say that correctly.

But as you point out, I think it doesn't change the point of
the post, that I need to manually make sure the name of the controller
servlet gets into the hyperlinks.

I wonder if a mapping of "/services" work better than "/services/*". Haven't tried that . . .

Thanks,
Erik



Jim Barrows wrote:







-----Original Message-----
From: Erik Weber [mailto:[EMAIL PROTECTED]
Sent: Wednesday, July 21, 2004 11:32 AM
To: Struts Users Mailing List
Subject: Re: Tag question


Sorry, I should have explained better what I am doing.

My controller Servlet is mapped to /services/*

All requests for JSP pages go through the controller, via action mappings. The actions have paths like:

/usecase/view_edit_page
/usecase/save_existing_record
/usecase/view_add_page
/usecase/add_new_record

So the full links look like:

<context>/services/usecase/view_edit_page

meanhwhile other resources have paths like:

<context>/images/some_image.gif

This keeps other resources out of the scope of the controller (and perhaps into the scope of some other servlet). Also, direct JSP access is prohibited.

So in places where I am building hyperlinks (within JSPs), I need to get "/services" into each link, in front of the action URI, but behind the context. And I want to do this in a portable way (in case the Servlet mapping changes).




If you use html:link and forwards then you can do whatever you want, and won't have to 
change the links themselves.  This would be pretty portable as well.





So the idea is to put something like <html:rewrite page="${controller_path}<action_URI_here>"> which literally would be "/services" + "/usecase/action" or "/services/usecase/action". Using the "page" attribute to the tag makes it come out right ("/context/services/usecase/action").

(When I say "usecase" here I really should say "collection of usecases" or "function group" to be more accurate).

I would be interested in hearing other mapping strategies.



I map jsp and directories by actor rather then use case, or use case package.  Makes 
everything easier (especially declaritive security, then again I've kept the *.do 
mapping, rather then what you're doing.
That would make your url something like services/actor/useCase, which doesn't get 
around your problem.





For now I'm making sure the JSP can call a method or access a variable that returns "/services".

Erik



Christian D Hahn wrote:





Are you mapping the jsp to /services in the web.xml? if you do, getServletPath should return the path you are looking for.

<servlet>
<servlet-name>jsp</servlet-name>
<jsp-file>/usecase/page.jsp</jsp-file>
</servlet>

<servlet-mapping>
<servlet-name>jsp</servlet-name>
<url-pattern>/services</url-pattern>
</servlet-mapping>

-Chris

Erik Weber wrote:





Hmm I must be doing something wrong. That's giving me the



same value



as Erez's example. Strange, I would have expected it to give me "/services". I wonder how I am causing it to give me "/usecase/page.jsp".

atta-ur rehman wrote:





Hi Erik,

This one worked for me:

<c:set var="v">
<%= request.getServletPath() %>
</c:set>

<c:out value="${v}"/>
<bean:write name="v"/>

HTH,

ATTA

On Tue, 20 Jul 2004 16:20:30 -0400, Erik Weber <[EMAIL PROTECTED]> wrote:






How can I set a variable (I assume with c:set) that will



hold the



value
of request.getServletPath, so that I can use it in el tags?

Thanks,
Erik






---------------------------------------------------------------------




To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]










---------------------------------------------------------------------




To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]












---------------------------------------------------------------------




To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]









---------------------------------------------------------------------




To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]






---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]






---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]








---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]


--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]





--------------------------------------------------------------------- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED]



Reply via email to