[ 
https://issues.apache.org/struts/browse/WW-1330?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#action_39706
 ] 

Frank W. Zammetti commented on WW-1330:
---------------------------------------

I just attached the sample app file, since I realized it was no longer on my 
server at the URL referenced in the first comment.

> SAF2 Automatic Ajax Support
> ---------------------------
>
>                 Key: WW-1330
>                 URL: https://issues.apache.org/struts/browse/WW-1330
>             Project: Struts 2
>          Issue Type: New Feature
>          Components: Actions, Interceptors, Misc
>    Affects Versions: WW 2.2.2, 2.0.0
>         Environment: Any
>            Reporter: Frank W. Zammetti
>             Fix For: 2.1.x
>
>         Attachments: code.zip, saf2_auto_ajax.zip
>
>
> Note: Full sample/test app, ready to try in the app server of your choice, 
> can be downloaded <a href="http://www.omnytex.com/saf2_auto_ajax.zip";>here 
> (http://www.omnytex.com/saf2_auto_ajax.zip)</a>
> Strictly speaking, this does not actually have anything specifically to do 
> with AJAX, but since that is likely to be the most common use case, that's 
> the name I went with.
> Two new Interceptors are introduced, both of which have the goal of 
> automatically populating the target Action from the incoming request's POST 
> body, either an XML message (AjaxXMLInterceptor) or a JSON message 
> (AjaxJSONInterceptor).
> In addition, two new Results are introduced, both of which have the goal of 
> automatically generating a response to the client in the form of an XML 
> message (AjaxXMLResult) or JSON message (AjaxJSONResult) whether the message 
> is automatically generated from the fields of the Action.
> Finally, two new marker interfaces are introduced, one to indicate that an 
> Action can be populated via the AjaxJSONInterceptor (AjaxJSONAware) and one 
> to indicate that the Action can be populated via the AjaxXMLInterceptor 
> (AjaxXMLAware).
> The Interceptors and Results can of course be mixed and matched, so you can 
> accept a JSON message, then generate XML to return to the client, or accept a 
> regular request and generate JSON, or accept XML and generate XML.
> Both of the Interceptors interrogate the incoming request's "content-type" 
> header to determine if it should do its work.  The AjaxXMLInterceptor looks 
> for the value "text/xml" and the AjaxJSONInterceptor looks for the value 
> "application/json".
> Incoming JSON
> -----------------------------------------------------
> An incoming JSON message to be used by the AjaxJSONInterceptor must be in the 
> form:
> { "aaa":"bbb", "ccc": [ "ddd", "eee" ], "fff": [ { "ggg":"hhh" } ] }
> For example:
> {
> "firstName" : "Frank", "children" : [ "Ashley", "Andrew" ], "certifications" 
> : [ { "microsoft" : "MCSD", "sun" : "SCJP" } ] }
> The message may not have any elements nested any deeper than that.  The array 
> section in this format with the elements "ddd" and "eee" can be used to 
> populate a List or an array.  The array section in this format with the 
> elements "ggg" and "hhh" will be used to populate a Map.
> Outgoing JSON
> -----------------------------------------------------
> An outgoing JSON message as generate by the AjaxJSONResult will be in 
> essentially the same format as above, except that there will be marker values 
> to indicate whether an array section came from a List or Map.  For example:
> {"physicalAttributes":{"map":{"height":"5.10","weight":"Too 
> much"}},"children":{"list":["Andrew","Ashley"]},"firstName":"Frank", 
> "certifications":["SCJP","MCSD"]}
> Incoming XML
> -----------------------------------------------------
> An incoming XML message to be used by the AjaxXMLInterceptor must be in the 
> form:
>   <scalarName>value</scalarName>
>   <listName>value</listName>
>   <listName>value</listName>
>   <mapName key="keyValue">value</mapName
>   <mapName key="keyValue">value</mapName
> For example:
> <person>
>   <firstName>Frank</firstName>
>   <children>Andrew</children>
>   <children>Ashley</children>
>   <certifications key="microsoft">MCSF</certifications>
>   <certifications key="sun">SCJP</certifications>
> </person>
> The message may not have elements nested any deeper than that.  So, you could 
> not for instance have:
> <children>
>   <child>Andrew</child>
>   <child>Ashley></child>
> </children>
> The presence of the "key" attribute on an element that would otherwise be 
> part of a list, as in the <children> elements for example, determines whether 
> the elements become part of a Map or not.
> Outgoing XML
> -----------------------------------------------------
> An outgoing XML message as generated by the AjaxXMLResult will be in the same 
> form as the above incoming XML example.
> Incoming Request Content-Type
> -----------------------------------------------------
> In order for either of the Interceptors to do their work, the incoming 
> request must have the appropriate "content-type" header set.  For JSON, that 
> value is "application/json", and for XML it's "text/xml".  If the 
> AjaxXMLInterceptor fires for instance, and the "content-type" is not 
> "text/xml", the interceptor will do nothing.
> Marker Interfaces
> -----------------------------------------------------
> In order for an Action to be populated by one of the interceptors, it must 
> implement the appropriate marker interface.  These are empty interfaces which 
> serve just to mark an Action as "aware" of either JSON or XML.  If the 
> AjaxXMLInterceptor fires for instance, and the Action does not implement the 
> AjaxXMLAware interface, the Action will not be populated.
> Configuration
> -----------------------------------------------------
> To make use of the new Results, you will need to declare them in the package 
> of the Action mappings that will use them.  The following examples will all 
> show how to set up the XML Result and Interceptor, but it is the same for the 
> JSON versions, obviously just with XML replaced with JSON everywhere:
> <result-types>
>   <result-type name="ajaxXML" 
> class="com.opensymphony.webwork.result.AjaxXMLResult" default="false" />
> </result-types>
> To make use of the Interceptors, you will likewise need to declare them in 
> the package of the Action mappings that will use them, and you will also need 
> to add them to the Interceptor stack your Action will use.  One way to do 
> this is to create a new stack.  For example, this can be accomplished as 
> follows, using the default stack as a model:
> <interceptors>
>   <interceptor name="ajaxXML" 
> class="com.opensymphony.webwork.interceptor.AjaxXMLInterceptor" />
>   <interceptor-stack name="xmlStack">
>     <interceptor-ref name="exception" />
>     <interceptor-ref name="alias" />
>     <interceptor-ref name="prepare" />
>     <interceptor-ref name="servlet-config" />
>     <interceptor-ref name="i18n" />
>     <interceptor-ref name="chain" />
>     <interceptor-ref name="model-driven" />
>     <interceptor-ref name="fileUpload" />
>     <interceptor-ref name="static-params" />
>     <interceptor-ref name="params" />
>     <interceptor-ref name="ajaxXML" />
>     <interceptor-ref name="conversionError" />
>     <interceptor-ref name="validation" />
>     <interceptor-ref name="workflow" />
>   </interceptor-stack>
> </interceptors>
> Lastly, you will need to reference the new stack, and/or Result, in your 
> Action mappings:
> <action name="sendXML_receiveXML" class="com.omnytex.TestAction">
>   <interceptor-ref name="xmlStack"/>
>   <result name="success" type="ajaxXML" />
> </action>
> Note that there are other ways to configure all of this, this is just one 
> approach (the approach used in the sample app).  Please refer to the SAF2 
> documentation for further details.
> How It All Works
> -----------------------------------------------------
> When either XML or JSON conforming to the above formats is received in the 
> body of a POST request, and the "content-type" matches the value appropriate 
> for a given Interceptor, the message is parsed, and a Map of elements is 
> created.  Each element of this Map is either a List or a Map.  For any 
> element in the XML that does not have the "key" attribute, it will be part of 
> a List.  For JSON, each array section is examined to determine if it 
> represents a straight array (or List, same thing in this case) or a Map, and 
> the appropriate type is inserted into the elements collection.  So, given the 
> above example messages, we would find that there are three elements in the 
> Map after this XML is parsed: "firstName", "children" and "certifications". 
> "firstName" and "children" would both of type List (ArrayList specifically) 
> and "certifications" will be of type Map (HashMap specifically).
> In the Action to be populated, "firstName" would be expected to be a scalar 
> value field, i.e.:
> private String firstName;
> Naturally, there should be a corresponding mutator for this field.  For the 
> "children" element, the field could be either a List or a String[] array, 
> either is supported.  For "certifications", it would need to be a Map.
> Note that in your Action, any arrays must be initialized before this 
> Interceptor fires!  You can either do this by initializing on the array 
> declaration line, or in a constructor.  They do not have to be populated, and 
> you can in fact initialize them with a size of 0, (i.e., String[] a = new 
> String[0]; is perfectly acceptable).
> Frank W. Zammetti, June 2006

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: 
https://issues.apache.org/struts/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

        

Reply via email to