[
https://issues.apache.org/struts/browse/WW-1330?page=com.atlassian.jira.plugin.system.issuetabpanels:all-tabpanel
]
Don Brown updated WW-1330:
--------------------------
Fix Version/s: (was: 2.1.x)
2.2.x
> SAF2 Automatic Ajax Support
> ---------------------------
>
> Key: WW-1330
> URL: https://issues.apache.org/struts/browse/WW-1330
> Project: Struts 2
> Issue Type: New Feature
> Components: Core Actions, Core Interceptors, Other
> Affects Versions: WW 2.2.2, 2.0.0
> Environment: Any
> Reporter: Frank W. Zammetti
> Fix For: 2.2.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.
-
You can reply to this email to add a comment to the issue online.