You are viewing a plain text version of this content. The canonical link for it is here.
Posted to user@struts.apache.org by Erik Weber <er...@mindspring.com> on 2004/07/22 20:43:01 UTC

Re: Tag question (JSP organization)

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:erikweber@mindspring.com]
>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:erikweber@mindspring.com]
>>>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 
>>>>>><er...@mindspring.com> 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: user-unsubscribe@struts.apache.org
>>>>>>>For additional commands, e-mail: user-help@struts.apache.org
>>>>>>>
>>>>>>>
>>>>>>>           
>>>>>>>
>>>>>>>              
>>>>>>>
>>>>>>         
>>>>>>
>>>>>>            
>>>>>>
>>>---------------------------------------------------------------------
>>>   
>>>
>>>      
>>>
>>>>>>To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
>>>>>>For additional commands, e-mail: user-help@struts.apache.org
>>>>>>
>>>>>>
>>>>>>
>>>>>>
>>>>>>         
>>>>>>
>>>>>>            
>>>>>>
>>>>>       
>>>>>
>>>>>          
>>>>>
>>>---------------------------------------------------------------------
>>>   
>>>
>>>      
>>>
>>>>>To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
>>>>>For additional commands, e-mail: user-help@struts.apache.org
>>>>>
>>>>>       
>>>>>
>>>>>          
>>>>>
>>>>     
>>>>
>>>>        
>>>>
>>>---------------------------------------------------------------------
>>>   
>>>
>>>      
>>>
>>>>To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
>>>>For additional commands, e-mail: user-help@struts.apache.org
>>>>
>>>>
>>>>     
>>>>
>>>>        
>>>>
>>>---------------------------------------------------------------------
>>>To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
>>>For additional commands, e-mail: user-help@struts.apache.org
>>>
>>>
>>>   
>>>
>>>      
>>>
>>---------------------------------------------------------------------
>>To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
>>For additional commands, e-mail: user-help@struts.apache.org
>>
>>
>> 
>>
>>    
>>
>
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
>For additional commands, e-mail: user-help@struts.apache.org
>
>
>---------------------------------------------------------------------
>To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
>For additional commands, e-mail: user-help@struts.apache.org
>
>
>  
>

---------------------------------------------------------------------
To unsubscribe, e-mail: user-unsubscribe@struts.apache.org
For additional commands, e-mail: user-help@struts.apache.org