Date: Fri, 29 Mar 2024 11:38:46 +0000 (UTC) Message-ID: <1803534456.7903.1711712326028@ip-10-10-7-29.ec2.internal> Subject: Exported From Confluence MIME-Version: 1.0 Content-Type: multipart/related; boundary="----=_Part_7902_659698584.1711712326027" ------=_Part_7902_659698584.1711712326027 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Content-Location: file:///C:/exported.html
This document describes the strategy for parsing and generating = XHTML, XML, JSON for Grouper WS Lite / REST
There is a custom automatic converter for the parsing and generation of = XHTML. If we want to eventually support XML / JSON / whatever, we can= plug that in. The parsing is very flexible, and will give warnings i= f things are not as expected (e.g. unexpected element / attribute). I= t is also possible to hose the parser (e.g. send the wrong type for a field= ). We can also add strict mode if we like so that invalid input (thou= gh preparing for WS upgrades) will be ok (e.g. unexpected element name or m= issing a required attribute).
For XML the same beans are translated with default XStream.
For JSON the same beans are translated with default XStream and Jettison= .
The server needs to know the request and response content type. If= sending data in the request, if it is not HTTP params, then set the Conten= t-type http header. Must be one of the content types specified in the= javadoc for the enum WsLiteRequestContentType. Currently the valid v= alues are: application/xhtml+xml, text/xml, text/x-json, and for http param= s (either dont set content type or set to application/x-www-form-urlencoded= ).
The response content type will be the same as the request content type.&= nbsp; If the request content type is http params (null or form encoded), th= en the response will be whatever is specified in the grouper-ws.properties,= and it defaults to xhtml. If the client wants to override this decis= ion (to either get a different content type than was requested, or to speci= fy a different than the one specified in the grouper-ws.properties), then i= t can be placed in the url.
e.g. here is a url where the content type is the same as request or what= is configured in grouper-ws.properties: http://localh= ost/grouper-ws/servicesLite/v3_0_000/group/a:b
e.g. here is a url where the request is an http param request, and the c= onfigured response content type is xhtml, but the client wants xml: http://localhost/grouper-ws/serv= icesLite/*xml*/v3_0_000/group/a:b?includeGroupDetail=3DT
When working with the XHTML, please prepare for upgrades on the server.&= nbsp; e.g. when parsing assume there might be different types of elements, = new attributes, etc. If there is something not expected, then probabl= y ignore it (unless something is badly malformed or something). Assum= e that things will be added to the service, and not changed or removed (unl= ess there is a drastic upgrade). Also, the XML/XHTML/JSON is not inde= nted, though this shouldnt matter. The XHTML should be valid based on= the strict doctype (can validate from validator.w3.org). The XML and= JSON should obviously be valid
The objects used for the Grouper SOAP / XML-HTTP web service will be use=
d for this web service also (though they dont have to be), it supports bean=
s based on javabean properties (read / getters, write / setters). It suppor=
ts only:
1. String fields
2. int fields
3. String arrays
4. int arrays
5. Bean fields
6. Bean arrays
7. Will not work with circular references
Will throw exception if something is not right... Does not support a=
ny other structures. Inheritance is not supported. Use the obje=
cts WsXhtmlOutputConverter, and WsXhtmlInputConverter once and throw away.<=
/p>
Each Object will be written to a div or li (if in list). Each scal= ar (currently only Strings or ints) will be written to p tags or li tags fo= r lists. Each array will be a ul with li's for each item. Each = div (except the root), p, and ul will have a "class" attribute of the field= Name. Each div and li (which is a bean and not scalar) will have a "t= itle" attribute which is the simple name of the java class (non-fully quali= fied).
Null and the empty string are interchangeable and are represented as an = empty element <p />
For these three classes:
/* * @author mchyzer * $Id$ */ package edu.internet2.middleware.grouper.ws.xml; /** * */ public class BeanGrandparent { /** field 1 */ private String field1; /** field 2*/ private String field2; /** string array */ private String[] stringArray; /** field */ private BeanParent beanParent; /** field */ private BeanParent[] beanParents; /** * empty */ public BeanGrandparent() { //empty } /** * @param _field1 * @param _field2 * @param _stringArray * @param _beanParent * @param _beanParents */ public BeanGrandparent(String _field1, String _field2, String[] _stringAr= ray, BeanParent _beanParent, BeanParent[] _beanParents) { super(); this.field1 =3D _field1; this.field2 =3D _field2; this.stringArray =3D _stringArray; this.beanParent =3D _beanParent; this.beanParents =3D _beanParents; } /** * @return the field1 */ public String getField1() { return this.field1; } /** * @param _field1 the field1 to set */ public void setField1(String _field1) { this.field1 =3D _field1; } /** * @return the field2 */ public String getField2() { return this.field2; } /** * @param _field2 the field2 to set */ public void setField2(String _field2) { this.field2 =3D _field2; } /** * @return the stringArray */ public String[] getStringArray() { return this.stringArray; } /** * @param _stringArray the stringArray to set */ public void setStringArray(String[] _stringArray) { this.stringArray =3D _stringArray; } /** * @return the beanParent */ public BeanParent getBeanParent() { return this.beanParent; } /** * @param _beanParent the beanParent to set */ public void setBeanParent(BeanParent _beanParent) { this.beanParent =3D _beanParent; } /** * @return the beanParents */ public BeanParent[] getBeanParents() { return this.beanParents; } /** * @param _beanParents the beanParents to set */ public void setBeanParents(BeanParent[] _beanParents) { this.beanParents =3D _beanParents; } }
/* * @author mchyzer * $Id$ */ package edu.internet2.middleware.grouper.ws.xml; /** * parent bean */ public class BeanParent { /** field */ private String parentField1; /** field */ private String parentField2; /** field */ private String[] parentStringArray; /** field */ private int intField; /** ean child */ private BeanChild beanChild; /** child */ private BeanChild beanChild2; /** child */ private BeanChild[] beanArray; /** child */ private BeanChild[] beanArray2; /** * @return the parentField1 */ public String getParentField1() { return this.parentField1; } /** * @param _parentField1 the parentField1 to set */ public void setParentField1(String _parentField1) { this.parentField1 =3D _parentField1; } /** * @return the parentField2 */ public String getParentField2() { return this.parentField2; } /** * @param _parentField2 the parentField2 to set */ public void setParentField2(String _parentField2) { this.parentField2 =3D _parentField2; } /** * @return the parentStringArray */ public String[] getParentStringArray() { return this.parentStringArray; } /** * @param _parentStringArray the parentStringArray to set */ public void setParentStringArray(String[] _parentStringArray) { this.parentStringArray =3D _parentStringArray; } /** * empty */ public BeanParent() { //empty } /** * @param _parentField1 * @param _parentField2 * @param _parentStringArray * @param _intField * @param _beanChild * @param _beanChild2 * @param _beanArray * @param _beanArray2 */ public BeanParent(String _parentField1, String _parentField2, String[] _p= arentStringArray, int _intField, BeanChild _beanChild, BeanChild _beanChild2, BeanChild= [] _beanArray, BeanChild[] _beanArray2) { super(); this.parentField1 =3D _parentField1; this.parentField2 =3D _parentField2; this.parentStringArray =3D _parentStringArray; this.intField =3D _intField; this.beanChild =3D _beanChild; this.beanChild2 =3D _beanChild2; this.beanArray =3D _beanArray; this.beanArray2 =3D _beanArray2; } /** * @return the intField */ public int getIntField() { return this.intField; } /** * @param _intField the intField to set */ public void setIntField(int _intField) { this.intField =3D _intField; } /** * @return the beanChild */ public BeanChild getBeanChild() { return this.beanChild; } /** * @param _beanChild the beanChild to set */ public void setBeanChild(BeanChild _beanChild) { this.beanChild =3D _beanChild; } /** * @return the beanChild2 */ public BeanChild getBeanChild2() { return this.beanChild2; } /** * @param _beanChild2 the beanChild2 to set */ public void setBeanChild2(BeanChild _beanChild2) { this.beanChild2 =3D _beanChild2; } /** * @return the beanArray */ public BeanChild[] getBeanArray() { return this.beanArray; } /** * @param _beanArray the beanArray to set */ public void setBeanArray(BeanChild[] _beanArray) { this.beanArray =3D _beanArray; } /** * @return the beanArray2 */ public BeanChild[] getBeanArray2() { return this.beanArray2; } /** * @param _beanArray2 the beanArray2 to set */ public void setBeanArray2(BeanChild[] _beanArray2) { this.beanArray2 =3D _beanArray2; } }
/* * @author mchyzer * $Id$ */ package edu.internet2.middleware.grouper.ws.xml; /** * child bean */ public class BeanChild { /** field */ private String childField1; /** field */ private String childField2; /** field */ private String[] childStringArray; /** int array */ private int[] childIntegerArray; /** * empty */ public BeanChild() { //empty } /** * @param _childField1 * @param _childField2 * @param _childStringArray * @param _childIntegerArray */ public BeanChild(String _childField1, String _childField2, String[] _chil= dStringArray, int[] _childIntegerArray) { super(); this.childField1 =3D _childField1; this.childField2 =3D _childField2; this.childStringArray =3D _childStringArray; this.childIntegerArray =3D _childIntegerArray; } /** * field * @return the childField1 */ public String getChildField1() { return this.childField1; } /** * field * @param _childField1 the childField1 to set */ public void setChildField1(String _childField1) { this.childField1 =3D _childField1; } /** * field * @return the childField2 */ public String getChildField2() { return this.childField2; } /** * field * @param _childField2 the childField2 to set */ public void setChildField2(String _childField2) { this.childField2 =3D _childField2; } /** * field * @return the childStringArray */ public String[] getChildStringArray() { return this.childStringArray; } /** * field * @param _childStringArray the childStringArray to set */ public void setChildStringArray(String[] _childStringArray) { this.childStringArray =3D _childStringArray; } /** * field * @return the childIntegerArray */ public int[] getChildIntegerArray() { return this.childIntegerArray; } /** * field * @param _childIntegerArray the childIntegerArray to set */ public void setChildIntegerArray(int[] _childIntegerArray) { this.childIntegerArray =3D _childIntegerArray; } }
and for this code:
BeanChild beanChild =3D new BeanChild("va<l1", "val2", new String[]= {"a"}, new int[]{1, 2}); BeanParent beanParent =3D new BeanParent("qwe", "rtyu", new String[]{ "= uio", "cv"}, 45, null, beanChild, null, new BeanChild[]{beanChild}); BeanGrandparent beanGrandparent =3D new BeanGrandparent("xv", "", new String[]{null},beanParent, new BeanParent[]{beanParent, beanPar= ent} );
It will generate this XHTML:
<?xml version=3D'1.0' encoding=3D'iso-8859-1'?> <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.= org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xmlns=3D"http://www.w3.org/1999/xhtml" xml:lang=3D"en" lang=3D"en"= > <head> <title>the title</title> </head> <body> <div title=3D"BeanGrandparent"> <p class=3D"field1">xv</p> <p class=3D"field2" /> <ul class=3D"stringArray"> <li /> </ul> <div class=3D"beanParent" title=3D"BeanParent"> <p class=3D"parentField1">qwe</p> <p class=3D"parentField2">rtyu</p> <ul class=3D"parentStringArray"> <li>uio</li> <li>cv</li> </ul> <p class=3D"intField">45</p> <div class=3D"beanChild" title=3D"BeanChild" /> <div class=3D"beanChild2" title=3D"BeanChild"> <p class=3D"childField1">va<l1</p> <p class=3D"childField2">val2</p> <ul class=3D"childStringArray"> <li>a</li> </ul> <ul class=3D"childIntegerArray"> <li>1</li> <li>2</li> </ul> </div> <ul class=3D"beanArray2"> <li title=3D"BeanChild"> <p class=3D"childField1">va<l1</p> <p class=3D"childField2">val2</p> <ul class=3D"childStringArray"> <li>a</li> </ul> <ul class=3D"childIntegerArray"> <li>1</li> <li>2</li> </ul> </li> </ul> </div> <ul class=3D"beanParents"> <li title=3D"BeanParent"> <p class=3D"parentField1">qwe</p> <p class=3D"parentField2">rtyu</p> <ul class=3D"parentStringArray"> <li>uio</li> <li>cv</li> </ul> <p class=3D"intField">45</p> <div class=3D"beanChild" title=3D"BeanChild" /> <div class=3D"beanChild2" title=3D"BeanChild"> <p class=3D"childField1">va<l1</p> <p class=3D"childField2">val2</p> <ul class=3D"childStringArray"> <li>a</li> </ul> <ul class=3D"childIntegerArray"> <li>1</li> <li>2</li> </ul> </div> <ul class=3D"beanArray2"> <li title=3D"BeanChild"> <p class=3D"childField1">va<l1</p> <p class=3D"childField2">val2</p> <ul class=3D"childStringArray"> <li>a</li> </ul> <ul class=3D"childIntegerArray"> <li>1</li> <li>2</li> </ul> </li> </ul> </li> <li title=3D"BeanParent"> <p class=3D"parentField1">qwe</p> <p class=3D"parentField2">rtyu</p> <ul class=3D"parentStringArray"> <li>uio</li> <li>cv</li> </ul> <p class=3D"intField">45</p> <div class=3D"beanChild" title=3D"BeanChild" /> <div class=3D"beanChild2" title=3D"BeanChild"> <p class=3D"childField1">va<l1</p> <p class=3D"childField2">val2</p> <ul class=3D"childStringArray"> <li>a</li> </ul> <ul class=3D"childIntegerArray"> <li>1</li> <li>2</li> </ul> </div> <ul class=3D"beanArray2"> <li title=3D"BeanChild"> <p class=3D"childField1">va<l1</p> <p class=3D"childField2">val2</p> <ul class=3D"childStringArray"> <li>a</li> </ul> <ul class=3D"childIntegerArray"> <li>1</li> <li>2</li> </ul> </li> </ul> </li> </ul> </div> </body> </html>
It generates this XML:
<BeanGrandparent> <field1>xv</field1> <stringArray> <null /> </stringArray> <beanParent> <parentField1>qwe</parentField1> <parentField2>rtyu</parentField2> <parentStringArray> <string>uio</string> <string>cv</string> </parentStringArray> <intField>45</intField> <beanChild2> <childField1>v"a<l{1}</childField1> <childField2>val2</childField2> <childStringArray> <string>a</string> </childStringArray> <childIntegerArray> <int>1</int> <int>2</int> </childIntegerArray> </beanChild2> <beanArray2> <BeanChild> <childField1>v"a<l{1}</childField1> <childField2>val2</childField2> <childStringArray> <string>a</string> </childStringArray> <childIntegerArray> <int>1</int> <int>2</int> </childIntegerArray> </BeanChild> </beanArray2> </beanParent> <beanParents> <BeanParent> <parentField1>qwe</parentField1> <parentField2>rtyu</parentField2> <parentStringArray> <string>uio</string> <string>cv</string> </parentStringArray> <intField>45</intField> <beanChild2> <childField1>v"a<l{1}</childField1> <childField2>val2</childField2> <childStringArray> <string>a</string> </childStringArray> <childIntegerArray> <int>1</int> <int>2</int> </childIntegerArray> </beanChild2> <beanArray2> <BeanChild> <childField1>v"a<l{1}</childField1> <childField2>val2</childField2> <childStringArray> <string>a</string> </childStringArray> <childIntegerArray> <int>1</int> <int>2</int> </childIntegerArray> </BeanChild> </beanArray2> </BeanParent> <BeanParent> <parentField1>qwe</parentField1> <parentField2>rtyu</parentField2> <parentStringArray> <string>uio</string> <string>cv</string> </parentStringArray> <intField>45</intField> <beanChild2> <childField1>v"a<l{1}</childField1> <childField2>val2</childField2> <childStringArray> <string>a</string> </childStringArray> <childIntegerArray> <int>1</int> <int>2</int> </childIntegerArray> </beanChild2> <beanArray2> <BeanChild> <childField1>v"a<l{1}</childField1> <childField2>val2</childField2> <childStringArray> <string>a</string> </childStringArray> <childIntegerArray> <int>1</int> <int>2</int> </childIntegerArray> </BeanChild> </beanArray2> </BeanParent> </beanParents> </BeanGrandparent>
And it generates this JSON:
{ "BeanGrandparent":{ "field1":"xv", "stringArray":{ "null":"" }, "beanParent":{ "parentField1":"qwe", "parentField2":"rtyu", "parentStringArray":{ "string":[ "uio", "cv" ] }, "intField":45, "beanChild2":{ "childField1":"v\"a<l{1}", "childField2":"val2", "childStringArray":{ "string":"a" }, "childIntegerArray":{ "int":[ 1, 2 ] } }, "beanArray2":{ "BeanChild":{ "childField1":"v\"a<l{1}", "childField2":"val2", "childStringArray":{ "string":"a" }, "childIntegerArray":{ "int":[ 1, 2 ] } } } }, "beanParents":{ "BeanParent":[ { "parentField1":"qwe", "parentField2":"rtyu", "parentStringArray":{ "string":[ "uio", "cv" ] }, "intField":45, "beanChild2":{ "childField1":"v\"a<l{1}", "childField2":"val2", "childStringArray":{ "string":"a" }, "childIntegerArray":{ "int":[ 1, 2 ] } }, "beanArray2":{ "BeanChild":{ "childField1":"v\"a<l{1}", "childField2":"val2", "childStringArray":{ "string":"a" }, "childIntegerArray":{ "int":[ 1, 2 ] } } } }, { "parentField1":"qwe", "parentField2":"rtyu", "parentStringArray":{ "string":[ "uio", "cv" ] }, "intField":45, "beanChild2":{ "childField1":"v\"a<l{1}", "childField2":"val2", "childStringArray":{ "string":"a" }, "childIntegerArray":{ "int":[ 1, 2 ] } }, "beanArray2":{ "BeanChild":{ "childField1":"v\"a<l{1}", "childField2":"val2", "childStringArray":{ "string":"a" }, "childIntegerArray":{ "int":[ 1, 2 ] } } } } ] } } }
Here is INVALID MARKUP, (extra attribute, and extra element) but i= t is successfully parsed and here is the warning that the web service will = produce in the response back to the client (though the request will still s= ucceed if everything else is ok)
<div title=3D" BeanChild " id=3D" something"> <span>something</span> <p class=3D"childField1">va<l1</p> <p class=3D"childField2">val2</p> <ul class=3D"childStringArray"> <li>a</li> </ul> <ul class=3D"childIntegerArray"> <li>1</li> <li>2</li> </ul> </div>
Warnings:
Element 'div' is not expecting attribute: 'id' Element 'div' is not expecting child element: 'span'