[ovirt-devel] Some ideas on oVirt Java SDK

Vojtech Szocs vszocs at redhat.com
Tue Dec 2 17:29:04 UTC 2014



----- Original Message -----
> From: "Juan Hernández" <jhernand at redhat.com>
> To: "Vojtech Szocs" <vszocs at redhat.com>
> Cc: devel at ovirt.org, "Michael Pasternak" <mishka8520 at 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 at redhat.com>
> >> To: "Vojtech Szocs" <vszocs at redhat.com>
> >> Cc: devel at 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 at redhat.com>
> >>>> To: "Michael Pasternak" <mishka8520 at yahoo.com>, "Vojtech Szocs"
> >>>> <vszocs at redhat.com>, devel at 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 at redhat.com <mailto:vszocs at 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 at 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.
> 



More information about the Devel mailing list