I've been following this thread and solicited you opinions individually.
I thought I might throw out some ideas.  

We have developed a struts plug-in that we called rustts (see
attachment).  It has properties of a page controller and view
controller.  

We implemented the page controller as a subclass of the DispatchAction
class.  It combines principles of the DispatchAction and
LookupDispatchAction.  This controller handles the creation of various
types of model classes that are associated with visual components thru
our struts extension XML file.  

The visual components are defined through xml entries which support
metadata inheritance, much like tiles. Each visual component can be
associated with a model class that controls visual aspects such as if
the visual element should be displayed.  The composition of visual
components on a page is defined in the extension XML file.  The page XML
element, being the outermost visual element, is associated with the
struts action using a custom attribute in a subclass of ActionMapping.

We have created view helpers that we use within JSP fragments that are
pulled together using tiles.  These view helpers use the metadata and
the associated modules to render the view.  Currently the helpers make
heavy use of scriptlet.  Eventually we could build custom tags that use
the helpers to render the page but we like the ability to quickly change
the skin of a visual element.  For example we have a vertical menu and
horizontal menu that use the same helper to render a different
presentation.  These view helpers could also be used by velocity to
render a presentation.

We have extended the ActionMapping and ActionForward classes to simplify
propagation of properties in the form bean to the target page.

<action path="/docInfoCategoryEdit" name="DocInfoCategoryForm"
                validate="true" input=".dynaPage" scope="request"
                parameter="cmd"
type="com.rustts.action.RusttsDispatchAction"
className="com.rustts.action.RusttsActionMapping">
                
        <set-property property="pageId"
value="docInfoCategoryEditPage"/>
                                                               
        <forward name="quit" path="/Welcome.do" redirect="true"
                className="com.rustts.action.RusttsForwardAction">
                   
                <set-property property="arg6" value="dcDivision" />
        </forward>
        
        <!-- next button -->
      <forward name="save-success" path="/docInfoType.do"
redirect="false"
                className="com.rustts.action.RusttsForwardAction">
                
                   <set-property property="arg1" value="drId" />
                   <set-property property="arg2" value="dcCode" />
                   <set-property property="arg3" value="drName" />
                   <set-property property="arg4" value="drComment" />
                   <set-property property="arg5" value="drOrigIndic" />
                   <set-property property="arg6" value="dcDivision" />
        </forward>

      <!-- validate button -->
      <forward name="add-success" path="/docInfoCategoryValidate.do" 
                        redirect="false" 
        
className="com.rustts.action.RusttsForwardAction">

                   <set-property property="arg1" value="drId" />
                   <set-property property="arg6" value="dcDivision" />
                </forward>
</action>
 
Each model has a public interface that provides callback methods that
can be implemented to conditionally effect different aspects about a
page or how a visual component behaves within a page.

We have extended the TilesRequestProcessor to cache the metadata loaded
by our plugin in request scope making it available to other resources.


Our extension sits on top of struts and is really where we came up with
the name "rustts".  Besides being an anagram of Struts, our vision was
that rust is a natural byproduct of metal structures of impressive
stature, and that often rust is most visible where the struts are
joined.


Regards,
   Gary


-----Original Message-----
From: Ted Husted [mailto:[EMAIL PROTECTED] 
Sent: Sunday, September 28, 2003 8:13 PM
To: Struts Developers List
Subject: Re: Reviving PageController (ViewController?) discussion?

Here's a third idea:

Instead of creating a new class, we could just associate an Action class

with the ActionForward. This is what people do now anyway. It seems to 
work, but wastes an ActionMapping and trip through the container.

So, we just add a "type" property to ActionForward, and a step to the 
RequestProcessor to handle it when available. If it's there, it gets 
called, and the RequestProcess forward to the path. If it's not there, 
the RP forwards to the path given by the original forward. Everything 
else remains the same.

I'm sure some people will misuse the feature, but some people will 
always misuse any feature. At least this way, we recognize what most 
people (including me) already do most of the time, put an Action in 
front of page. The advantage being that we don't have to waste an 
ActionMapping or a trip through the container just to forward to the
page.

-Ted.

Joe Germuska wrote:
> I've been thinking about this a bit; as I see it now, some 
> implementation choices might be a little contentious, so I feel like
the 
> right approach is discuss first, code later.
> 
> Below is my interpretation of the interface based on earlier
discussion 
> and such.  Note that I suggest we change the name from
"PageController" 
> to "ViewController", although I don't feel very strongly about it.
It's 
> just one method (plus some javadoc to flesh out the idea.)
> 
> package org.apache.struts.action;
> 
> public interface ViewController {
> 
>     /**
>      * <p>Perform any view-level preparations after an [EMAIL PROTECTED] Action} 
> has executed
>      * and before the display is rendered.  Return a [EMAIL PROTECTED]
ForwardConfig}
>      * instance describing where and how control should be forwarded,
or
>      * <code>null</code> if the response has already been
completed.</p>
>      *
>      * <p>In the simplest case, where an implementation only modifies
the
>      * request context, the return value may be the same as the 
> <code>ForwardConfig</code>
>      * provided as an argument.  However, note that implementations 
> should not
>      * directly modify the given ForwardConfig if it is not the
appropriate
>      * return value; they must instead return a new instance
>      * (or an implementation-level cached instance).</p>
>      *
>      * @param forward The ForwardConfig in whose context this
controller is
>      * being invoked.
>      * @param request The HTTP request we are processing
>      * @param response The HTTP response we are creating
>      * @return a ForwardConfig which will be used for final view
dispatch,
>      * or null if the response has already been completed
>      * @exception Exception if the view preparation process throws
>      *  an exception
>      */
>     public ForwardConfig prepareView(
>         ForwardConfig forward,
>         HttpServletRequest request,
>         HttpServletResponse response)
>         throws Exception;
> 
> I think it's important (as noted in the JavaDoc) to help people 
> understand that they can't change a "frozen" ForwardConfig.  (I kind
of 
> feel like this belongs more in something like o.a.s.view, but if it's 
> going to be the only class there...)
> 
> At 10:31 -0400 9/15/03, Ted Husted wrote:
> 
>> I'll post more on this later, but to avoid the "gotcha", I'm now 
>> thinking we should try this using a modified
ActionMapping.findForward 
>> method. In that way, all the navigational control stays within the 
>> Action.
> 
> 
> The part that seems like it might raise some discussion is about who 
> manages the ViewControllers.  It seems wasteful to instantiate one
each 
> time a view is dispatched.  So then does the base ActionMapping cache 
> ViewControllers?  If that's the case, then what about Module-level 
> "global forwards"?  You could make a simple support class that wrapped

> up the instantiation and caching and have it available to
ActionMapping 
> and implementations of ModuleConfig -- and just to note, the fact that

> ModuleConfig is an interface leaves open the risk that existing 
> implementations wouldn't implement the new, more complex contract of 
> "findForwardConfig".
> 
> I guess I'm waiting to hear more on Ted's teaser; I'm not sure I see
the 
> gotcha that makes hiding this behavior in ActionMapping better than 
> making it the responsibility of the RequestProcessor, which seems like
a 
> clearer place to put a single cache of ViewController classes -- which

> seems to be how Tiles works.
> 
> If people want to weigh in on this, I'll distill the discussion into 
> draft code once we think the path is clear.
> 
> Joe
> 

-- 
Ted Husted,
   Junit in Action  - <http://www.manning.com/massol/>,
   Struts in Action - <http://husted.com/struts/book.html>,
   JSP Site Design  -
<http://www.amazon.com/exec/obidos/ISBN=1861005512>.

"Get Ready, We're Moving Out!!" - <http://www.clark04.com>



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

<!--
	A "Boolean" represents the result of a binary expression represented
	as a true or false value
-->
<!ENTITY % Boolean "(true|false)">
<!--
	A "ButtonMethod" represents the method name that will be invoked on the page
	model when a page is submitted to an action.
-->
<!ENTITY % ButtonMethod "(add|save|delete|quit|other1|other2)">
<!--
	A "button" represents a submit button in a page form.  The "page" element aggregates 
	up to six buttons defined by the "ButtonMethod".
	
	method		The type of button
	Visible		Is the button visible on the page.  
	MessageKey	the message key in the properties file that defines the label on the buton
	Validate	If the value is true, the action forms validate method will be invoked if 
				defined (assuming the action validate is also true).  If the value is false, 
				the button is determined to be a struts cancel button and the action forms 
				validate method is not invoked.  A button representing a Quit or Delete action 
				would not require form validation.
	Roles		A comma delimited list of security roles that the user must have in order to perform 
				this action.  If the user is not a member of the role(s) the button will not be visible.
-->

<!ELEMENT button (#PCDATA)>
<!ATTLIST button    
    method %ButtonMethod; #REQUIRED
	visible %Boolean; #IMPLIED
	messageKey CDATA #IMPLIED
	validate %Boolean; #IMPLIED
	roles CDATA #IMPLIED
>
<!--
	An "Align" represents the horizontal positioning of a column in the a resultset
-->
<!ENTITY % Align "(left|right|center)">
<!--
	The "struts-extension" is the root node of the document
-->
<!ELEMENT struts-extension (resultset-definition?, menu-definition?, page-definition?, field-format-pattern-definition?, display-element-definition?, list-element-definition?)>
<!--
	A "field-format-pattern-definition" is the container hoding zero or more
	"field-format-patterns"
-->
<!ELEMENT field-format-pattern-definition (field-format-pattern*)>
<!--
	A "field-format-pattern" represents a common format pattern that should be applied
	to a property when converted from a strong type to a string literal or from a string 
	literal to a strong type.  For example, suppose a fiscal ending period (fyEndDt) was
	always displayed in the format of MM/dd.

	properyName	The value of this attribute should correspond to an object property.
	pattern		The format pattern that corresponds to the Format class designed
				for each datatype.

				 	java.text.DecimalFormat;
                    java.text.MessageFormat;
                    java.text.SimpleDateFormat;
-->
<!ELEMENT field-format-pattern (#PCDATA)>
<!ATTLIST field-format-pattern
	propertyName CDATA #REQUIRED
	pattern CDATA #IMPLIED
>
<!--
	A "page-definition" is a container node holding zero or more pages
-->
<!ELEMENT page-definition (page*)>
<!--
	A "page" element will correspond to a struts action.  A set-property tag in the
	action, will associating with the pageId in the page node.  
	
	A page can contain up to six buttons defined by ButtonMethod.  The buttons inherit 
	characteristics of buttons defined is extended pages.
      
	&lt;action&gt;
		&lt;set-property property="rsetId" value="personrs"/&gt;
	&lt;/action&gt;
      
	pageId			Unique identifier for a page
	extends			The pageId that this page will inherit attributes, menu-items and resultset-items from
	titleKey		The message resource key used to find the localized page title text
	subtitleKey		The message resource key of the context description of the page
	descriptionKey	The message key used to pull text from the resource file describing the page
	modelClassname	The fully qualified class name of the model that will handle the pageā€™s business logic
	transaction		This flag indicates if the page will participate in a transaction.  If the 
					value is "true", a synchronization token will be encoded in page links and 
					the form to ensure that a dirty/cached page is not in use.
	focus			This will identify the name of the form field that will initially obtain the focus.
	
-->
<!ELEMENT page (button*, menu-item*, resultset-item*, display-element-item*, list-element-item*)>
<!ATTLIST page
	pageId CDATA #REQUIRED
	extends CDATA #IMPLIED
	titleKey CDATA #IMPLIED
	subtitleKey CDATA #IMPLIED
	descriptionKey CDATA #IMPLIED
	modelClassname CDATA #IMPLIED
	transaction  %Boolean; #IMPLIED
	focus CDATA #IMPLIED
> 
<!--
	The "resultset-definition" node is a container holding zero or more "resultset" nodes
-->
<!ELEMENT resultset-definition (resultset*)>
<!--
	A "resultset" defines a table of rows and columns.  One or more resultset can be associated
	with a page and a resultset can be associated with many pages.

	rsetId			Unique identifier for a resultset
	messageKey		The message key used to form the caption of the resultset
	modelClassname	The fully qualified java class name of the model that supplies the resultset view
					helper with the data source (List of simple beans) and validation logic to
					conditionally turn off or on a column link.  An instance of this class will be
					dynamically loaded by the action class.
	rowsPerPage		The override/default rows per page that the resultet view helper should render
					for a page.
	checkboxHeaderKey		This is a key into the application properties for the text of the column header fir
							the checkbox column
	noBoxesCheckedKey		This is a key into the properties for when no checkboxes are checked but some are
							expected to be
	truncatedKey			The message key used to display a truncated message in the event all rows could not be delivered
	numBoxesProcessedKey	The message key that will report on the number of boxes processed 						
    defaultIsSortedAscending The default sort order of the default column 
 	defaultSortByColumn   	 The default column the resultset should first ordered by
	extends			A parent rsetId the current resultset inherits attributes from
-->
<!ELEMENT resultset (column*)>
<!ATTLIST resultset
	rsetId CDATA #REQUIRED
	messageKey CDATA #IMPLIED
	modelClassname CDATA #IMPLIED
	rowsPerPage CDATA #IMPLIED
	checkboxHeaderKey CDATA #IMPLIED
	noBoxesCheckedKey CDATA #IMPLIED
	numBoxesProcessedKey CDATA #IMPLIED
	truncatedKey CDATA #IMPLIED	
	defaultIsSortedAscending %Boolean; #IMPLIED
	defaultSortByColumn CDATA #IMPLIED
	extends CDATA #IMPLIED
>
<!--
	The "column" element represents a single cell of data.  It's visual context is supplied from a single
	property in a simple java bean.  The row of the table is mapped to properties on the bean. Each column
	can become a navigational point to another uri.
	
	sequence		A numeric sequential identifier used to order the cell from left to right in a table row
	propertyName	The object attribute name "getter method" of the data source of the column content.	
	messageKey		The message resource key used to find the column header description
	length			The maximum width in characters a column should be.  
					The column value will wrap at a word boundary if one can be found.
	isSortable		A boolean flag indicating the column should allow for sorting.
	isLinkable		An indicator that the column should become a link to another page.
	align			The horizontal alignment of a cell value.
	sortByColumns	This is a value list of property names that will be used to sort a resultset.  If this attribute 
	                (sortByColumns) is not specified in the XML column node, the propertyName will be assumed.  
	                The value list can include property names in the mapped value object that are not defined in the resultset.
-->
<!ELEMENT column (link?)>
<!ATTLIST column
	sequence CDATA #REQUIRED
	propertyName CDATA #REQUIRED
	messageKey CDATA #IMPLIED
	length CDATA #IMPLIED
	isSortable %Boolean; #REQUIRED
	isLinkable %Boolean; #REQUIRED
	align %Align; #REQUIRED
	sortByColumns CDATA #IMPLIED
>
<!--
	A "menu-definition" is a container for zero or more menu elements.
-->
<!ELEMENT menu-definition (menu*)>
<!--
	A "menu" is a group qualifier for a series of page links. A page can be associated
	with one or more menus and one menu can be associated with many pages.

	menuId			Unique identifier for a menu.
	messageKey		The resource message key for the text description of link
	modelClassname	The fully qualified path of a java class that performs the
					conditional validation of links within the menu group.
	doubleSpace		A flag indicating whether or not to double space the menu links
	extends			a parent menuId the current menu inherits attributes from
-->
<!ELEMENT menu (link*)>
<!ATTLIST menu
	menuId CDATA #REQUIRED
	messageKey CDATA #REQUIRED
	modelClassname CDATA #IMPLIED
	doubleSpace %Boolean; #IMPLIED
	extends CDATA #IMPLIED
>
<!--
	A "menu-item" ties a menu to a page.

	menuId		unique menu identifier
	key			arbitrary identifier used by the view to identify a menu as it is associated
				with a page.
-->
<!ELEMENT menu-item (#PCDATA)>
<!ATTLIST menu-item
	key CDATA #REQUIRED
	menuId CDATA #REQUIRED
	sequence CDATA #IMPLIED
>
<!--
	A "resultset-item" ties a resultset to a page.

	rsetId		unique resultset identifier
	key			arbitrary identifier used by the view to identify a resultset as it is
				associated with a page.
-->
<!ELEMENT resultset-item (#PCDATA)>
<!ATTLIST resultset-item
	key CDATA #REQUIRED
	rsetId CDATA #REQUIRED
>

<!--
	The "list-element-id" ties a list-element to a page.
   
	key				identifier used by the view to identify a list-element entry
	listElementId	unique list-element identifier		
-->
<!ELEMENT list-element-item (#PCDATA)>
<!ATTLIST list-element-item
	key CDATA #REQUIRED
	listElementId CDATA #REQUIRED
>
	
	 
<!--
	A "link" is a navigational point owned by a column or a menu.  A link can define
	arguments that should be used to compute the query parameter of the url.

	sequence	numeric value used to order links, only applies to menu's
	messageKey	the message resource key used to build the text description of the link
	path		the uri or url of the target location
	isExternal	indicates if the location is external to the web application (uri or url)
	roles		if specified, the user must be authorized to these roles to see this link.
				Multiple roles are delimited using a comma (role1, role2)
-->
<!ELEMENT link (arg*)>
<!ATTLIST link
	sequence CDATA #IMPLIED
	messageKey CDATA #IMPLIED
	path CDATA #REQUIRED
	isExternal %Boolean; #IMPLIED
	roles CDATA #IMPLIED

>


<!--
	The value of an "arg" is a object propery name "getter method" of a simple bean
	attribute that should be encoded as an argument within the query parameter of the
	target uri.
	
		propertyName	The name of the property within the formbean or value object 
		roleName		An optional argument name override
-->
<!ELEMENT arg (#PCDATA)>
<!ATTLIST arg
	propertyName CDATA #REQUIRED
	roleName CDATA #IMPLIED
>

<!--
	A "display-element-item" ties a resultset to a page.

	displayElementId		unique resultset identifier
	key			arbitrary identifier used by the view to identify a displayElement as it is
				associated with a page.
-->
<!ELEMENT display-element-item (#PCDATA)>
<!ATTLIST display-element-item
	key CDATA #REQUIRED
	displayElementId CDATA #REQUIRED
>
<!ELEMENT display-element-definition (display-element*)>

<!ELEMENT display-element (attribute*, set-property*)>
<!ATTLIST display-element
	displayElementId CDATA #REQUIRED
	jspName CDATA #IMPLIED
	extends CDATA #IMPLIED
	modelClassname CDATA #IMPLIED
	roles CDATA #IMPLIED
>

<!ELEMENT set-property (#PCDATA)>
<!ATTLIST set-property
	name CDATA #REQUIRED
	value CDATA #REQUIRED
>

<!ELEMENT attribute (set-property*)>
<!ATTLIST attribute
	attName CDATA #IMPLIED
	displayName CDATA #IMPLIED
	displayElementId CDATA #REQUIRED
	requiredField %Boolean; #IMPLIED
	sequence CDATA #REQUIRED
	roles CDATA #IMPLIED
>
<!-- 
	Container holding list-element entries
--> 
<!ELEMENT list-element-definition (list-element*)>
<!--
	The list element is a cached collection of values used by the view 
	to populate an option list.  The list is cached using lazy retrieval.  
	The first time a list is retrieved, it is cached in application scope 
	within the web container.  Subsequent access to the same list will 
	utilize the cached list.
	
	listElementId		unique list identifier
	labelProperty		The object property name that will be used populate 
						the text description of an option tag within the homogeneous 
						collection.
	valueProperty		The object property name used to populate the value attribute of a 
						HTML option tag
	filterClassname		The fully qualified class path to a class implementing the IFilter
						interface.
	includeBlankElement	A flag indicating whether or not to include a blank element at the top of the list
	DAOClassname		The fully qualified class path to the data access object that 
						will retrieve a homogeneous collection of value objects.  The 
						DAO class must implement the IDomain interface.  
	sortByColumns		A comma delimited value list of property names within the value 
	                    object that list should be sorted on after the filter is applied. 
	                    This is similar to the column sortByColumns attribute. 
-->
<!ELEMENT list-element (set-property*)>
<!ATTLIST list-element
	listElementId CDATA #REQUIRED
	labelProperty CDATA #REQUIRED
	valueProperty CDATA #REQUIRED
	filterClassname CDATA #IMPLIED
	includeBlankElement %Boolean; #IMPLIED
	DAOClassname CDATA #REQUIRED
	sortByColumns CDATA #IMPLIED
>


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

Reply via email to