WSIT Design Details

Here are some basic design thoughts about the Xsoap and WSIT model.

Relationship between WSDL and WSIT

Basically WSIT is a C++ description of the service model described in WSDL.




Basic Operation

User runs wsdl2wsit to generate stubs, skels, and some static type information (Vobjects). This procedure will ignore the binding information.

At run time, a client application uses the generated stub to send an invocation. The stub retrieves WSDL information via an interface provided and uses this information to decides which proxy to create (e.g. xsoap, xbmp (or proteus???), etc). The proxy will serialize the Vobjects using its own Serializer (i.e. xsoap proxy will use xsoap serializer).

Sequence Diagrams



Client End

The sequence of event at client side when calling a remote function "Test3Vobject foo(Test2Vobject)"


One modification for current version is adding some meta data about operation in Client proxy, one candidater for the struct of meta data is a table of triple tuple <operationname, element name, type>, another is using wsdlpull data struct directly.

Server End

The sequence of event at server side when calling a remote function "Test3Vobject foo(Test2Vobject)"


Since in Doc style, no method name is provided in the message so the dispatching of invocation will be difficult, one simple solution is using the first root element of body element as the dispatching key, it should work for most of application (wrap)

WSIT Serializer and Deserializer interface



[1]. If the interface is message oriented style, like packStargTag, packContent , packCloseTag, then the client code, which call the serializer and deserializer, represents a xml-inforset-like model implicitly. In the case of Vobject, the client code (i.e. The vobject::Serialize and vobject::deseriailie) will travers the struct of vobject and generate the xml-inforset-like model implicitly (i.e. The order of invocation to serializer and deseriailier)and then the Serializer will generate the wire format message.

Pros: Flexibility due to the fine granularity interface, which will be helpful to implement the peeking ; and may be helpful to the high performance turnning.

Cons: Client program should be responsible for building the xml-inforset-like model. Since we are going to support the both RPC/ENC and DOC/LIT and they are all supposed to be the encoding rules based on which the xml infoset could be generated for a data type, client programs should build a generic xml-inforset-like model, which can cover the xml-inforset generated by both Soap Encoding and Literla Encoding rules and can be converted into them respectivly. The problem is we are not positively sure whether the generic model is feasible.

Example Code

class Vobject {

serialize(Qname& name, Serializer* ser) { //for generic model

ser->packStartTag(name,”Vobject”, NULL);

ser->packStartTag(“i”,”xsd:int”,NULL);

ser->packContent_int(i);

ser->packEndTag();

ser->packEndTag();

}

}




[2]. If the interface is data element oriented style, like pack_int, beginVobject..., then the client code just travers the data model (i.e. The Vobject) and invokes the Serializer/Deserilizer; and the protocol specific Serializer/Deserilizer will be responsible for encoding the data item into final wire format message.

Pros: Client doesn't need to build the xml-inforset-like model, the protocol specific Serializer/Deserilizer will handle the model building(The model is not necesseary to be the XML-inforset-like). Since the model is depent on the encoding protocol, the speration looks more natually.

Cons: The high-level interface make the peeking difficult and if we provide some interfaces for peeking, like unpackStartTag, it will make the Deserializer interface asymmetric with the Serializer interface.

Example Code

class Vobject {

serialize(Qname& name, Serializer* ser) {

ser->beginVobject(name);

ser->pack<int>(“i”,i);

ser->endVobject();

}

}






The interface of Ser/Deser

[1] They should provide the interface for every C++ native primitive types, like int, double...;

packContent_int(int);

packContent_string(string);

...

int unpackContent_int();

string unpackContent_string();

...

or // in the term of generic programming

...

packContent<int>(int);

packContent<string>(string);

...

int unpackContent<int>();

string unpackContent<string>();

...

[2] For performance consideration, they shoud provide a set of special interface for array data type since different protocol has different optimization for array data type. The key point is how to represent the array. If the array is represented by a list of

Vobject pointer (Array_base<Vobject_sptr>),

then the de/ser of array interface will be polymophised and deser function also need hint about the element type of the array so that it can deserialize the msg into specified vobject, so the interface of deser will be

deser_array(QName elementName)

or

deser_array(VobjectFactory* vf);

But this polymophism policy has 3 downsides:

  1. every de/ser of element needs dynaimical dispatching;

  2. deser needs the looking up to create the specific vobject object;

  3. creating and manipulating the array will be tedious for primitive element type, we need first create the value , then create the primitive vobject and then insert into the vobject sptr list.

Obviously this polymorphism representation of array is not parctical for primitive type array (like array of int); Alternativly, we can represent the array of primitive type directly by Array_base<T> so that de/ser can save from dynamical dispatching penalty and looking up penality for creating a data object, meanwhile the manipulation of the Array will be more natual. This policy results in the seperation of the interface for de/sering the array of primitive type from the array of vobject. The interface will somewhat like that:

packContent_array_int(Array_base<int>&);

packContent_array_string(Array_base<string>&);

...

packConent_array_vobject(Array_base<Vobject_sptr>&);

Array_base<int>* unpackContent_array_int();

Array_base<string>* unpackContent_array_string();

...

Array_base<Vobject_sptr>* unpackConent_array_vobject(QName& typeName);

or // in the term of generic programming

packContent_array<int>(Array_base<int>&);

packContent_array<string>(Array_base<string>&);

packContent_array<Vobject_sptr>(Array_base<Vobject_sptr>&);

...

Array_base<int>* unpackContent_array<int>();

Array_base<string>* unpackContent_array<string>();

Array_base<Vobject_sptr>* unpackConent_array<Vobject_sptr>(QName& typeName);

Noted that the interface of de/ser for the array of vobject is different from the array of primitive types (i.e. an extra parameter typeName is needed since we need know the exact vobject type to deserialize it). This raises a question: do we need provide interface for de/sering an array of vobject in de/serer? As said above, the providing of de/sering interface for an array in de/ser-er is for performance, but it is hard to say we will get formance for array of vobject since most probabily the bottel neck of de/ser-ing is at the elment de/ser-ing rather than the whole array de/ser-ing. So if it is true, we can remove the interface for the array of vobject for de/ser-er. This make the de/ser-er interface simple and unified, that is the wsit::de/ser-er just provides the interface for de/ser-ing primivite type and the array of primitive type. Now we add de/serialziing vobject_array into the interface since it may be hard to get the size inmformation out side of deserializer

2. WSIT Vobject Design

Let us first think about how to construct a Vobject and how to de/ser it,

Q1: how to represent the primitive element type in a compound/array Vobject?

There are 2 options:

[1] pure vobject method: Compound/Array Vobject is only aware of vobject element, which could be primitive, compund or array vobject type. Only primitive vobject has reference to native C++ primitive type.

Strongpoint: clearly seperated interface in wsit; the expressive power is best, it is easy to present the recursive style vobject.

Downside: Bad performance; since every C++ native primitive type will be wrapped by a Vobject class, every de/serialization relied on the dynamic dispatching of vobject::de/serialization, which will be disastrous for array of primitive type (like array of int);

[2] mixed vobject method: Compound/Array Vobject use the native C++ primitive data type to represent the primitive element type directly.

Strongpoint: Vobject can directly call de/ser interface to de/serlize the primitive element type. No dynamic dispatching penalty;

We prefer the 2nd options in the design.

Q2: how to represent the array data type using Vobject?

In wsit, we will define a set of helper class for array, PArrayVobject and VArrayVobject. PArrayVobject is the wraper class for array of Primitive. Since de/ser-er provides interface for array of primitive, PArrayVobject will pass its array of primitives directly to de/ser-er and explore the protocol specific optimization for the array; VArrayVobject is the wrapper class for array of Vobjects, and it will call the de/ser-ing member function of very vobject element.

Q3: how to represent the array element type in a Vobject?

Just like Q1, we have 2 options: Vobject vs Array_baes; If we use PArrayVobject/VArrayVobject to represent the array, we will get the double dynamic dispatching penalty (one for vobject, one for Array_base). So in the design we prefer present the array type directly via the Array_base<>

Now we think about how to de/ser the top level element.

Q4: Why is the proceessing of top level data type different with Vobject level data type?

In a Vobject, the type of each sub element is known sepecificly, which means we can decided the type statically(in compiling time); but the top level data type are de/serialized without any statical type context. That is because top level element is represented by Arg, which is an abstract and generic concept about argument(part in term of WSDL) and doesn't have any statical and specific type information about its content. But the Arg can be assocated with type inforamtion generated dynamically(like typeName of the type). Because Vobject is polymorphism and can be generated dynamically with the help of VobjectFactory, we represent the Arg content via Vobject, which can be PrimitiveVobject, PArrayVobject, VArrayVobjct or other user-defined Vobject. For serialization, we can utilize the polymophism of Vobject (that mean the type information is represetned by the dynamica type of Vobject point); For deserialztion, given the typeName we use the VobjectFactory to dynamically generated the Vobject and then the Arg object.

Q5: Why do we need the PrimitiveVobject, PArrayVobject and VArrayVobject?

As the Q4 for top leve element we use Vobject. So we need build the wrapper class for basic data type, i.e. primitive type and aray_base;



Conlusion:

In a Vobject, we prefer native C++ type for primitive type and Array_base for array type over Vobject subelment. Only when we need represent a sub compound class in the Vobject, we use the Vobject; In other word the C++ native type and Array_base are the basic type in wsit, Vobjec is the container of them; For top level element, we use the Vobject and its subtype to represent the type of the element, the element object should be created, de/ser at run time;



ISSUE:

1. ---- WSDL as remote reference

Accept WSDL as a remote reference.

Ken

3. ---- Result class needs a member to distinguish from output argument.

In Result, we need add a member Sptr for return value to distinguish it from output arugment.

Wei

4. ---- Socket library

Current socket library encapsulates the basic socket operation, so It is difficult to do some optimization. Try to use the socket directly in the Http server

Wei

5. ---- xsd:ur-type support

Current in wsit, primitive type and vobject type are seprated, which make the concepte any-type difficult to represent. Try to make the primtive type as a subtype of vobject.

Wei

6. ---- The fault message in the Doc style soap encoding

For Doc, when get a fault message, xsoap can't handle it since unpacker already deserialize the first element Add Err sig for Doc when deserialization

Wei

7. ---- Dynamically select the deserialization style for enc/lit

// XXX In this implementation, we have a serious design problem, that is

// the kind of deserializer should be decided by the operation name, which

// is in the middle of message and should be deserialized by some general

// deserializer. That means we need a somewhat deserializer at first to

// get the method name, and but then we can down-cast the deserializer into

// enc or lit deserializer to demarshel the data.

Wei



New Interface (4th) and their psudo implementation

// Concept:

template<T>

class Array_base {

public:

const Vobject_sptr& operator[](size_t i) const;

Vobject_sptr& operator[](size_t i);

private:

int m_numDims;

size_t m_dims;

size_t m_size;

Vobject_sptr *m_data;

};

class Serializer {

public:

template <typename T>

void packContent(T v); // for primitive type

template <typename T>

void packContent_Array(T v); // for array of primitive type element

virtual void packContent_int32(int32 v);

virtual void packContent_string(string& v);

...

virtual void packContent_Array_int32(Array_base<int32>& array);

virtual void packContent_Array_string(Array_base<string>& array);

...

};

class Deserializer {

public:

template <typename T>

T unpackContent(); // for primitive type

template <typename T>

Sptr<Array_baes<T> >

unpackContent_Array(); // for array of primitive type element

virtual int32 unpackContent_int32();

virtual string unpackContent_string();

...

virtual Sptr<Array_base<int32> > unpackContent_Array_int32();

virtual Sptr<Array_base<string> > unpackContent_Array_string();

...

};

class Vobject {

public:

Vobject(Deserializer*);

virtual serialize(Serializer*);

virtual QName typeName();

};

class VobjectFactory {



typedef Vobject associated_Vobject;

public:

Vobject* newObject(Deserializer*);

};

// T is concept for primitive type

template <typename T>

class PrimitiveVobject : public Vobject {

T m_value;

public:

void serialize(Serializer* se) {

se->template packContent<T>(m_value);

}

PrimitiveVobject(Deserializer* dse)

: m_value(dse->template unpackContent<T>())

{}

};

// T is concept for primitive type

template <typename T>

class PrimitiveVobjectFactory : public VobjectFactory {

typedef PrimitiveVobject<T> associated_Vobject;

public:

PrimitiveVobject<T>* newObject(Deserializer*);

};

// T is concept for primitive type

template <typename T>

class PArrayVobject : public Vobject {

Array_base<T> m_value;

public:

void serialize(Serializer* se) {

se->template packCotnent_array<T>(m_value);

}

PrimitiveVobject(Deserializer* dse)

: m_value(dse->template unpackContent_array<T>())

{}

};

// T is concept for primitive type

template <typename T>

class PArrayVobjectFactory : public VobjectFactory {

typedef PArrayVobject<T> associated_Vobject;

public:

PArrayVobject<T>* newObject(Deserializer*);

};

// T is concept for primitive type

template <typename T>

class MatrixVobject : public Vobject {

Array<T,2> m_value;

public:

void serialize(Serializer* se) {

se->template packCotnent_array<T>(m_value.base());

}

PrimitiveVobject(Deserializer* dse)

: m_value(dse->template unpackContent_array<T>())

{}

};

// T is concept for primitive type

template <typename T>

class MatrixVobjectFactory : public VobjectFactory {

typedef MatrixVobject<T> associated_Vobject;

public:

MatrixVobject<T>* newObject(Deserializer*);

};

// T is concept for Vobject

template <typename T>

class VArrayVobject : public Vobject {

Array_base<Sptr<T> > m_value;

public:

void serialize(Serializer* se) {

for (every element) {

packStartTag();

element->serialize();

packEndTag();

}

}

VArrayVobject(Deserializer* dse)

{

// try to get the size;

// try to get the vobject factory;

for (int i=0; i<size; ++i) {

unpackStartTag();

element[i](Sptr<T>(NewTag,dse));

upackEndTag();

}

}

};

// T is concept for Vobject

template <typename T>

class VArrayVobjectFactory : public VobjectFactory {

typedef VArrayVobject<T> associated_Vobject;

public:

VArrayVobject<T>* newObject(Deserializer*);

};