Some ideas on oVirt Java SDK

Hi guys, since the initial (small, working & well-tested) version of oVirtJS JavaScript SDK is finished [*], I've started working on GWT wrapper for oVirtJS. While analyzing/reverse-engineering oVirt Java SDK, some thoughts came to my mind, and I wanted to share them with you. [*] TODO(vszocs) upload new patchset with all recent changes First, the way XJC (JAXB binding compiler that generates Java beans out of REST XSD schema) is invoked looks a bit weird to me, as Java SDK's XsdCodegen does this: Runtime.getRuntime().exec(command) Why not simply use existing Maven plugins to invoke XJC? - either: https://github.com/highsource/maven-jaxb2-plugin - or: http://mojo.codehaus.org/jaxb2-maven-plugin/ Second, and most importantly, what's the point of having "group" entities? I'll give an example - api.xsd contains this: <xs:complexType name="DataCenters"> <xs:complexContent> <xs:extension base="BaseResources"> <xs:sequence> <xs:annotation> <xs:appinfo> <jaxb:property name="DataCenters"/> </xs:appinfo> </xs:annotation> <xs:element ref="data_center" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType> (Same as above for Hosts, Clusters, VMs, etc.) This results in following (IMHO rather meaningless) Java class being generated by XJC: public class DataCenters extends BaseResources { @XmlElement(name = "data_center") protected List<DataCenter> dataCenters; public List<DataCenter> getDataCenters() { if (dataCenters == null) { dataCenters = new ArrayList<DataCenter>(); } return this.dataCenters; } public boolean isSetDataCenters() { return ((this.dataCenters!= null)&&(!this.dataCenters.isEmpty())); } public void unsetDataCenters() { this.dataCenters = null; } } Instead, we could use @XmlElementWrapper as described in [1] to avoid generating "group" entities altogether. [1] https://github.com/dmak/jaxb-xew-plugin The fact that Java SDK provides decorator for each specific resource collection (like DataCenters), instead of having ONE resource collection type, greatly complicates overall design and code-gen aspect. In oVirtJS GWT wrapper, we'll avoid above complication through single resource collection type (having common methods like get(id), list() etc) for all resources. Regards, Vojtech

------=_Part_1859450_1427808343.1417346766163 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: quoted-printable Hey Vojtech, How are you?, please see my reply inline. On Friday, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.co= m> wrote: =20 Hi guys, since the initial (small, working & well-tested) version of oVirtJS JavaScript SDK is finished [*], I've started working on GWT wrapper for oVirtJS. While analyzing/reverse-engineering oVirt Java SDK, some thoughts came to my mind, and I wanted to share them with you. [*] TODO(vszocs) upload new patchset with all recent changes First, the way XJC (JAXB binding compiler that generates Java beans out of REST XSD schema) is invoked looks a bit weird to me, as Java SDK's XsdCodegen does this: =C2=A0 Runtime.getRuntime().exec(command) Why not simply use existing Maven plugins to invoke XJC? - either: https://github.com/highsource/maven-jaxb2-plugin [MP] sdk was using jaxb to begin with, it was replaced with XJC just recent= ly, btw Juan, what was the motivation behind this?=20 (REST api uses jaxb as well so we used to have 1x1 mappings) =C2=A0 - or: http://mojo.codehaus.org/jaxb2-maven-plugin/ [MP]=C2=A0same. Second, and most importantly, what's the point of having "group" entities? I'll give an example - api.xsd contains this: =C2=A0 <xs:complexType name=3D"DataCenters"> =C2=A0 =C2=A0 <xs:complexContent> =C2=A0 =C2=A0 =C2=A0 <xs:extension base=3D"BaseResources"> =C2=A0 =C2=A0 =C2=A0 =C2=A0 <xs:sequence> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 <xs:annotation> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 <xs:appinfo> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 <jaxb:property name= =3D"DataCenters"/> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </xs:appinfo> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </xs:annotation> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 <xs:element ref=3D"data_center" minOccur= s=3D"0" maxOccurs=3D"unbounded"/> =C2=A0 =C2=A0 =C2=A0 =C2=A0 </xs:sequence> =C2=A0 =C2=A0 =C2=A0 </xs:extension> =C2=A0 =C2=A0 </xs:complexContent> =C2=A0 </xs:complexType> (Same as above for Hosts, Clusters, VMs, etc.) This results in following (IMHO rather meaningless) Java class being generated by XJC: public class DataCenters extends BaseResources { =C2=A0 =C2=A0 @XmlElement(name =3D "data_center") =C2=A0 =C2=A0 protected List<DataCenter> dataCenters; =C2=A0 =C2=A0 public List<DataCenter> getDataCenters() { =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (dataCenters =3D=3D null) { =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 dataCenters =3D new ArrayList<Dat= aCenter>(); =C2=A0 =C2=A0 =C2=A0 =C2=A0 } =C2=A0 =C2=A0 =C2=A0 =C2=A0 return this.dataCenters; =C2=A0 =C2=A0 } =C2=A0 =C2=A0 public boolean isSetDataCenters() { =C2=A0 =C2=A0 =C2=A0 =C2=A0 return ((this.dataCenters!=3D null)&&(!this.dat= aCenters.isEmpty())); =C2=A0 =C2=A0 } =C2=A0 =C2=A0 public void unsetDataCenters() { =C2=A0 =C2=A0 =C2=A0 =C2=A0 this.dataCenters =3D null; =C2=A0 =C2=A0 } } Instead, we could use @XmlElementWrapper as described in [1] to avoid generating "group" entities altogether. [1] https://github.com/dmak/jaxb-xew-plugin The fact that Java SDK provides decorator for each specific resource collection (like DataCenters), instead of having ONE resource collection type, greatly complicates overall design and code-gen aspect. [MP]=C2=A0Well, i guess now is speaking JS constraints ghost, am i right?, in any case, the reasons for having decorator per collection are: 1. compliance with REST API (all SDKs and REST api are sharing same well kn= ow architecture) 2. "decorator" is a well known and commonly used java design pattern 3. having one resource type serving all collections would create a bottlene= ck (well it might depend on how you implementing it, but still in my view it's= less convenient/readable than dedicated collection with own context, verbs and behavior),=C2=A0 after all the purpose of sdk is being java client serving application in "J= ava" way(i.e type-safe + well bounded interface),=C2=A0while JS use-cases &= paradigms are totallydifferent,=C2=A0just consider: [1] java-sdk stile Disk snapshotDisk =3D api.getVms().get('my-vm').getSnapshots().get('my-snap= shot').getDisks().get('my-disk') [2] JS style you propose Disk snapshotDisk =3D getCollections().get(new Params[] { Disk.class, 'my-v= m', 'my-snapshot', 'my-disk'}) notice:=C2=A0=3D=3D=3D=3D=3D in [2] you have a bunch of parameters disconnected form any context where o= rderis *important* (other way you heuristic guesses what user meaning by th= ese params won't work),obviously it's fragile and error prone, while [1] is readable, well bounded, defending it's consumers from potentia= ls errors(exactly what SDK should look like), hope it helps. =20 On Friday, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.com=
wrote: =20
<xs:element ref=3D"data_center" minO= ccurs=3D"0" maxOccurs=3D"unbounded"/><br class=3D"" style=3D""> &n= bsp; </xs:sequence><br class=3D"" style=3D""> &nb= sp; </xs:extension><br class=3D"" style=3D""> <= ;/xs:complexContent><br class=3D"" style=3D""> </xs:complexType= ><br class=3D"" style=3D""><br class=3D"" style=3D"">(Same as above for = Hosts, Clusters, VMs, etc.)<br class=3D"" style=3D""><br class=3D"" style= =3D"">This results in following (IMHO rather meaningless) Java class<br cla= ss=3D"" style=3D"">being generated by XJC:<br class=3D"" style=3D""><br cla= ss=3D"" style=3D"">public class DataCenters extends BaseResources {<br clas= s=3D"" style=3D""><br class=3D"" style=3D""> @XmlElement(name = =3D "data_center")<br class=3D"" style=3D""> protected List<= ;DataCenter> dataCenters;<br class=3D"" style=3D""><br class=3D"" style= =3D""> public List<DataCenter> getDataCenters() {<br cla= ss=3D"" style=3D""> if (dataCenters =3D=3D null)= {<br class=3D"" style=3D""> dataC= enters =3D new ArrayList<DataCenter>();<br class=3D"" style=3D"">&nbs=
<div class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_14466"><font s= ize=3D"4" class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_14465">[MP= ] Well, i guess now is speaking JS constraints ghost, am i right?</fon= t>,<br class=3D"" style=3D""></div><div class=3D"" style=3D"" id=3D"yui_3_1= 6_0_1_1417345481659_12513"><font size=3D"4" class=3D"" style=3D"" id=3D"yui= _3_16_0_1_1417345481659_12514">in any case, the reasons for having decorato= r per collection are:<br class=3D"" style=3D""><br class=3D"" style=3D""></= font></div><div class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_1251= 2"><font size=3D"4" class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_= 12511">1. compliance with REST API (all SDKs and REST api are sharing same = well know architecture)<br class=3D"" style=3D""></font></div><div class=3D= "" style=3D"" id=3D"yui_3_16_0_1_1417345481659_12510"><font size=3D"4" clas= s=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_12509">2. "decorator" is= a well known and commonly used java design pattern<br class=3D"" style=3D"= "></font></div><div class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_= 12508"><font size=3D"4" class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481= 659_12507">3. having one resource type serving all collections would create= a bottleneck<br class=3D"" style=3D""></font></div><div class=3D"" style= =3D"" id=3D"yui_3_16_0_1_1417345481659_12506"><font size=3D"4" class=3D"" s= tyle=3D"" id=3D"yui_3_16_0_1_1417345481659_12505">(well it might depend on = how you implementing it, but still in my view it's less convenient/readable= <br class=3D"" style=3D"">than dedicated collection with own context, verbs= and behavior), </font></div><div class=3D"" style=3D"" id=3D"yui_3_16= _0_1_1417345481659_12506"><font size=3D"4" class=3D"" style=3D""><br></font= </div><font size=3D"4" class=3D"" id=3D"yui_3_16_0_1_1417345481659_12521" =
</div><div class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_12506" d= ir=3D"ltr"><font size=3D"4" class=3D"" style=3D"" id=3D"yui_3_16_0_1_141734= 5481659_16215">[1] java-sdk stile</font></div><div class=3D"" style=3D"" id= =3D"yui_3_16_0_1_1417345481659_12506" dir=3D"ltr"><font size=3D"4" class=3D= "" style=3D""><br></font></div><div class=3D"" style=3D"" id=3D"yui_3_16_0_= 1_1417345481659_12506" dir=3D"ltr"><font size=3D"4" class=3D"" style=3D"" i= d=3D"yui_3_16_0_1_1417345481659_12981">Disk snapshotDisk =3D api.getVms().g= et('my-vm').getSnapshots().get('my-snapshot').getDisks().get('my-disk')</fo= nt></div><div class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_12506"=
</div><div class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_12506" d= ir=3D"ltr"><font size=3D"4" class=3D"" style=3D"" id=3D"yui_3_16_0_1_141734= 5481659_13698">in [2] you have a bunch of parameters disconnected form any = context where order</font></div><div class=3D"" style=3D"" id=3D"yui_3_16_0= _1_1417345481659_12506" dir=3D"ltr"><font size=3D"4" class=3D"" style=3D"" = id=3D"yui_3_16_0_1_1417345481659_13001">is *important* (other way you heuri= stic guesses what user meaning by these params won't work),</font></div><di= v class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_12506" dir=3D"ltr"= <font size=3D"4" class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_14= 446">obviously it's fragile and error prone,</font></div><div class=3D"" st= yle=3D"" id=3D"yui_3_16_0_1_1417345481659_12506" dir=3D"ltr"><font size=3D"= 4" class=3D"" style=3D""><br></font></div><div class=3D"" style=3D"" id=3D"= yui_3_16_0_1_1417345481659_12506" dir=3D"ltr"><font size=3D"4" class=3D"" s= tyle=3D"" id=3D"yui_3_16_0_1_1417345481659_13697">while [1] is readable, we= ll bounded, defending it's consumers from potentials errors</font></div><di= v class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_12506" dir=3D"ltr"= <font size=3D"4" class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_18= 064">(exactly what SDK should look like),</font></div><div class=3D"" style= =3D"" id=3D"yui_3_16_0_1_1417345481659_12506" dir=3D"ltr"><font size=3D"4" = class=3D"" style=3D""><br></font></div><div class=3D"" style=3D"" id=3D"yui= _3_16_0_1_1417345481659_12506" dir=3D"ltr"><font size=3D"4" class=3D"" styl= e=3D"" id=3D"yui_3_16_0_1_1417345481659_17133">hope it helps.</font></div><=
Hi guys, since the initial (small, working & well-tested) version of oVirtJS JavaScript SDK is finished [*], I've started working on GWT wrapper for oVirtJS. While analyzing/reverse-engineering oVirt Java SDK, some thoughts came to my mind, and I wanted to share them with you. [*] TODO(vszocs) upload new patchset with all recent changes First, the way XJC (JAXB binding compiler that generates Java beans out of REST XSD schema) is invoked looks a bit weird to me, as Java SDK's XsdCodegen does this: =C2=A0 Runtime.getRuntime().exec(command) Why not simply use existing Maven plugins to invoke XJC? - either: https://github.com/highsource/maven-jaxb2-plugin - or: http://mojo.codehaus.org/jaxb2-maven-plugin/ Second, and most importantly, what's the point of having "group" entities? I'll give an example - api.xsd contains this: =C2=A0 <xs:complexType name=3D"DataCenters"> =C2=A0 =C2=A0 <xs:complexContent> =C2=A0 =C2=A0 =C2=A0 <xs:extension base=3D"BaseResources"> =C2=A0 =C2=A0 =C2=A0 =C2=A0 <xs:sequence> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 <xs:annotation> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 <xs:appinfo> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 <jaxb:property name= =3D"DataCenters"/> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </xs:appinfo> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 </xs:annotation> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 <xs:element ref=3D"data_center" minOccur= s=3D"0" maxOccurs=3D"unbounded"/> =C2=A0 =C2=A0 =C2=A0 =C2=A0 </xs:sequence> =C2=A0 =C2=A0 =C2=A0 </xs:extension> =C2=A0 =C2=A0 </xs:complexContent> =C2=A0 </xs:complexType> (Same as above for Hosts, Clusters, VMs, etc.) This results in following (IMHO rather meaningless) Java class being generated by XJC: public class DataCenters extends BaseResources { =C2=A0 =C2=A0 @XmlElement(name =3D "data_center") =C2=A0 =C2=A0 protected List<DataCenter> dataCenters; =C2=A0 =C2=A0 public List<DataCenter> getDataCenters() { =C2=A0 =C2=A0 =C2=A0 =C2=A0 if (dataCenters =3D=3D null) { =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 dataCenters =3D new ArrayList<Dat= aCenter>(); =C2=A0 =C2=A0 =C2=A0 =C2=A0 } =C2=A0 =C2=A0 =C2=A0 =C2=A0 return this.dataCenters; =C2=A0 =C2=A0 } =C2=A0 =C2=A0 public boolean isSetDataCenters() { =C2=A0 =C2=A0 =C2=A0 =C2=A0 return ((this.dataCenters!=3D null)&&(!this.dat= aCenters.isEmpty())); =C2=A0 =C2=A0 } =C2=A0 =C2=A0 public void unsetDataCenters() { =C2=A0 =C2=A0 =C2=A0 =C2=A0 this.dataCenters =3D null; =C2=A0 =C2=A0 } } Instead, we could use @XmlElementWrapper as described in [1] to avoid generating "group" entities altogether. [1] https://github.com/dmak/jaxb-xew-plugin The fact that Java SDK provides decorator for each specific resource collection (like DataCenters), instead of having ONE resource collection type, greatly complicates overall design and code-gen aspect. In oVirtJS GWT wrapper, we'll avoid above complication through single resource collection type (having common methods like get(id), list() etc) for all resources. Regards, Vojtech _______________________________________________ Devel mailing list Devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/devel ------=_Part_1859450_1427808343.1417346766163 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div style=3D"color:#000; background-color:#fff; font-family:HelveticaNeue-= Light, Helvetica Neue Light, Helvetica Neue, Helvetica, Arial, Lucida Grand= e, sans-serif;font-size:16px"><div id=3D"yui_3_16_0_1_1417345481659_9805"><= span></span></div><div class=3D"" style=3D"" id=3D"yui_3_16_0_1_14173454816= 59_9941">Hey <font face=3D"Arial" class=3D"" style=3D"">Vojtech,<br class= =3D"" style=3D""><br class=3D"" style=3D""></font></div><div class=3D"" sty= le=3D"" id=3D"yui_3_16_0_1_1417345481659_9944"><font face=3D"Arial" class= =3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_9943">How are you?, pleas= e see my reply inline.<br class=3D"" style=3D""></font></div><div class=3D"= " style=3D"" id=3D"yui_3_16_0_1_1417345481659_9922"><div class=3D"" style= =3D"" id=3D"yui_3_16_0_1_1417345481659_9921"><span class=3D"" style=3D"" id= =3D"yui_3_16_0_1_1417345481659_9938"><br class=3D"" style=3D""><blockquote = class=3D"" style=3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,= 204,204);padding-left:1ex" id=3D"yui_3_16_0_1_1417345481659_9937"><div styl= e=3D"font-family: HelveticaNeue, 'Helvetica Neue', Helvetica, Arial, 'Lucid= a Grande', sans-serif;" class=3D"" id=3D"yui_3_16_0_1_1417345481659_9936"><= div class=3D"" style=3D""></div><div class=3D"" style=3D"" id=3D"yui_3_16_0= _1_1417345481659_9942"><br class=3D"" style=3D""><br class=3D"" style=3D"">= </div> <div class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_9935"> = <div class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_9934"> <div cla= ss=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_9933"> <div dir=3D"ltr"= class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_9940"> <font face= =3D"Arial" class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_9939"> On= Friday, November 28, 2014 5:26 PM, Vojtech Szocs <<a href=3D"mailto:vsz= ocs@redhat.com" target=3D"_blank" class=3D"" style=3D"">vszocs@redhat.com</= a>> wrote:<br class=3D"" style=3D""> </font> </div> <br class=3D"" styl= e=3D""><br class=3D"" style=3D""> <div class=3D"" style=3D"" id=3D"yui_3_16= _0_1_1417345481659_9932">Hi guys,<br class=3D"" style=3D""><br class=3D"" s= tyle=3D"">since the initial (small, working & well-tested) version of o= VirtJS<br class=3D"" style=3D"">JavaScript SDK is finished [*], I've starte= d working on GWT wrapper<br class=3D"" style=3D"">for oVirtJS.<br class=3D"= " style=3D""><br class=3D"" style=3D"">While analyzing/reverse-engineering = oVirt Java SDK, some thoughts<br class=3D"" style=3D"">came to my mind, and= I wanted to share them with you.<br class=3D"" style=3D""><br class=3D"" s= tyle=3D"">[*] TODO(vszocs) upload new patchset with all recent changes<br c= lass=3D"" style=3D""><br class=3D"" style=3D"">First, the way XJC (JAXB bin= ding compiler that generates Java beans<br class=3D"" style=3D"">out of RES= T XSD schema) is invoked looks a bit weird to me, as Java<br class=3D"" sty= le=3D"">SDK's XsdCodegen does this:<br class=3D"" style=3D""><br class=3D""= style=3D""> Runtime.getRuntime().exec(<wbr class=3D"" style=3D"">com= mand)<br class=3D"" style=3D""><br class=3D"" style=3D"">Why not simply use= existing Maven plugins to invoke XJC?<br class=3D"" style=3D"">- either: <= a href=3D"https://github.com/highsource/maven-jaxb2-plugin" target=3D"_blan= k" class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_9931">https://git= hub.com/highsource/<wbr class=3D"" style=3D"">maven-jaxb2-plugin</a><br cla= ss=3D"" style=3D""></div></div></div></div></div></blockquote><div class=3D= "" style=3D"" id=3D"yui_3_16_0_1_1417345481659_10278"><br class=3D"" style= =3D""></div></span><div class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481= 659_9930" dir=3D"ltr"><font size=3D"4" class=3D"" style=3D"" id=3D"yui_3_16= _0_1_1417345481659_9929">[MP] sdk was using jaxb to begin with, it was repl= aced with XJC just recently,<br class=3D"" style=3D""></font></div><div cla= ss=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_9928"><font size=3D"4" = class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_9927">btw Juan, what= was the motivation behind this? <br class=3D"" style=3D"">(REST api uses j= axb as well so we used to have 1x1 mappings)</font><br class=3D"" style=3D"= "></div><div class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_10277">= </div><blockquote class=3D"" style=3D"margin:0px 0px 0px 0.8ex;border= -left:1px solid rgb(204,204,204);padding-left:1ex" id=3D"yui_3_16_0_1_14173= 45481659_9920"><div style=3D"font-family: HelveticaNeue, 'Helvetica Neue', = Helvetica, Arial, 'Lucida Grande', sans-serif;" class=3D"" id=3D"yui_3_16_0= _1_1417345481659_9919">- or: <a href=3D"http://mojo.codehaus.org/jaxb2-mave= n-plugin/" target=3D"_blank" class=3D"" style=3D"" id=3D"yui_3_16_0_1_14173= 45481659_9918">http://mojo.codehaus.org/<wbr class=3D"" style=3D"">jaxb2-ma= ven-plugin/</a><br class=3D"" style=3D""></div></blockquote><div class=3D""= style=3D"" id=3D"yui_3_16_0_1_1417345481659_9923"><br class=3D"" style=3D"= "></div><div class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_9924"><= font size=3D"4" class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_1029= 0">[MP] same.</font><br class=3D"" style=3D""></div><div class=3D"" st= yle=3D""><div class=3D"" style=3D""><div id=3D"q_14a003ec78624219_3" class= =3D"" style=3D""><div class=3D"" style=3D""></div></div></div></div><div cl= ass=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_9926"><br></div><div c= lass=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_9926"><div class=3D""= style=3D"" id=3D"yui_3_16_0_1_1417345481659_14459"><div class=3D"" style= =3D"" id=3D"yui_3_16_0_1_1417345481659_14458"><blockquote class=3D"" style= =3D"margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding= -left:1ex" id=3D"yui_3_16_0_1_1417345481659_14457"><div style=3D"font-famil= y: HelveticaNeue, 'Helvetica Neue', Helvetica, Arial, 'Lucida Grande', sans= -serif;" class=3D"" id=3D"yui_3_16_0_1_1417345481659_14456"><br class=3D"" = style=3D"">Second, and most importantly, what's the point of having "group"= <br class=3D"" style=3D"">entities? I'll give an example - api.xsd contains= this:<br class=3D"" style=3D""><br class=3D"" style=3D""> <xs:com= plexType name=3D"DataCenters"><br class=3D"" style=3D""> &l= t;xs:complexContent><br class=3D"" style=3D""> <x= s:extension base=3D"BaseResources"><br class=3D"" style=3D""> &nbs= p; <xs:sequence><br class=3D"" style=3D""> = <xs:annotation><br class=3D"" style=3D""> = <xs:appinfo><br class=3D"" style= =3D""> <jaxb:prop= erty name=3D"DataCenters"/><br class=3D"" style=3D"">  = ; </xs:appinfo><br class=3D"" style=3D""> = </xs:annotation><br class=3D"" style=3D""= p; }<br class=3D"" style=3D""> &nb= sp; return this.dataCenters;<br class=3D"" style=3D""> }<br cl= ass=3D"" style=3D""><br class=3D"" style=3D""> public boolean = isSetDataCenters() {<br class=3D"" style=3D""> r= eturn ((this.dataCenters!=3D null)&&(!this.dataCenters.<wbr class= =3D"" style=3D"">isEmpty()));<br class=3D"" style=3D""> }<br c= lass=3D"" style=3D""><br class=3D"" style=3D""> public void un= setDataCenters() {<br class=3D"" style=3D""> thi= s.dataCenters =3D null;<br class=3D"" style=3D""> }<br class= =3D"" style=3D""><br class=3D"" style=3D"">}<br class=3D"" style=3D""><br c= lass=3D"" style=3D"">Instead, we could use @XmlElementWrapper as described = in [1]<br class=3D"" style=3D"">to avoid generating "group" entities altoge= ther.<br class=3D"" style=3D""><br class=3D"" style=3D"">[1] <a href=3D"htt= ps://github.com/dmak/jaxb-xew-plugin" target=3D"_blank" class=3D"" style=3D= "" id=3D"yui_3_16_0_1_1417345481659_14463">https://github.com/dmak/jaxb-<wb= r class=3D"" style=3D"">xew-plugin</a><br class=3D"" style=3D""><br class= =3D"" style=3D"">The fact that Java SDK provides decorator for each specifi= c<br class=3D"" style=3D"">resource collection (like DataCenters), instead = of having ONE<br class=3D"" style=3D"">resource collection type, greatly co= mplicates overall design<br class=3D"" style=3D"">and code-gen aspect.<br c= lass=3D"" style=3D""></div></blockquote><div class=3D"" style=3D"" id=3D"yu= i_3_16_0_1_1417345481659_14464"><br class=3D"" style=3D""></div></div></div= style=3D"">after all the purpose of sdk is being java client serving applic= ation in "Java" way</font></div><div class=3D"" style=3D"" id=3D"yui_3_16_0= _1_1417345481659_9926" dir=3D"ltr"><font size=3D"4" class=3D"" style=3D"">(= i.e type-safe + well bounded interface), </font><font size=3D"4" class= =3D"" id=3D"yui_3_16_0_1_1417345481659_12521" style=3D"font-size: large;">w= hile JS use-cases & paradigms are totally</font></div><div class=3D"" s= tyle=3D"" id=3D"yui_3_16_0_1_1417345481659_9926" dir=3D"ltr"><font size=3D"= 4" class=3D"" style=3D"font-size: large;">different</font><span class=3D"" = id=3D"yui_3_16_0_1_1417345481659_16206">, </span><span style=3D"font-s= ize: large;">just consider:</span><div class=3D"" style=3D"" id=3D"yui_3_16= _0_1_1417345481659_12506"><font size=3D"4" class=3D"" style=3D""><br></font= dir=3D"ltr"><font size=3D"4" class=3D"" style=3D""><br></font></div><div c= lass=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_12506" dir=3D"ltr"><f= ont size=3D"4" class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_12991= ">[2] JS style you propose</font></div><div class=3D"" style=3D"" id=3D"yui= _3_16_0_1_1417345481659_12506" dir=3D"ltr"><font size=3D"4" class=3D"" styl= e=3D""><br></font></div><div class=3D"" style=3D"" id=3D"yui_3_16_0_1_14173= 45481659_12506" dir=3D"ltr"><font size=3D"4" class=3D"" style=3D"" id=3D"yu= i_3_16_0_1_1417345481659_12988">Disk snapshotDisk =3D getCollections().get(= new Params[] { Disk.class, 'my-vm', 'my-snapshot', 'my-disk'})<br></font></= div><div class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_12506" dir= =3D"ltr"><font size=3D"4" class=3D"" style=3D""><br></font></div><div class= =3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_12506" dir=3D"ltr"><font = size=3D"4" class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_13000">no= tice: </font></div><div class=3D"" style=3D"" id=3D"yui_3_16_0_1_14173= 45481659_12506" dir=3D"ltr"><font size=3D"4" class=3D"" style=3D"">=3D=3D= =3D=3D=3D</font></div><div class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345= 481659_12506" dir=3D"ltr"><font size=3D"4" class=3D"" style=3D""><br></font= div class=3D"" style=3D"" id=3D"yui_3_16_0_1_1417345481659_12506" dir=3D"lt= r"><font size=3D"4" class=3D"" style=3D""><br></font></div><div class=3D"" = style=3D"" id=3D"yui_3_16_0_1_1417345481659_12520"><font size=3D"4" class= =3D"" style=3D""><br class=3D"" style=3D""></font></div><div class=3D"" sty= le=3D"" id=3D"yui_3_16_0_1_1417345481659_12522"><br><div class=3D"" style= =3D"" id=3D"yui_3_16_0_1_1417345481659_12976"><div data-tooltip=3D"Hide exp= anded content" aria-label=3D"Hide expanded content" id=3D":g8" class=3D"" r= ole=3D"button" tabindex=3D"0" style=3D""><img class=3D"" src=3D"https://ssl= .gstatic.com/ui/v1/icons/mail/images/cleardot.gif" style=3D"" data-id=3D"cc= 22cabd-7587-31ae-35b3-0bad76861607"></div></div></div></div><div class=3D""= style=3D"" id=3D"yui_3_16_0_1_1417345481659_9926"><br class=3D"" style=3D"= "></div></div></div> <div class=3D"qtdSeparateBR"><br><br></div><div class= =3D"yahoo_quoted" style=3D"display: block;"> <div style=3D"font-family: Hel= veticaNeue-Light, Helvetica Neue Light, Helvetica Neue, Helvetica, Arial, L= ucida Grande, sans-serif; font-size: 16px;"> <div style=3D"font-family: Hel= veticaNeue, Helvetica Neue, Helvetica, Arial, Lucida Grande, sans-serif; fo= nt-size: 16px;"> <div dir=3D"ltr"> <font size=3D"2" face=3D"Arial"> On Frid= ay, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.com> wrot= e:<br> </font> </div> <br><br> <div class=3D"y_msg_container">Hi guys,<br>= <br>since the initial (small, working & well-tested) version of oVirtJS= <br>JavaScript SDK is finished [*], I've started working on GWT wrapper<br>= for oVirtJS.<br><br>While analyzing/reverse-engineering oVirt Java SDK, som= e thoughts<br>came to my mind, and I wanted to share them with you.<br><br>= [*] TODO(vszocs) upload new patchset with all recent changes<br><br>First, = the way XJC (JAXB binding compiler that generates Java beans<br>out of REST= XSD schema) is invoked looks a bit weird to me, as Java<br>SDK's XsdCodege= n does this:<br><br> Runtime.getRuntime().exec(command)<br><br>Why no= t simply use existing Maven plugins to invoke XJC?<br>- either: <a href=3D"= https://github.com/highsource/maven-jaxb2-plugin" target=3D"_blank">https:/= /github.com/highsource/maven-jaxb2-plugin</a><br>- or: <a href=3D"http://mo= jo.codehaus.org/jaxb2-maven-plugin/" target=3D"_blank">http://mojo.codehaus= .org/jaxb2-maven-plugin/</a><br><br>Second, and most importantly, what's th= e point of having "group"<br>entities? I'll give an example - api.xsd conta= ins this:<br><br> <xs:complexType name=3D"DataCenters"><br>&nbs= p; <xs:complexContent><br> <xs:extensio= n base=3D"BaseResources"><br> <xs:sequence= ><br> <xs:annotation><br> = <xs:appinfo><br> &nbs= p; <jaxb:property name=3D"DataCenters= "/><br> </xs:appinfo><br>= </xs:annotation><br> = <xs:element ref=3D"data_center" minOccurs=3D"0" max= Occurs=3D"unbounded"/><br> </xs:sequence&g= t;<br> </xs:extension><br> </xs:c= omplexContent><br> </xs:complexType><br><br>(Same as above f= or Hosts, Clusters, VMs, etc.)<br><br>This results in following (IMHO rathe= r meaningless) Java class<br>being generated by XJC:<br><br>public class Da= taCenters extends BaseResources {<br><br> @XmlElement(name =3D= "data_center")<br> protected List<DataCenter> dataCente= rs;<br><br> public List<DataCenter> getDataCenters() {<b= r> if (dataCenters =3D=3D null) {<br> &nbs= p; dataCenters =3D new ArrayList<DataCenter&= gt;();<br> }<br> retu= rn this.dataCenters;<br> }<br><br> public boolean= isSetDataCenters() {<br> return ((this.dataCent= ers!=3D null)&&(!this.dataCenters.isEmpty()));<br> }<b= r><br> public void unsetDataCenters() {<br>  = ; this.dataCenters =3D null;<br> }<br><br>}<br><br>Inst= ead, we could use @XmlElementWrapper as described in [1]<br>to avoid genera= ting "group" entities altogether.<br><br>[1] <a href=3D"https://github.com/= dmak/jaxb-xew-plugin" target=3D"_blank">https://github.com/dmak/jaxb-xew-pl= ugin</a><br><br>The fact that Java SDK provides decorator for each specific= <br>resource collection (like DataCenters), instead of having ONE<br>resour= ce collection type, greatly complicates overall design<br>and code-gen aspe= ct.<br><br>In oVirtJS GWT wrapper, we'll avoid above complication through<b= r>single resource collection type (having common methods like<br>get(id), l= ist() etc) for all resources.<br><br>Regards,<br>Vojtech<br>_______________= ________________________________<br>Devel mailing list<br><a ymailto=3D"mai= lto:Devel@ovirt.org" href=3D"mailto:Devel@ovirt.org">Devel@ovirt.org</a><br=
<a href=3D"http://lists.ovirt.org/mailman/listinfo/devel" target=3D"_blank= ">http://lists.ovirt.org/mailman/listinfo/devel</a><br><br><br></div> </di= v> </div> </div> </div> ------=_Part_1859450_1427808343.1417346766163--

On 11/30/2014 12:26 PM, Michael Pasternak wrote:
Hey Vojtech,
How are you?, please see my reply inline.
On Friday, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.com <mailto:vszocs@redhat.com>> wrote:
Hi guys,
since the initial (small, working & well-tested) version of oVirtJS JavaScript SDK is finished [*], I've started working on GWT wrapper for oVirtJS.
While analyzing/reverse-engineering oVirt Java SDK, some thoughts came to my mind, and I wanted to share them with you.
[*] TODO(vszocs) upload new patchset with all recent changes
First, the way XJC (JAXB binding compiler that generates Java beans out of REST XSD schema) is invoked looks a bit weird to me, as Java SDK's XsdCodegen does this:
Runtime.getRuntime().exec(command)
Why not simply use existing Maven plugins to invoke XJC? - either: https://github.com/highsource/maven-jaxb2-plugin <https://github.com/highsource/maven-jaxb2-plugin>
[MP] sdk was using jaxb to begin with, it was replaced with XJC just recently, btw Juan, what was the motivation behind this?
This didn't change, the use of "xjc" is there since commit 95a25a4, Nov 12 2012. Note that using Maven for this isn't as simple as it may look. The development model of the SDK is that the maven build does *not* generate any code, it just builds what has been manually generated previously.
(REST api uses jaxb as well so we used to have 1x1 mappings)
- or: http://mojo.codehaus.org/jaxb2-maven-plugin/ <http://mojo.codehaus.org/jaxb2-maven-plugin/>
[MP] same.
Second, and most importantly, what's the point of having "group" entities? I'll give an example - api.xsd contains this:
<xs:complexType name="DataCenters"> <xs:complexContent> <xs:extension base="BaseResources"> <xs:sequence> <xs:annotation> <xs:appinfo> <jaxb:property name="DataCenters"/> </xs:appinfo> </xs:annotation> <xs:element ref="data_center" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>
(Same as above for Hosts, Clusters, VMs, etc.)
This results in following (IMHO rather meaningless) Java class being generated by XJC:
public class DataCenters extends BaseResources {
@XmlElement(name = "data_center") protected List<DataCenter> dataCenters;
public List<DataCenter> getDataCenters() { if (dataCenters == null) { dataCenters = new ArrayList<DataCenter>(); } return this.dataCenters; }
public boolean isSetDataCenters() { return ((this.dataCenters!= null)&&(!this.dataCenters.isEmpty())); }
public void unsetDataCenters() { this.dataCenters = null; }
}
Instead, we could use @XmlElementWrapper as described in [1] to avoid generating "group" entities altogether.
[1] https://github.com/dmak/jaxb-xew-plugin <https://github.com/dmak/jaxb-xew-plugin>
The fact that Java SDK provides decorator for each specific resource collection (like DataCenters), instead of having ONE resource collection type, greatly complicates overall design and code-gen aspect.
[MP] Well, i guess now is speaking JS constraints ghost, am i right?, in any case, the reasons for having decorator per collection are:
1. compliance with REST API (all SDKs and REST api are sharing same well know architecture) 2. "decorator" is a well known and commonly used java design pattern 3. having one resource type serving all collections would create a bottleneck (well it might depend on how you implementing it, but still in my view it's less convenient/readable than dedicated collection with own context, verbs and behavior),
after all the purpose of sdk is being java client serving application in "Java" way (i.e type-safe + well bounded interface), while JS use-cases & paradigms are totally different, just consider:
[1] java-sdk stile
Disk snapshotDisk = api.getVms().get('my-vm').getSnapshots().get('my-snapshot').getDisks().get('my-disk')
[2] JS style you propose
Disk snapshotDisk = getCollections().get(new Params[] { Disk.class, 'my-vm', 'my-snapshot', 'my-disk'})
notice: =====
in [2] you have a bunch of parameters disconnected form any context where order is *important* (other way you heuristic guesses what user meaning by these params won't work), obviously it's fragile and error prone,
while [1] is readable, well bounded, defending it's consumers from potentials errors (exactly what SDK should look like),
hope it helps.
On Friday, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.com> wrote:
Hi guys,
since the initial (small, working & well-tested) version of oVirtJS JavaScript SDK is finished [*], I've started working on GWT wrapper for oVirtJS.
While analyzing/reverse-engineering oVirt Java SDK, some thoughts came to my mind, and I wanted to share them with you.
[*] TODO(vszocs) upload new patchset with all recent changes
First, the way XJC (JAXB binding compiler that generates Java beans out of REST XSD schema) is invoked looks a bit weird to me, as Java SDK's XsdCodegen does this:
Runtime.getRuntime().exec(command)
Why not simply use existing Maven plugins to invoke XJC? - either: https://github.com/highsource/maven-jaxb2-plugin - or: http://mojo.codehaus.org/jaxb2-maven-plugin/
Second, and most importantly, what's the point of having "group" entities? I'll give an example - api.xsd contains this:
<xs:complexType name="DataCenters"> <xs:complexContent> <xs:extension base="BaseResources"> <xs:sequence> <xs:annotation> <xs:appinfo> <jaxb:property name="DataCenters"/> </xs:appinfo> </xs:annotation> <xs:element ref="data_center" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>
(Same as above for Hosts, Clusters, VMs, etc.)
This results in following (IMHO rather meaningless) Java class being generated by XJC:
public class DataCenters extends BaseResources {
@XmlElement(name = "data_center") protected List<DataCenter> dataCenters;
public List<DataCenter> getDataCenters() { if (dataCenters == null) { dataCenters = new ArrayList<DataCenter>(); } return this.dataCenters; }
public boolean isSetDataCenters() { return ((this.dataCenters!= null)&&(!this.dataCenters.isEmpty())); }
public void unsetDataCenters() { this.dataCenters = null; }
}
Instead, we could use @XmlElementWrapper as described in [1] to avoid generating "group" entities altogether.
[1] https://github.com/dmak/jaxb-xew-plugin
The fact that Java SDK provides decorator for each specific resource collection (like DataCenters), instead of having ONE resource collection type, greatly complicates overall design and code-gen aspect.
In oVirtJS GWT wrapper, we'll avoid above complication through single resource collection type (having common methods like get(id), list() etc) for all resources.
Regards, Vojtech _______________________________________________ Devel mailing list Devel@ovirt.org <mailto:Devel@ovirt.org> http://lists.ovirt.org/mailman/listinfo/devel
-- Dirección Comercial: C/Jose Bardasano Baos, 9, Edif. Gorbea 3, planta 3ºD, 28016 Madrid, Spain Inscrita en el Reg. Mercantil de Madrid – C.I.F. B82657941 - Red Hat S.L.

----- Original Message -----
From: "Juan Hernández" <jhernand@redhat.com> To: "Michael Pasternak" <mishka8520@yahoo.com>, "Vojtech Szocs" <vszocs@redhat.com>, devel@ovirt.org Sent: Monday, December 1, 2014 9:54:51 AM Subject: Re: [ovirt-devel] Some ideas on oVirt Java SDK
On 11/30/2014 12:26 PM, Michael Pasternak wrote:
Hey Vojtech,
How are you?, please see my reply inline.
On Friday, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.com <mailto:vszocs@redhat.com>> wrote:
Hi guys,
since the initial (small, working & well-tested) version of oVirtJS JavaScript SDK is finished [*], I've started working on GWT wrapper for oVirtJS.
While analyzing/reverse-engineering oVirt Java SDK, some thoughts came to my mind, and I wanted to share them with you.
[*] TODO(vszocs) upload new patchset with all recent changes
First, the way XJC (JAXB binding compiler that generates Java beans out of REST XSD schema) is invoked looks a bit weird to me, as Java SDK's XsdCodegen does this:
Runtime.getRuntime().exec(command)
Why not simply use existing Maven plugins to invoke XJC? - either: https://github.com/highsource/maven-jaxb2-plugin <https://github.com/highsource/maven-jaxb2-plugin>
[MP] sdk was using jaxb to begin with, it was replaced with XJC just recently, btw Juan, what was the motivation behind this?
This didn't change, the use of "xjc" is there since commit 95a25a4, Nov 12 2012.
Note that using Maven for this isn't as simple as it may look. The development model of the SDK is that the maven build does *not* generate any code, it just builds what has been manually generated previously.
To clarify, my question was meant for "ovirt-engine-sdk-java-codegen" project and its org.ovirt.engine.sdk.codegen.Main class that produces Java classes out of XSD as part of XsdCodegen.generate() method. But if XsdCodegen invokes XJC programatically, what is the purpose of: org.jvnet.jaxb2.maven2:maven-jaxb22-plugin:generate in "ovirt-engine-sdk-java-codegen" project's pom.xml? Is it related to what XsdCodegen is doing?
(REST api uses jaxb as well so we used to have 1x1 mappings)
- or: http://mojo.codehaus.org/jaxb2-maven-plugin/ <http://mojo.codehaus.org/jaxb2-maven-plugin/>
[MP] same.
Second, and most importantly, what's the point of having "group" entities? I'll give an example - api.xsd contains this:
<xs:complexType name="DataCenters"> <xs:complexContent> <xs:extension base="BaseResources"> <xs:sequence> <xs:annotation> <xs:appinfo> <jaxb:property name="DataCenters"/> </xs:appinfo> </xs:annotation> <xs:element ref="data_center" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>
(Same as above for Hosts, Clusters, VMs, etc.)
This results in following (IMHO rather meaningless) Java class being generated by XJC:
public class DataCenters extends BaseResources {
@XmlElement(name = "data_center") protected List<DataCenter> dataCenters;
public List<DataCenter> getDataCenters() { if (dataCenters == null) { dataCenters = new ArrayList<DataCenter>(); } return this.dataCenters; }
public boolean isSetDataCenters() { return ((this.dataCenters!= null)&&(!this.dataCenters.isEmpty())); }
public void unsetDataCenters() { this.dataCenters = null; }
}
Instead, we could use @XmlElementWrapper as described in [1] to avoid generating "group" entities altogether.
[1] https://github.com/dmak/jaxb-xew-plugin <https://github.com/dmak/jaxb-xew-plugin>
The fact that Java SDK provides decorator for each specific resource collection (like DataCenters), instead of having ONE resource collection type, greatly complicates overall design and code-gen aspect.
[MP] Well, i guess now is speaking JS constraints ghost, am i right?, in any case, the reasons for having decorator per collection are:
1. compliance with REST API (all SDKs and REST api are sharing same well know architecture) 2. "decorator" is a well known and commonly used java design pattern 3. having one resource type serving all collections would create a bottleneck (well it might depend on how you implementing it, but still in my view it's less convenient/readable than dedicated collection with own context, verbs and behavior),
after all the purpose of sdk is being java client serving application in "Java" way (i.e type-safe + well bounded interface), while JS use-cases & paradigms are totally different, just consider:
[1] java-sdk stile
Disk snapshotDisk = api.getVms().get('my-vm').getSnapshots().get('my-snapshot').getDisks().get('my-disk')
[2] JS style you propose
Disk snapshotDisk = getCollections().get(new Params[] { Disk.class, 'my-vm', 'my-snapshot', 'my-disk'})
notice: =====
in [2] you have a bunch of parameters disconnected form any context where order is *important* (other way you heuristic guesses what user meaning by these params won't work), obviously it's fragile and error prone,
while [1] is readable, well bounded, defending it's consumers from potentials errors (exactly what SDK should look like),
hope it helps.
On Friday, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.com> wrote:
Hi guys,
since the initial (small, working & well-tested) version of oVirtJS JavaScript SDK is finished [*], I've started working on GWT wrapper for oVirtJS.
While analyzing/reverse-engineering oVirt Java SDK, some thoughts came to my mind, and I wanted to share them with you.
[*] TODO(vszocs) upload new patchset with all recent changes
First, the way XJC (JAXB binding compiler that generates Java beans out of REST XSD schema) is invoked looks a bit weird to me, as Java SDK's XsdCodegen does this:
Runtime.getRuntime().exec(command)
Why not simply use existing Maven plugins to invoke XJC? - either: https://github.com/highsource/maven-jaxb2-plugin - or: http://mojo.codehaus.org/jaxb2-maven-plugin/
Second, and most importantly, what's the point of having "group" entities? I'll give an example - api.xsd contains this:
<xs:complexType name="DataCenters"> <xs:complexContent> <xs:extension base="BaseResources"> <xs:sequence> <xs:annotation> <xs:appinfo> <jaxb:property name="DataCenters"/> </xs:appinfo> </xs:annotation> <xs:element ref="data_center" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>
(Same as above for Hosts, Clusters, VMs, etc.)
This results in following (IMHO rather meaningless) Java class being generated by XJC:
public class DataCenters extends BaseResources {
@XmlElement(name = "data_center") protected List<DataCenter> dataCenters;
public List<DataCenter> getDataCenters() { if (dataCenters == null) { dataCenters = new ArrayList<DataCenter>(); } return this.dataCenters; }
public boolean isSetDataCenters() { return ((this.dataCenters!= null)&&(!this.dataCenters.isEmpty())); }
public void unsetDataCenters() { this.dataCenters = null; }
}
Instead, we could use @XmlElementWrapper as described in [1] to avoid generating "group" entities altogether.
[1] https://github.com/dmak/jaxb-xew-plugin
The fact that Java SDK provides decorator for each specific resource collection (like DataCenters), instead of having ONE resource collection type, greatly complicates overall design and code-gen aspect.
In oVirtJS GWT wrapper, we'll avoid above complication through single resource collection type (having common methods like get(id), list() etc) for all resources.
Regards, Vojtech _______________________________________________ Devel mailing list Devel@ovirt.org <mailto:Devel@ovirt.org> http://lists.ovirt.org/mailman/listinfo/devel
-- Dirección Comercial: C/Jose Bardasano Baos, 9, Edif. Gorbea 3, planta 3ºD, 28016 Madrid, Spain Inscrita en el Reg. Mercantil de Madrid – C.I.F. B82657941 - Red Hat S.L.

On 12/01/2014 04:13 PM, Vojtech Szocs wrote:
----- Original Message -----
From: "Juan Hernández" <jhernand@redhat.com> To: "Michael Pasternak" <mishka8520@yahoo.com>, "Vojtech Szocs" <vszocs@redhat.com>, devel@ovirt.org Sent: Monday, December 1, 2014 9:54:51 AM Subject: Re: [ovirt-devel] Some ideas on oVirt Java SDK
On 11/30/2014 12:26 PM, Michael Pasternak wrote:
Hey Vojtech,
How are you?, please see my reply inline.
On Friday, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.com <mailto:vszocs@redhat.com>> wrote:
Hi guys,
since the initial (small, working & well-tested) version of oVirtJS JavaScript SDK is finished [*], I've started working on GWT wrapper for oVirtJS.
While analyzing/reverse-engineering oVirt Java SDK, some thoughts came to my mind, and I wanted to share them with you.
[*] TODO(vszocs) upload new patchset with all recent changes
First, the way XJC (JAXB binding compiler that generates Java beans out of REST XSD schema) is invoked looks a bit weird to me, as Java SDK's XsdCodegen does this:
Runtime.getRuntime().exec(command)
Why not simply use existing Maven plugins to invoke XJC? - either: https://github.com/highsource/maven-jaxb2-plugin <https://github.com/highsource/maven-jaxb2-plugin>
[MP] sdk was using jaxb to begin with, it was replaced with XJC just recently, btw Juan, what was the motivation behind this?
This didn't change, the use of "xjc" is there since commit 95a25a4, Nov 12 2012.
Note that using Maven for this isn't as simple as it may look. The development model of the SDK is that the maven build does *not* generate any code, it just builds what has been manually generated previously.
To clarify, my question was meant for "ovirt-engine-sdk-java-codegen" project and its org.ovirt.engine.sdk.codegen.Main class that produces Java classes out of XSD as part of XsdCodegen.generate() method.
But if XsdCodegen invokes XJC programatically, what is the purpose of:
org.jvnet.jaxb2.maven2:maven-jaxb22-plugin:generate
in "ovirt-engine-sdk-java-codegen" project's pom.xml?
Is it related to what XsdCodegen is doing?
The code generator invokes "xjc" directly in order to generate from the XML schema the code that will eventually be part of the generated SDK. In order to do its work it needs to parse the RSDL metadata, and for that it uses JAXB and classes generated from the XML schema. Those classes are generated as part of the build process of the code generator. So the XML schema is converted into Java classes twice: once for the internal use of the generator (during build time of the generator), and another time for the generated SDK (during run time of the generator). This is convenient in order to avoid dependencies between the generator and the SDK.
(REST api uses jaxb as well so we used to have 1x1 mappings)
- or: http://mojo.codehaus.org/jaxb2-maven-plugin/ <http://mojo.codehaus.org/jaxb2-maven-plugin/>
[MP] same.
Second, and most importantly, what's the point of having "group" entities? I'll give an example - api.xsd contains this:
<xs:complexType name="DataCenters"> <xs:complexContent> <xs:extension base="BaseResources"> <xs:sequence> <xs:annotation> <xs:appinfo> <jaxb:property name="DataCenters"/> </xs:appinfo> </xs:annotation> <xs:element ref="data_center" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>
(Same as above for Hosts, Clusters, VMs, etc.)
This results in following (IMHO rather meaningless) Java class being generated by XJC:
public class DataCenters extends BaseResources {
@XmlElement(name = "data_center") protected List<DataCenter> dataCenters;
public List<DataCenter> getDataCenters() { if (dataCenters == null) { dataCenters = new ArrayList<DataCenter>(); } return this.dataCenters; }
public boolean isSetDataCenters() { return ((this.dataCenters!= null)&&(!this.dataCenters.isEmpty())); }
public void unsetDataCenters() { this.dataCenters = null; }
}
Instead, we could use @XmlElementWrapper as described in [1] to avoid generating "group" entities altogether.
[1] https://github.com/dmak/jaxb-xew-plugin <https://github.com/dmak/jaxb-xew-plugin>
The fact that Java SDK provides decorator for each specific resource collection (like DataCenters), instead of having ONE resource collection type, greatly complicates overall design and code-gen aspect.
[MP] Well, i guess now is speaking JS constraints ghost, am i right?, in any case, the reasons for having decorator per collection are:
1. compliance with REST API (all SDKs and REST api are sharing same well know architecture) 2. "decorator" is a well known and commonly used java design pattern 3. having one resource type serving all collections would create a bottleneck (well it might depend on how you implementing it, but still in my view it's less convenient/readable than dedicated collection with own context, verbs and behavior),
after all the purpose of sdk is being java client serving application in "Java" way (i.e type-safe + well bounded interface), while JS use-cases & paradigms are totally different, just consider:
[1] java-sdk stile
Disk snapshotDisk = api.getVms().get('my-vm').getSnapshots().get('my-snapshot').getDisks().get('my-disk')
[2] JS style you propose
Disk snapshotDisk = getCollections().get(new Params[] { Disk.class, 'my-vm', 'my-snapshot', 'my-disk'})
notice: =====
in [2] you have a bunch of parameters disconnected form any context where order is *important* (other way you heuristic guesses what user meaning by these params won't work), obviously it's fragile and error prone,
while [1] is readable, well bounded, defending it's consumers from potentials errors (exactly what SDK should look like),
hope it helps.
On Friday, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.com> wrote:
Hi guys,
since the initial (small, working & well-tested) version of oVirtJS JavaScript SDK is finished [*], I've started working on GWT wrapper for oVirtJS.
While analyzing/reverse-engineering oVirt Java SDK, some thoughts came to my mind, and I wanted to share them with you.
[*] TODO(vszocs) upload new patchset with all recent changes
First, the way XJC (JAXB binding compiler that generates Java beans out of REST XSD schema) is invoked looks a bit weird to me, as Java SDK's XsdCodegen does this:
Runtime.getRuntime().exec(command)
Why not simply use existing Maven plugins to invoke XJC? - either: https://github.com/highsource/maven-jaxb2-plugin - or: http://mojo.codehaus.org/jaxb2-maven-plugin/
Second, and most importantly, what's the point of having "group" entities? I'll give an example - api.xsd contains this:
<xs:complexType name="DataCenters"> <xs:complexContent> <xs:extension base="BaseResources"> <xs:sequence> <xs:annotation> <xs:appinfo> <jaxb:property name="DataCenters"/> </xs:appinfo> </xs:annotation> <xs:element ref="data_center" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>
(Same as above for Hosts, Clusters, VMs, etc.)
This results in following (IMHO rather meaningless) Java class being generated by XJC:
public class DataCenters extends BaseResources {
@XmlElement(name = "data_center") protected List<DataCenter> dataCenters;
public List<DataCenter> getDataCenters() { if (dataCenters == null) { dataCenters = new ArrayList<DataCenter>(); } return this.dataCenters; }
public boolean isSetDataCenters() { return ((this.dataCenters!= null)&&(!this.dataCenters.isEmpty())); }
public void unsetDataCenters() { this.dataCenters = null; }
}
Instead, we could use @XmlElementWrapper as described in [1] to avoid generating "group" entities altogether.
[1] https://github.com/dmak/jaxb-xew-plugin
The fact that Java SDK provides decorator for each specific resource collection (like DataCenters), instead of having ONE resource collection type, greatly complicates overall design and code-gen aspect.
In oVirtJS GWT wrapper, we'll avoid above complication through single resource collection type (having common methods like get(id), list() etc) for all resources.
Regards, Vojtech
-- Dirección Comercial: C/Jose Bardasano Baos, 9, Edif. Gorbea 3, planta 3ºD, 28016 Madrid, Spain Inscrita en el Reg. Mercantil de Madrid – C.I.F. B82657941 - Red Hat S.L.

----- Original Message -----
From: "Juan Hernández" <jhernand@redhat.com> To: "Vojtech Szocs" <vszocs@redhat.com> Cc: devel@ovirt.org Sent: Monday, December 1, 2014 4:24:45 PM Subject: Re: [ovirt-devel] Some ideas on oVirt Java SDK
On 12/01/2014 04:13 PM, Vojtech Szocs wrote:
----- Original Message -----
From: "Juan Hernández" <jhernand@redhat.com> To: "Michael Pasternak" <mishka8520@yahoo.com>, "Vojtech Szocs" <vszocs@redhat.com>, devel@ovirt.org Sent: Monday, December 1, 2014 9:54:51 AM Subject: Re: [ovirt-devel] Some ideas on oVirt Java SDK
On 11/30/2014 12:26 PM, Michael Pasternak wrote:
Hey Vojtech,
How are you?, please see my reply inline.
On Friday, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.com <mailto:vszocs@redhat.com>> wrote:
Hi guys,
since the initial (small, working & well-tested) version of oVirtJS JavaScript SDK is finished [*], I've started working on GWT wrapper for oVirtJS.
While analyzing/reverse-engineering oVirt Java SDK, some thoughts came to my mind, and I wanted to share them with you.
[*] TODO(vszocs) upload new patchset with all recent changes
First, the way XJC (JAXB binding compiler that generates Java beans out of REST XSD schema) is invoked looks a bit weird to me, as Java SDK's XsdCodegen does this:
Runtime.getRuntime().exec(command)
Why not simply use existing Maven plugins to invoke XJC? - either: https://github.com/highsource/maven-jaxb2-plugin <https://github.com/highsource/maven-jaxb2-plugin>
[MP] sdk was using jaxb to begin with, it was replaced with XJC just recently, btw Juan, what was the motivation behind this?
This didn't change, the use of "xjc" is there since commit 95a25a4, Nov 12 2012.
Note that using Maven for this isn't as simple as it may look. The development model of the SDK is that the maven build does *not* generate any code, it just builds what has been manually generated previously.
To clarify, my question was meant for "ovirt-engine-sdk-java-codegen" project and its org.ovirt.engine.sdk.codegen.Main class that produces Java classes out of XSD as part of XsdCodegen.generate() method.
But if XsdCodegen invokes XJC programatically, what is the purpose of:
org.jvnet.jaxb2.maven2:maven-jaxb22-plugin:generate
in "ovirt-engine-sdk-java-codegen" project's pom.xml?
Is it related to what XsdCodegen is doing?
The code generator invokes "xjc" directly in order to generate from the XML schema the code that will eventually be part of the generated SDK. In order to do its work it needs to parse the RSDL metadata, and for that it uses JAXB and classes generated from the XML schema. Those classes are generated as part of the build process of the code generator. So the XML schema is converted into Java classes twice: once for the internal use of the generator (during build time of the generator), and another time for the generated SDK (during run time of the generator). This is convenient in order to avoid dependencies between the generator and the SDK.
Thanks for clarification. IMHO calling XJC just to generate JAXB code that parses RSDL data is an overkill. In oVirtJS GWT wrapper project, I'm parsing RSDL as XML file directly. Conceptually, RSDL definition shouldn't even be inside api.xsd: <xs:element name="rsdl" type="RSDL"/> Above ^^ is unrelated to REST entity schema, it describes RSDL schema. It's inside api.xsd just to parse RSDL via JAXB. Entity schema and RSDL schema are two separate things. I suggest to split above into separate file, i.e. rsdl.xsd and reference shared types (like "Version") from api.xsd. This would be the proper separation these two schemas.
(REST api uses jaxb as well so we used to have 1x1 mappings)
- or: http://mojo.codehaus.org/jaxb2-maven-plugin/ <http://mojo.codehaus.org/jaxb2-maven-plugin/>
[MP] same.
Second, and most importantly, what's the point of having "group" entities? I'll give an example - api.xsd contains this:
<xs:complexType name="DataCenters"> <xs:complexContent> <xs:extension base="BaseResources"> <xs:sequence> <xs:annotation> <xs:appinfo> <jaxb:property name="DataCenters"/> </xs:appinfo> </xs:annotation> <xs:element ref="data_center" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>
(Same as above for Hosts, Clusters, VMs, etc.)
This results in following (IMHO rather meaningless) Java class being generated by XJC:
public class DataCenters extends BaseResources {
@XmlElement(name = "data_center") protected List<DataCenter> dataCenters;
public List<DataCenter> getDataCenters() { if (dataCenters == null) { dataCenters = new ArrayList<DataCenter>(); } return this.dataCenters; }
public boolean isSetDataCenters() { return ((this.dataCenters!= null)&&(!this.dataCenters.isEmpty())); }
public void unsetDataCenters() { this.dataCenters = null; }
}
Instead, we could use @XmlElementWrapper as described in [1] to avoid generating "group" entities altogether.
[1] https://github.com/dmak/jaxb-xew-plugin <https://github.com/dmak/jaxb-xew-plugin>
The fact that Java SDK provides decorator for each specific resource collection (like DataCenters), instead of having ONE resource collection type, greatly complicates overall design and code-gen aspect.
[MP] Well, i guess now is speaking JS constraints ghost, am i right?, in any case, the reasons for having decorator per collection are:
1. compliance with REST API (all SDKs and REST api are sharing same well know architecture) 2. "decorator" is a well known and commonly used java design pattern 3. having one resource type serving all collections would create a bottleneck (well it might depend on how you implementing it, but still in my view it's less convenient/readable than dedicated collection with own context, verbs and behavior),
after all the purpose of sdk is being java client serving application in "Java" way (i.e type-safe + well bounded interface), while JS use-cases & paradigms are totally different, just consider:
[1] java-sdk stile
Disk snapshotDisk = api.getVms().get('my-vm').getSnapshots().get('my-snapshot').getDisks().get('my-disk')
[2] JS style you propose
Disk snapshotDisk = getCollections().get(new Params[] { Disk.class, 'my-vm', 'my-snapshot', 'my-disk'})
notice: =====
in [2] you have a bunch of parameters disconnected form any context where order is *important* (other way you heuristic guesses what user meaning by these params won't work), obviously it's fragile and error prone,
while [1] is readable, well bounded, defending it's consumers from potentials errors (exactly what SDK should look like),
hope it helps.
On Friday, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.com> wrote:
Hi guys,
since the initial (small, working & well-tested) version of oVirtJS JavaScript SDK is finished [*], I've started working on GWT wrapper for oVirtJS.
While analyzing/reverse-engineering oVirt Java SDK, some thoughts came to my mind, and I wanted to share them with you.
[*] TODO(vszocs) upload new patchset with all recent changes
First, the way XJC (JAXB binding compiler that generates Java beans out of REST XSD schema) is invoked looks a bit weird to me, as Java SDK's XsdCodegen does this:
Runtime.getRuntime().exec(command)
Why not simply use existing Maven plugins to invoke XJC? - either: https://github.com/highsource/maven-jaxb2-plugin - or: http://mojo.codehaus.org/jaxb2-maven-plugin/
Second, and most importantly, what's the point of having "group" entities? I'll give an example - api.xsd contains this:
<xs:complexType name="DataCenters"> <xs:complexContent> <xs:extension base="BaseResources"> <xs:sequence> <xs:annotation> <xs:appinfo> <jaxb:property name="DataCenters"/> </xs:appinfo> </xs:annotation> <xs:element ref="data_center" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>
(Same as above for Hosts, Clusters, VMs, etc.)
This results in following (IMHO rather meaningless) Java class being generated by XJC:
public class DataCenters extends BaseResources {
@XmlElement(name = "data_center") protected List<DataCenter> dataCenters;
public List<DataCenter> getDataCenters() { if (dataCenters == null) { dataCenters = new ArrayList<DataCenter>(); } return this.dataCenters; }
public boolean isSetDataCenters() { return ((this.dataCenters!= null)&&(!this.dataCenters.isEmpty())); }
public void unsetDataCenters() { this.dataCenters = null; }
}
Instead, we could use @XmlElementWrapper as described in [1] to avoid generating "group" entities altogether.
[1] https://github.com/dmak/jaxb-xew-plugin
The fact that Java SDK provides decorator for each specific resource collection (like DataCenters), instead of having ONE resource collection type, greatly complicates overall design and code-gen aspect.
In oVirtJS GWT wrapper, we'll avoid above complication through single resource collection type (having common methods like get(id), list() etc) for all resources.
Regards, Vojtech
-- Dirección Comercial: C/Jose Bardasano Baos, 9, Edif. Gorbea 3, planta 3ºD, 28016 Madrid, Spain Inscrita en el Reg. Mercantil de Madrid – C.I.F. B82657941 - Red Hat S.L.

On 12/01/2014 06:36 PM, Vojtech Szocs wrote:
----- Original Message -----
From: "Juan Hernández" <jhernand@redhat.com> To: "Vojtech Szocs" <vszocs@redhat.com> Cc: devel@ovirt.org Sent: Monday, December 1, 2014 4:24:45 PM Subject: Re: [ovirt-devel] Some ideas on oVirt Java SDK
On 12/01/2014 04:13 PM, Vojtech Szocs wrote:
----- Original Message -----
From: "Juan Hernández" <jhernand@redhat.com> To: "Michael Pasternak" <mishka8520@yahoo.com>, "Vojtech Szocs" <vszocs@redhat.com>, devel@ovirt.org Sent: Monday, December 1, 2014 9:54:51 AM Subject: Re: [ovirt-devel] Some ideas on oVirt Java SDK
On 11/30/2014 12:26 PM, Michael Pasternak wrote:
Hey Vojtech,
How are you?, please see my reply inline.
On Friday, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.com <mailto:vszocs@redhat.com>> wrote:
Hi guys,
since the initial (small, working & well-tested) version of oVirtJS JavaScript SDK is finished [*], I've started working on GWT wrapper for oVirtJS.
While analyzing/reverse-engineering oVirt Java SDK, some thoughts came to my mind, and I wanted to share them with you.
[*] TODO(vszocs) upload new patchset with all recent changes
First, the way XJC (JAXB binding compiler that generates Java beans out of REST XSD schema) is invoked looks a bit weird to me, as Java SDK's XsdCodegen does this:
Runtime.getRuntime().exec(command)
Why not simply use existing Maven plugins to invoke XJC? - either: https://github.com/highsource/maven-jaxb2-plugin <https://github.com/highsource/maven-jaxb2-plugin>
[MP] sdk was using jaxb to begin with, it was replaced with XJC just recently, btw Juan, what was the motivation behind this?
This didn't change, the use of "xjc" is there since commit 95a25a4, Nov 12 2012.
Note that using Maven for this isn't as simple as it may look. The development model of the SDK is that the maven build does *not* generate any code, it just builds what has been manually generated previously.
To clarify, my question was meant for "ovirt-engine-sdk-java-codegen" project and its org.ovirt.engine.sdk.codegen.Main class that produces Java classes out of XSD as part of XsdCodegen.generate() method.
But if XsdCodegen invokes XJC programatically, what is the purpose of:
org.jvnet.jaxb2.maven2:maven-jaxb22-plugin:generate
in "ovirt-engine-sdk-java-codegen" project's pom.xml?
Is it related to what XsdCodegen is doing?
The code generator invokes "xjc" directly in order to generate from the XML schema the code that will eventually be part of the generated SDK. In order to do its work it needs to parse the RSDL metadata, and for that it uses JAXB and classes generated from the XML schema. Those classes are generated as part of the build process of the code generator. So the XML schema is converted into Java classes twice: once for the internal use of the generator (during build time of the generator), and another time for the generated SDK (during run time of the generator). This is convenient in order to avoid dependencies between the generator and the SDK.
Thanks for clarification.
IMHO calling XJC just to generate JAXB code that parses RSDL data is an overkill. In oVirtJS GWT wrapper project, I'm parsing RSDL as XML file directly.
The "xjc" compiler isn't called directly to generate the code to parse RSDL, it is called to generate the code of the SDK. The code that the generator uses internally is generated using the Maven plugin (which in turn calls "xjc"). We could argue about the convenience of using JAXB or manually parsing the RSDL, but it won't take us anywhere. If you find it convenient parsing it directly just do it.
Conceptually, RSDL definition shouldn't even be inside api.xsd:
<xs:element name="rsdl" type="RSDL"/>
Above ^^ is unrelated to REST entity schema, it describes RSDL schema. It's inside api.xsd just to parse RSDL via JAXB. Entity schema and RSDL schema are two separate things.
I suggest to split above into separate file, i.e. rsdl.xsd and reference shared types (like "Version") from api.xsd. This would be the proper separation these two schemas.
The RSDL is just one resource offered by the RESTAPI, like a VM or a host. It supports multiple formats (XML, JSON, etc) and it is consumed by clients. So its entities, like any other entity, must be described in the XML schema. We only have one XML schema, and we can split it as it would break backwards compatibility.
(REST api uses jaxb as well so we used to have 1x1 mappings)
- or: http://mojo.codehaus.org/jaxb2-maven-plugin/ <http://mojo.codehaus.org/jaxb2-maven-plugin/>
[MP] same.
Second, and most importantly, what's the point of having "group" entities? I'll give an example - api.xsd contains this:
<xs:complexType name="DataCenters"> <xs:complexContent> <xs:extension base="BaseResources"> <xs:sequence> <xs:annotation> <xs:appinfo> <jaxb:property name="DataCenters"/> </xs:appinfo> </xs:annotation> <xs:element ref="data_center" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>
(Same as above for Hosts, Clusters, VMs, etc.)
This results in following (IMHO rather meaningless) Java class being generated by XJC:
public class DataCenters extends BaseResources {
@XmlElement(name = "data_center") protected List<DataCenter> dataCenters;
public List<DataCenter> getDataCenters() { if (dataCenters == null) { dataCenters = new ArrayList<DataCenter>(); } return this.dataCenters; }
public boolean isSetDataCenters() { return ((this.dataCenters!= null)&&(!this.dataCenters.isEmpty())); }
public void unsetDataCenters() { this.dataCenters = null; }
}
Instead, we could use @XmlElementWrapper as described in [1] to avoid generating "group" entities altogether.
[1] https://github.com/dmak/jaxb-xew-plugin <https://github.com/dmak/jaxb-xew-plugin>
The fact that Java SDK provides decorator for each specific resource collection (like DataCenters), instead of having ONE resource collection type, greatly complicates overall design and code-gen aspect.
[MP] Well, i guess now is speaking JS constraints ghost, am i right?, in any case, the reasons for having decorator per collection are:
1. compliance with REST API (all SDKs and REST api are sharing same well know architecture) 2. "decorator" is a well known and commonly used java design pattern 3. having one resource type serving all collections would create a bottleneck (well it might depend on how you implementing it, but still in my view it's less convenient/readable than dedicated collection with own context, verbs and behavior),
after all the purpose of sdk is being java client serving application in "Java" way (i.e type-safe + well bounded interface), while JS use-cases & paradigms are totally different, just consider:
[1] java-sdk stile
Disk snapshotDisk = api.getVms().get('my-vm').getSnapshots().get('my-snapshot').getDisks().get('my-disk')
[2] JS style you propose
Disk snapshotDisk = getCollections().get(new Params[] { Disk.class, 'my-vm', 'my-snapshot', 'my-disk'})
notice: =====
in [2] you have a bunch of parameters disconnected form any context where order is *important* (other way you heuristic guesses what user meaning by these params won't work), obviously it's fragile and error prone,
while [1] is readable, well bounded, defending it's consumers from potentials errors (exactly what SDK should look like),
hope it helps.
On Friday, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.com> wrote:
Hi guys,
since the initial (small, working & well-tested) version of oVirtJS JavaScript SDK is finished [*], I've started working on GWT wrapper for oVirtJS.
While analyzing/reverse-engineering oVirt Java SDK, some thoughts came to my mind, and I wanted to share them with you.
[*] TODO(vszocs) upload new patchset with all recent changes
First, the way XJC (JAXB binding compiler that generates Java beans out of REST XSD schema) is invoked looks a bit weird to me, as Java SDK's XsdCodegen does this:
Runtime.getRuntime().exec(command)
Why not simply use existing Maven plugins to invoke XJC? - either: https://github.com/highsource/maven-jaxb2-plugin - or: http://mojo.codehaus.org/jaxb2-maven-plugin/
Second, and most importantly, what's the point of having "group" entities? I'll give an example - api.xsd contains this:
<xs:complexType name="DataCenters"> <xs:complexContent> <xs:extension base="BaseResources"> <xs:sequence> <xs:annotation> <xs:appinfo> <jaxb:property name="DataCenters"/> </xs:appinfo> </xs:annotation> <xs:element ref="data_center" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>
(Same as above for Hosts, Clusters, VMs, etc.)
This results in following (IMHO rather meaningless) Java class being generated by XJC:
public class DataCenters extends BaseResources {
@XmlElement(name = "data_center") protected List<DataCenter> dataCenters;
public List<DataCenter> getDataCenters() { if (dataCenters == null) { dataCenters = new ArrayList<DataCenter>(); } return this.dataCenters; }
public boolean isSetDataCenters() { return ((this.dataCenters!= null)&&(!this.dataCenters.isEmpty())); }
public void unsetDataCenters() { this.dataCenters = null; }
}
Instead, we could use @XmlElementWrapper as described in [1] to avoid generating "group" entities altogether.
[1] https://github.com/dmak/jaxb-xew-plugin
The fact that Java SDK provides decorator for each specific resource collection (like DataCenters), instead of having ONE resource collection type, greatly complicates overall design and code-gen aspect.
In oVirtJS GWT wrapper, we'll avoid above complication through single resource collection type (having common methods like get(id), list() etc) for all resources.
Regards, Vojtech
-- Dirección Comercial: C/Jose Bardasano Baos, 9, Edif. Gorbea 3, planta 3ºD, 28016 Madrid, Spain Inscrita en el Reg. Mercantil de Madrid – C.I.F. B82657941 - Red Hat S.L.

----- Original Message -----
From: "Juan Hernández" <jhernand@redhat.com> To: "Vojtech Szocs" <vszocs@redhat.com> Cc: devel@ovirt.org, "Michael Pasternak" <mishka8520@yahoo.com> Sent: Tuesday, December 2, 2014 10:02:36 AM Subject: Re: [ovirt-devel] Some ideas on oVirt Java SDK
On 12/01/2014 06:36 PM, Vojtech Szocs wrote:
----- Original Message -----
From: "Juan Hernández" <jhernand@redhat.com> To: "Vojtech Szocs" <vszocs@redhat.com> Cc: devel@ovirt.org Sent: Monday, December 1, 2014 4:24:45 PM Subject: Re: [ovirt-devel] Some ideas on oVirt Java SDK
On 12/01/2014 04:13 PM, Vojtech Szocs wrote:
----- Original Message -----
From: "Juan Hernández" <jhernand@redhat.com> To: "Michael Pasternak" <mishka8520@yahoo.com>, "Vojtech Szocs" <vszocs@redhat.com>, devel@ovirt.org Sent: Monday, December 1, 2014 9:54:51 AM Subject: Re: [ovirt-devel] Some ideas on oVirt Java SDK
On 11/30/2014 12:26 PM, Michael Pasternak wrote:
Hey Vojtech,
How are you?, please see my reply inline.
On Friday, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.com <mailto:vszocs@redhat.com>> wrote:
Hi guys,
since the initial (small, working & well-tested) version of oVirtJS JavaScript SDK is finished [*], I've started working on GWT wrapper for oVirtJS.
While analyzing/reverse-engineering oVirt Java SDK, some thoughts came to my mind, and I wanted to share them with you.
[*] TODO(vszocs) upload new patchset with all recent changes
First, the way XJC (JAXB binding compiler that generates Java beans out of REST XSD schema) is invoked looks a bit weird to me, as Java SDK's XsdCodegen does this:
Runtime.getRuntime().exec(command)
Why not simply use existing Maven plugins to invoke XJC? - either: https://github.com/highsource/maven-jaxb2-plugin <https://github.com/highsource/maven-jaxb2-plugin>
[MP] sdk was using jaxb to begin with, it was replaced with XJC just recently, btw Juan, what was the motivation behind this?
This didn't change, the use of "xjc" is there since commit 95a25a4, Nov 12 2012.
Note that using Maven for this isn't as simple as it may look. The development model of the SDK is that the maven build does *not* generate any code, it just builds what has been manually generated previously.
To clarify, my question was meant for "ovirt-engine-sdk-java-codegen" project and its org.ovirt.engine.sdk.codegen.Main class that produces Java classes out of XSD as part of XsdCodegen.generate() method.
But if XsdCodegen invokes XJC programatically, what is the purpose of:
org.jvnet.jaxb2.maven2:maven-jaxb22-plugin:generate
in "ovirt-engine-sdk-java-codegen" project's pom.xml?
Is it related to what XsdCodegen is doing?
The code generator invokes "xjc" directly in order to generate from the XML schema the code that will eventually be part of the generated SDK. In order to do its work it needs to parse the RSDL metadata, and for that it uses JAXB and classes generated from the XML schema. Those classes are generated as part of the build process of the code generator. So the XML schema is converted into Java classes twice: once for the internal use of the generator (during build time of the generator), and another time for the generated SDK (during run time of the generator). This is convenient in order to avoid dependencies between the generator and the SDK.
Thanks for clarification.
IMHO calling XJC just to generate JAXB code that parses RSDL data is an overkill. In oVirtJS GWT wrapper project, I'm parsing RSDL as XML file directly.
The "xjc" compiler isn't called directly to generate the code to parse RSDL, it is called to generate the code of the SDK.
Yes, that's what XsdCodegen is doing.
The code that the generator uses internally is generated using the Maven plugin (which in turn calls "xjc").
Yes, that's what maven-jaxb22-plugin is doing in ovirt-engine-sdk-java-codegen/pom.xml file.
We could argue about the convenience of using JAXB or manually parsing the RSDL, but it won't take us anywhere. If you find it convenient parsing it directly just do it.
Conceptually, RSDL definition shouldn't even be inside api.xsd:
<xs:element name="rsdl" type="RSDL"/>
Above ^^ is unrelated to REST entity schema, it describes RSDL schema. It's inside api.xsd just to parse RSDL via JAXB. Entity schema and RSDL schema are two separate things.
I suggest to split above into separate file, i.e. rsdl.xsd and reference shared types (like "Version") from api.xsd. This would be the proper separation these two schemas.
The RSDL is just one resource offered by the RESTAPI, like a VM or a host. It supports multiple formats (XML, JSON, etc) and it is consumed by clients. So its entities, like any other entity, must be described in the XML schema. We only have one XML schema, and we can split it as it would break backwards compatibility.
In my opinion, VM/host/etc. are resources representing business entities, while RSDL is a description (meta-data) of all operations (essentially links) supported on these entities. It makes sense to HTTP GET/POST/etc. a VM/host/etc. but it doesn't make sense to do that for RSDL. RSDL (as defined in api.xsd) isn't a proper resource from REST API point of view, in my opinion. In api.xsd I don't see any entity-specific type utilize RSDL type. Therefore I assume that RSDL in api.xsd just serves the purpose of having the convenience to utilize JAXB RI to parse RSDL XML file. Ideally, there would be two files: - api.xsd (without RSDL type) - rsdl.xsd -> containing <xs:element name="rsdl" type="RSDL"/> and related stuff During XJC execution both XSD files above would be passed, current behavior would be preserved. This is what I proposed in my previous email. However, I'm not REST API maintainer so this was just a suggestion that I wanted to elaborate on.
(REST api uses jaxb as well so we used to have 1x1 mappings)
- or: http://mojo.codehaus.org/jaxb2-maven-plugin/ <http://mojo.codehaus.org/jaxb2-maven-plugin/>
[MP] same.
Second, and most importantly, what's the point of having "group" entities? I'll give an example - api.xsd contains this:
<xs:complexType name="DataCenters"> <xs:complexContent> <xs:extension base="BaseResources"> <xs:sequence> <xs:annotation> <xs:appinfo> <jaxb:property name="DataCenters"/> </xs:appinfo> </xs:annotation> <xs:element ref="data_center" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>
(Same as above for Hosts, Clusters, VMs, etc.)
This results in following (IMHO rather meaningless) Java class being generated by XJC:
public class DataCenters extends BaseResources {
@XmlElement(name = "data_center") protected List<DataCenter> dataCenters;
public List<DataCenter> getDataCenters() { if (dataCenters == null) { dataCenters = new ArrayList<DataCenter>(); } return this.dataCenters; }
public boolean isSetDataCenters() { return ((this.dataCenters!= null)&&(!this.dataCenters.isEmpty())); }
public void unsetDataCenters() { this.dataCenters = null; }
}
Instead, we could use @XmlElementWrapper as described in [1] to avoid generating "group" entities altogether.
[1] https://github.com/dmak/jaxb-xew-plugin <https://github.com/dmak/jaxb-xew-plugin>
The fact that Java SDK provides decorator for each specific resource collection (like DataCenters), instead of having ONE resource collection type, greatly complicates overall design and code-gen aspect.
[MP] Well, i guess now is speaking JS constraints ghost, am i right?, in any case, the reasons for having decorator per collection are:
1. compliance with REST API (all SDKs and REST api are sharing same well know architecture) 2. "decorator" is a well known and commonly used java design pattern 3. having one resource type serving all collections would create a bottleneck (well it might depend on how you implementing it, but still in my view it's less convenient/readable than dedicated collection with own context, verbs and behavior),
after all the purpose of sdk is being java client serving application in "Java" way (i.e type-safe + well bounded interface), while JS use-cases & paradigms are totally different, just consider:
[1] java-sdk stile
Disk snapshotDisk = api.getVms().get('my-vm').getSnapshots().get('my-snapshot').getDisks().get('my-disk')
[2] JS style you propose
Disk snapshotDisk = getCollections().get(new Params[] { Disk.class, 'my-vm', 'my-snapshot', 'my-disk'})
notice: =====
in [2] you have a bunch of parameters disconnected form any context where order is *important* (other way you heuristic guesses what user meaning by these params won't work), obviously it's fragile and error prone,
while [1] is readable, well bounded, defending it's consumers from potentials errors (exactly what SDK should look like),
hope it helps.
On Friday, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.com> wrote:
Hi guys,
since the initial (small, working & well-tested) version of oVirtJS JavaScript SDK is finished [*], I've started working on GWT wrapper for oVirtJS.
While analyzing/reverse-engineering oVirt Java SDK, some thoughts came to my mind, and I wanted to share them with you.
[*] TODO(vszocs) upload new patchset with all recent changes
First, the way XJC (JAXB binding compiler that generates Java beans out of REST XSD schema) is invoked looks a bit weird to me, as Java SDK's XsdCodegen does this:
Runtime.getRuntime().exec(command)
Why not simply use existing Maven plugins to invoke XJC? - either: https://github.com/highsource/maven-jaxb2-plugin - or: http://mojo.codehaus.org/jaxb2-maven-plugin/
Second, and most importantly, what's the point of having "group" entities? I'll give an example - api.xsd contains this:
<xs:complexType name="DataCenters"> <xs:complexContent> <xs:extension base="BaseResources"> <xs:sequence> <xs:annotation> <xs:appinfo> <jaxb:property name="DataCenters"/> </xs:appinfo> </xs:annotation> <xs:element ref="data_center" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>
(Same as above for Hosts, Clusters, VMs, etc.)
This results in following (IMHO rather meaningless) Java class being generated by XJC:
public class DataCenters extends BaseResources {
@XmlElement(name = "data_center") protected List<DataCenter> dataCenters;
public List<DataCenter> getDataCenters() { if (dataCenters == null) { dataCenters = new ArrayList<DataCenter>(); } return this.dataCenters; }
public boolean isSetDataCenters() { return ((this.dataCenters!= null)&&(!this.dataCenters.isEmpty())); }
public void unsetDataCenters() { this.dataCenters = null; }
}
Instead, we could use @XmlElementWrapper as described in [1] to avoid generating "group" entities altogether.
[1] https://github.com/dmak/jaxb-xew-plugin
The fact that Java SDK provides decorator for each specific resource collection (like DataCenters), instead of having ONE resource collection type, greatly complicates overall design and code-gen aspect.
In oVirtJS GWT wrapper, we'll avoid above complication through single resource collection type (having common methods like get(id), list() etc) for all resources.
Regards, Vojtech
-- Dirección Comercial: C/Jose Bardasano Baos, 9, Edif. Gorbea 3, planta 3ºD, 28016 Madrid, Spain Inscrita en el Reg. Mercantil de Madrid – C.I.F. B82657941 - Red Hat S.L.

On 12/02/2014 06:29 PM, Vojtech Szocs wrote:
----- Original Message -----
From: "Juan Hernández" <jhernand@redhat.com> To: "Vojtech Szocs" <vszocs@redhat.com> Cc: devel@ovirt.org, "Michael Pasternak" <mishka8520@yahoo.com> Sent: Tuesday, December 2, 2014 10:02:36 AM Subject: Re: [ovirt-devel] Some ideas on oVirt Java SDK
On 12/01/2014 06:36 PM, Vojtech Szocs wrote:
----- Original Message -----
From: "Juan Hernández" <jhernand@redhat.com> To: "Vojtech Szocs" <vszocs@redhat.com> Cc: devel@ovirt.org Sent: Monday, December 1, 2014 4:24:45 PM Subject: Re: [ovirt-devel] Some ideas on oVirt Java SDK
On 12/01/2014 04:13 PM, Vojtech Szocs wrote:
----- Original Message -----
From: "Juan Hernández" <jhernand@redhat.com> To: "Michael Pasternak" <mishka8520@yahoo.com>, "Vojtech Szocs" <vszocs@redhat.com>, devel@ovirt.org Sent: Monday, December 1, 2014 9:54:51 AM Subject: Re: [ovirt-devel] Some ideas on oVirt Java SDK
On 11/30/2014 12:26 PM, Michael Pasternak wrote: > Hey Vojtech, > > How are you?, please see my reply inline. > > > > On Friday, November 28, 2014 5:26 PM, Vojtech Szocs > <vszocs@redhat.com <mailto:vszocs@redhat.com>> wrote: > > > Hi guys, > > since the initial (small, working & well-tested) version of oVirtJS > JavaScript SDK is finished [*], I've started working on GWT wrapper > for oVirtJS. > > While analyzing/reverse-engineering oVirt Java SDK, some thoughts > came to my mind, and I wanted to share them with you. > > [*] TODO(vszocs) upload new patchset with all recent changes > > First, the way XJC (JAXB binding compiler that generates Java beans > out of REST XSD schema) is invoked looks a bit weird to me, as Java > SDK's XsdCodegen does this: > > Runtime.getRuntime().exec(command) > > Why not simply use existing Maven plugins to invoke XJC? > - either: https://github.com/highsource/maven-jaxb2-plugin > <https://github.com/highsource/maven-jaxb2-plugin> > > > [MP] sdk was using jaxb to begin with, it was replaced with XJC just > recently, > btw Juan, what was the motivation behind this?
This didn't change, the use of "xjc" is there since commit 95a25a4, Nov 12 2012.
Note that using Maven for this isn't as simple as it may look. The development model of the SDK is that the maven build does *not* generate any code, it just builds what has been manually generated previously.
To clarify, my question was meant for "ovirt-engine-sdk-java-codegen" project and its org.ovirt.engine.sdk.codegen.Main class that produces Java classes out of XSD as part of XsdCodegen.generate() method.
But if XsdCodegen invokes XJC programatically, what is the purpose of:
org.jvnet.jaxb2.maven2:maven-jaxb22-plugin:generate
in "ovirt-engine-sdk-java-codegen" project's pom.xml?
Is it related to what XsdCodegen is doing?
The code generator invokes "xjc" directly in order to generate from the XML schema the code that will eventually be part of the generated SDK. In order to do its work it needs to parse the RSDL metadata, and for that it uses JAXB and classes generated from the XML schema. Those classes are generated as part of the build process of the code generator. So the XML schema is converted into Java classes twice: once for the internal use of the generator (during build time of the generator), and another time for the generated SDK (during run time of the generator). This is convenient in order to avoid dependencies between the generator and the SDK.
Thanks for clarification.
IMHO calling XJC just to generate JAXB code that parses RSDL data is an overkill. In oVirtJS GWT wrapper project, I'm parsing RSDL as XML file directly.
The "xjc" compiler isn't called directly to generate the code to parse RSDL, it is called to generate the code of the SDK.
Yes, that's what XsdCodegen is doing.
The code that the generator uses internally is generated using the Maven plugin (which in turn calls "xjc").
Yes, that's what maven-jaxb22-plugin is doing in ovirt-engine-sdk-java-codegen/pom.xml file.
We could argue about the convenience of using JAXB or manually parsing the RSDL, but it won't take us anywhere. If you find it convenient parsing it directly just do it.
Conceptually, RSDL definition shouldn't even be inside api.xsd:
<xs:element name="rsdl" type="RSDL"/>
Above ^^ is unrelated to REST entity schema, it describes RSDL schema. It's inside api.xsd just to parse RSDL via JAXB. Entity schema and RSDL schema are two separate things.
I suggest to split above into separate file, i.e. rsdl.xsd and reference shared types (like "Version") from api.xsd. This would be the proper separation these two schemas.
The RSDL is just one resource offered by the RESTAPI, like a VM or a host. It supports multiple formats (XML, JSON, etc) and it is consumed by clients. So its entities, like any other entity, must be described in the XML schema. We only have one XML schema, and we can split it as it would break backwards compatibility.
In my opinion, VM/host/etc. are resources representing business entities, while RSDL is a description (meta-data) of all operations (essentially links) supported on these entities.
It makes sense to HTTP GET/POST/etc. a VM/host/etc. but it doesn't make sense to do that for RSDL. RSDL (as defined in api.xsd) isn't a proper resource from REST API point of view, in my opinion.
In api.xsd I don't see any entity-specific type utilize RSDL type. Therefore I assume that RSDL in api.xsd just serves the purpose of having the convenience to utilize JAXB RI to parse RSDL XML file.
Ideally, there would be two files: - api.xsd (without RSDL type) - rsdl.xsd -> containing <xs:element name="rsdl" type="RSDL"/> and related stuff
During XJC execution both XSD files above would be passed, current behavior would be preserved. This is what I proposed in my previous email. However, I'm not REST API maintainer so this was just a suggestion that I wanted to elaborate on.
The RSDL and the XML schema are part of the contract of the RESTAPI, and as such they can't be changed in the way you suggest as that would break backwards compatibility.
> (REST api uses jaxb as well so we used to have 1x1 mappings) > > > - or: http://mojo.codehaus.org/jaxb2-maven-plugin/ > <http://mojo.codehaus.org/jaxb2-maven-plugin/> > > > [MP] same. > > > Second, and most importantly, what's the point of having "group" > entities? I'll give an example - api.xsd contains this: > > <xs:complexType name="DataCenters"> > <xs:complexContent> > <xs:extension base="BaseResources"> > <xs:sequence> > <xs:annotation> > <xs:appinfo> > <jaxb:property name="DataCenters"/> > </xs:appinfo> > </xs:annotation> > <xs:element ref="data_center" minOccurs="0" > maxOccurs="unbounded"/> > </xs:sequence> > </xs:extension> > </xs:complexContent> > </xs:complexType> > > (Same as above for Hosts, Clusters, VMs, etc.) > > This results in following (IMHO rather meaningless) Java class > being generated by XJC: > > public class DataCenters extends BaseResources { > > @XmlElement(name = "data_center") > protected List<DataCenter> dataCenters; > > public List<DataCenter> getDataCenters() { > if (dataCenters == null) { > dataCenters = new ArrayList<DataCenter>(); > } > return this.dataCenters; > } > > public boolean isSetDataCenters() { > return ((this.dataCenters!= > null)&&(!this.dataCenters.isEmpty())); > } > > public void unsetDataCenters() { > this.dataCenters = null; > } > > } > > Instead, we could use @XmlElementWrapper as described in [1] > to avoid generating "group" entities altogether. > > [1] https://github.com/dmak/jaxb-xew-plugin > <https://github.com/dmak/jaxb-xew-plugin> > > The fact that Java SDK provides decorator for each specific > resource collection (like DataCenters), instead of having ONE > resource collection type, greatly complicates overall design > and code-gen aspect. > > > [MP] Well, i guess now is speaking JS constraints ghost, am i right?, > in any case, the reasons for having decorator per collection are: > > 1. compliance with REST API (all SDKs and REST api are sharing same > well > know architecture) > 2. "decorator" is a well known and commonly used java design pattern > 3. having one resource type serving all collections would create a > bottleneck > (well it might depend on how you implementing it, but still in my view > it's less convenient/readable > than dedicated collection with own context, verbs and behavior), > > after all the purpose of sdk is being java client serving application > in > "Java" way > (i.e type-safe + well bounded interface), while JS use-cases & > paradigms > are totally > different, just consider: > > [1] java-sdk stile > > Disk snapshotDisk = > api.getVms().get('my-vm').getSnapshots().get('my-snapshot').getDisks().get('my-disk') > > [2] JS style you propose > > Disk snapshotDisk = getCollections().get(new Params[] { Disk.class, > 'my-vm', 'my-snapshot', 'my-disk'}) > > notice: > ===== > > in [2] you have a bunch of parameters disconnected form any context > where order > is *important* (other way you heuristic guesses what user meaning by > these params won't work), > obviously it's fragile and error prone, > > while [1] is readable, well bounded, defending it's consumers from > potentials errors > (exactly what SDK should look like), > > hope it helps. > > > > > > > On Friday, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.com> > wrote: > > > Hi guys, > > since the initial (small, working & well-tested) version of oVirtJS > JavaScript SDK is finished [*], I've started working on GWT wrapper > for oVirtJS. > > While analyzing/reverse-engineering oVirt Java SDK, some thoughts > came to my mind, and I wanted to share them with you. > > [*] TODO(vszocs) upload new patchset with all recent changes > > First, the way XJC (JAXB binding compiler that generates Java beans > out of REST XSD schema) is invoked looks a bit weird to me, as Java > SDK's XsdCodegen does this: > > Runtime.getRuntime().exec(command) > > Why not simply use existing Maven plugins to invoke XJC? > - either: https://github.com/highsource/maven-jaxb2-plugin > - or: http://mojo.codehaus.org/jaxb2-maven-plugin/ > > Second, and most importantly, what's the point of having "group" > entities? I'll give an example - api.xsd contains this: > > <xs:complexType name="DataCenters"> > <xs:complexContent> > <xs:extension base="BaseResources"> > <xs:sequence> > <xs:annotation> > <xs:appinfo> > <jaxb:property name="DataCenters"/> > </xs:appinfo> > </xs:annotation> > <xs:element ref="data_center" minOccurs="0" > maxOccurs="unbounded"/> > </xs:sequence> > </xs:extension> > </xs:complexContent> > </xs:complexType> > > (Same as above for Hosts, Clusters, VMs, etc.) > > This results in following (IMHO rather meaningless) Java class > being generated by XJC: > > public class DataCenters extends BaseResources { > > @XmlElement(name = "data_center") > protected List<DataCenter> dataCenters; > > public List<DataCenter> getDataCenters() { > if (dataCenters == null) { > dataCenters = new ArrayList<DataCenter>(); > } > return this.dataCenters; > } > > public boolean isSetDataCenters() { > return ((this.dataCenters!= > null)&&(!this.dataCenters.isEmpty())); > } > > public void unsetDataCenters() { > this.dataCenters = null; > } > > } > > Instead, we could use @XmlElementWrapper as described in [1] > to avoid generating "group" entities altogether. > > [1] https://github.com/dmak/jaxb-xew-plugin > > The fact that Java SDK provides decorator for each specific > resource collection (like DataCenters), instead of having ONE > resource collection type, greatly complicates overall design > and code-gen aspect. > > In oVirtJS GWT wrapper, we'll avoid above complication through > single resource collection type (having common methods like > get(id), list() etc) for all resources. > > Regards, > Vojtech
-- Dirección Comercial: C/Jose Bardasano Baos, 9, Edif. Gorbea 3, planta 3ºD, 28016 Madrid, Spain Inscrita en el Reg. Mercantil de Madrid – C.I.F. B82657941 - Red Hat S.L.

Hey Michael! good to hear from you, please see my comments below. ----- Original Message -----
From: "Michael Pasternak" <mishka8520@yahoo.com> To: "Vojtech Szocs" <vszocs@redhat.com>, devel@ovirt.org Cc: "Juan Antonio Hernandez Fernandez" <jhernand@redhat.com> Sent: Sunday, November 30, 2014 12:26:06 PM Subject: Re: [ovirt-devel] Some ideas on oVirt Java SDK
Hey Vojtech,
How are you?, please see my reply inline.
On Friday, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.com> wrote:
Hi guys,
since the initial (small, working & well-tested) version of oVirtJS JavaScript SDK is finished [*], I've started working on GWT wrapper for oVirtJS.
While analyzing/reverse-engineering oVirt Java SDK, some thoughts came to my mind, and I wanted to share them with you.
[*] TODO(vszocs) upload new patchset with all recent changes
First, the way XJC (JAXB binding compiler that generates Java beans out of REST XSD schema) is invoked looks a bit weird to me, as Java SDK's XsdCodegen does this:
Runtime.getRuntime().exec(command)
Why not simply use existing Maven plugins to invoke XJC? - either: https://github.com/highsource/maven-jaxb2-plugin
[MP] sdk was using jaxb to begin with, it was replaced with XJC just recently,
OK, so if I get this correctly: before XJC was used (to generate Java beans from XSD), Java SDK contained hand-maintained Java beans and used JAXB RI (runtime implementation) to load objects from XSD? (And same hand-maintained Java beans were, as you wrote below, also used in REST API backend webapp, i.e. that part of code was shared?)
btw Juan, what was the motivation behind this? (REST api uses jaxb as well so we used to have 1x1 mappings) - or: http://mojo.codehaus.org/jaxb2-maven-plugin/
[MP] same.
Second, and most importantly, what's the point of having "group" entities? I'll give an example - api.xsd contains this:
<xs:complexType name="DataCenters"> <xs:complexContent> <xs:extension base="BaseResources"> <xs:sequence> <xs:annotation> <xs:appinfo> <jaxb:property name="DataCenters"/> </xs:appinfo> </xs:annotation> <xs:element ref="data_center" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>
(Same as above for Hosts, Clusters, VMs, etc.)
This results in following (IMHO rather meaningless) Java class being generated by XJC:
public class DataCenters extends BaseResources {
@XmlElement(name = "data_center") protected List<DataCenter> dataCenters;
public List<DataCenter> getDataCenters() { if (dataCenters == null) { dataCenters = new ArrayList<DataCenter>(); } return this.dataCenters; }
public boolean isSetDataCenters() { return ((this.dataCenters!= null)&&(!this.dataCenters.isEmpty())); }
public void unsetDataCenters() { this.dataCenters = null; }
}
Instead, we could use @XmlElementWrapper as described in [1] to avoid generating "group" entities altogether.
[1] https://github.com/dmak/jaxb-xew-plugin
The fact that Java SDK provides decorator for each specific resource collection (like DataCenters), instead of having ONE resource collection type, greatly complicates overall design and code-gen aspect.
[MP] Well, i guess now is speaking JS constraints ghost, am i right?, in any case, the reasons for having decorator per collection are:
1. compliance with REST API (all SDKs and REST api are sharing same well know architecture) 2. "decorator" is a well known and commonly used java design pattern 3. having one resource type serving all collections would create a bottleneck (well it might depend on how you implementing it, but still in my view it's less convenient/readable than dedicated collection with own context, verbs and behavior),
I agree with your points. What I wanted to say is that all existing resource collection decorator classes aren't too different from each other - each collection has well-known API like list(), get(id) etc. Sure, there are small differences, i.e. root collections have some extra methods with extra params like Bookmarks.list() having params like "query", "caseSensitive", "max" etc. I guess the reason of generating per-collection decorator are above mentioned differences. Perhaps later when oVirtJS GWT wrapper will be more mature, we'll end up with per-collection class too, but for now, we'll keep things simple and have single collection class with well-known API like list(), get(id) etc.
after all the purpose of sdk is being java client serving application in "Java" way(i.e type-safe + well bounded interface), while JS use-cases & paradigms are totallydifferent, just consider: [1] java-sdk stile Disk snapshotDisk = api.getVms().get('my-vm').getSnapshots().get('my-snapshot').getDisks().get('my-disk')
Above style is synchronous, which means this style is not applicable to web application environment (it makes no sense to write blocking JavaScript code). Also, REST HTTP web interface is asynchronous in its very nature. In oVirtJS GWT wrapper, accessing items of resource collection is explicitly modeled as asynchronous operation, for example: // notice we use 'ResourceOperation' instead of 'DataCenters' ResourceOperation<DataCenter> op = api.getDataCenters().get('dc-id'); op.run(callback); // translates to HTTP GET request with given callback
[2] JS style you propose Disk snapshotDisk = getCollections().get(new Params[] { Disk.class, 'my-vm', 'my-snapshot', 'my-disk'})
Not sure what you mean here, but above isn't what I had in mind :) We'll still generate Java code for oVirtJS GWT wrapper, we'll also use XJC (and most likely, write our own XJC plugin to adapt it more) as well. However, there should be much clearer separation between various concepts: - resource (containing data + operations) vs. resource data itself - resource collection containing uniform API - explicit asynchronous API representing resource operations Hope this helps to explain design we're trying to achieve.
notice: ===== in [2] you have a bunch of parameters disconnected form any context where orderis *important* (other way you heuristic guesses what user meaning by these params won't work),obviously it's fragile and error prone, while [1] is readable, well bounded, defending it's consumers from potentials errors(exactly what SDK should look like), hope it helps.
I agree, but API style you wrote above in [2] isn't what I had in mind - we'll still generate code that will resemble Java SDK code.
On Friday, November 28, 2014 5:26 PM, Vojtech Szocs <vszocs@redhat.com> wrote:
Hi guys,
since the initial (small, working & well-tested) version of oVirtJS JavaScript SDK is finished [*], I've started working on GWT wrapper for oVirtJS.
While analyzing/reverse-engineering oVirt Java SDK, some thoughts came to my mind, and I wanted to share them with you.
[*] TODO(vszocs) upload new patchset with all recent changes
First, the way XJC (JAXB binding compiler that generates Java beans out of REST XSD schema) is invoked looks a bit weird to me, as Java SDK's XsdCodegen does this:
Runtime.getRuntime().exec(command)
Why not simply use existing Maven plugins to invoke XJC? - either: https://github.com/highsource/maven-jaxb2-plugin - or: http://mojo.codehaus.org/jaxb2-maven-plugin/
Second, and most importantly, what's the point of having "group" entities? I'll give an example - api.xsd contains this:
<xs:complexType name="DataCenters"> <xs:complexContent> <xs:extension base="BaseResources"> <xs:sequence> <xs:annotation> <xs:appinfo> <jaxb:property name="DataCenters"/> </xs:appinfo> </xs:annotation> <xs:element ref="data_center" minOccurs="0" maxOccurs="unbounded"/> </xs:sequence> </xs:extension> </xs:complexContent> </xs:complexType>
(Same as above for Hosts, Clusters, VMs, etc.)
This results in following (IMHO rather meaningless) Java class being generated by XJC:
public class DataCenters extends BaseResources {
@XmlElement(name = "data_center") protected List<DataCenter> dataCenters;
public List<DataCenter> getDataCenters() { if (dataCenters == null) { dataCenters = new ArrayList<DataCenter>(); } return this.dataCenters; }
public boolean isSetDataCenters() { return ((this.dataCenters!= null)&&(!this.dataCenters.isEmpty())); }
public void unsetDataCenters() { this.dataCenters = null; }
}
Instead, we could use @XmlElementWrapper as described in [1] to avoid generating "group" entities altogether.
[1] https://github.com/dmak/jaxb-xew-plugin
The fact that Java SDK provides decorator for each specific resource collection (like DataCenters), instead of having ONE resource collection type, greatly complicates overall design and code-gen aspect.
In oVirtJS GWT wrapper, we'll avoid above complication through single resource collection type (having common methods like get(id), list() etc) for all resources.
Regards, Vojtech _______________________________________________ Devel mailing list Devel@ovirt.org http://lists.ovirt.org/mailman/listinfo/devel
participants (3)
-
Juan Hernández
-
Michael Pasternak
-
Vojtech Szocs