                                Plugin Framework Design

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Plugin Framework is designed as a bridge to connect WS-MAN with Plugins, it
manages these plugins, including load and unload. All plugins are in a special
directory.  Plugin Framework just call wsman_plugins_load during its
initialization.  When WS-MAN receive the request from client, it analyze this
request and deliver this request to the appropriate plugin, and get the response
from this plugin. Then it envelops this response by WS-Management Specification,
and send this package to client.


0. Structure of Plugin Framework
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
                 --------------          --------------
                 |  plugin 0  |          |  plugin 1  |         ...
                 --------------          --------------
                       |                        |
              ----------------------------------------------
                                   |
                       --------------------------
                       |   Plugin    Framework  |
                       --------------------------
                       --------------------------
                       |         WS-MAN         |
                       --------------------------

1. Importand Data Structure
~~~~~~~~~~~~~~~~~~~~~~~~~~~
struct __WsDispatchInterfaceInfo
{
	unsigned long flags;                // reserved
	char *notes;                        // plugin information -- note
	char *vendor;                       // plugin information -- vendor
	char *displayName;                  // plugin information -- titile
	char *compliance;                   // compliant protocol
	char *actionUriBase;                // base part of the action URI string
	char *wsmanSystemUri;               // WS-MAN system URI, it may be NULL
	char *wsmanResourceUri;             // WS-MAN resource URI, it can not be 
                                            // NULL
	void *extraData;                    // reserved
	WsDispatchEndPointInfo *endPoints;  // pointer to table of resource.
};
typedef struct __WsDispatchInterfaceInfo WsDispatchInterfaceInfo;

This structure describes the plugin and its resource. The endPoints table is an
array of struct __WsDispatchEndPointInfo ending with a all-zero entry.
================================================================================
struct __WsSelector 
{
	char *name;                         // selector name, it identifies with
                                            // mof class keybind.
	char *value;                        // selector value
	char *type;                         // selector type,
	char *description;                  // decription of 
};
typedef struct __WsSelector WsSelector;

This structure describes the selectors about endpoint.
================================================================================
#define WS_DISP_TYPE_RAW_DOC			0
#define WS_DISP_TYPE_GET                        1
#define WS_DISP_TYPE_PUT			2
#define WS_DISP_TYPE_CREATE			3
#define WS_DISP_TYPE_DELETE			4

#define WS_DISP_TYPE_ENUMERATE			5
#define WS_DISP_TYPE_PULL			6
#define WS_DISP_TYPE_RELEASE			7
#define WS_DISP_TYPE_UPDATE			8
#define WS_DISP_TYPE_GETSTATUS			9

#define WS_DISP_TYPE_SOAP_RPC			10

#define WS_DISP_TYPE_COUNT			11

struct __WsDispatchEndPointInfo
{
	unsigned long flags;                   // it is one of the above macro
	char* rqstName;                        // request name, usually it is 
                                               // NULL 
                                               // except WS_DISP_TYPE_SOAP_RPC 
	char* respName;                        // response name, usually it is 
                                               // NULL except WS_DISP_TYPE_SOAP_RPC
	char* inAction;                        // an unique input action name
	char* outAction;                       // an unique output action name
	struct __XmlSerializerInfo* serializationInfo;  
                                               // pointer to a table, used to 
                                               // serialize this endpoint
	WsProcType serviceEndPoint;            // hook fuction for this endpoint
	void* data;                            // pointer to the base resource 
                                               // URI, used as a namespace
	struct __WsSelector* selectors;        // pointer to a seclector table,
                                               // It may be NULL.
};
typedef struct __WsDispatchEndPointInfo WsDispatchEndPointInfo;

This structure describes all information about endpoint, An endpoint which
represents a distinct type of management operation or value. The
serializationInfo table is an array of struct __XmlSerializerInfo, only include
one element, it include some detail about this endpoint 
The selectors table is an array of struct __WsSelector  ending with a 
all-zero entry.
===============================================================================

struct __XmlSerializerInfo
{
	char* name;                       // property of resource                     
	unsigned short flagsMinCount;     // count can be 1 for single               	
                                          // elementd; > 1 for fixed size             
                                          // array; 0 for dynamic array.              
	unsigned short funcMaxCount;                                                        
	XmlSerializationProc proc;        // hook fuction for this property,          
                                          // used to serialize this property.         
                                          // it can be one of do_serialize_xxx        
	XML_TYPE_PTR extData;             // if type of this property is a            
                                          // simple date, it is NULL, or              
                                          // it is a pointer to a                     
                                          // __XmlSerializerInfo structure.           
};
typedef struct __XmlSerializerInfo XmlSerializerInfo;

This structure deccribes all Serialization type information for resource
================================================================================

2. useful MACRO
~~~~~~~~~~~~~~~
#define SER_UINT8(n, x, y)\
	{(n), (x), (y), do_serialize_uint8, NULL}
#define SER_UINT16(n, x, y)\
	{(n), (x), (y), do_serialize_uint16, NULL}
#define SER_UINT32(n, x, y)\
	{(n), (x), (y), do_serialize_uint32, NULL}
#define SER_BOOL(n, x, y)\
	{(n), (x), (y), do_serialize_bool, NULL}

#define SER_UINT8_PTR (n, x, y)\
	{(n), SER_PTR | (x), (y), do_serialize_uint8, NULL}
#define SER_UINT16_PTR (n, x, y)\
	{(n), SER_PTR | (x), (y), do_serialize_uint16, NULL}
#define SER_UINT32_PTR(n, x, y)\
	{(n), SER_PTR | (x), (y), do_serialize_uint32, NULL}
#define SER_BOOL_PTR(n, x, y)\
	{(n), SER_PTR | (x), (y), do_serialize_bool, NULL}

#define SER_STR(n, x, y)\
	{(n), SER_PTR | (x), (y), do_serialize_string, NULL}

#define SER_STRUCT(n, x, y, t)\
	{(n), (x), (y), do_serialize_struct, t##_TypeItems}
	
#define SER_DYN_ARRAY_PTR(t)\
	{NULL, SER_PTR, 1, do_serialize_syn_size_array, t##_TypeInfo}

#define SER_DYN_ARRAY(t)\
	{NULL, 1, 1, do_serialize_dyn_size_array, t##_TypeInfo}


#define SER_IN_UINT8 (n)\
	{(n), 1, 1 | SER_IN, do_serialize_uint8, NULL}
#define SER_IN_UINT16(n)\
	{(n), 1, 1 | SER_IN, do_serialize_uint16, NULL}
#define SER_IN_UINT32(n)\
	{(n), 1, 1 | SER_IN, do_serialize_uint32, NULL}
#define SER_IN_BOOL(n)\
	{(n), 1, 1 | SER_IN, do_serialize_bool, NULL}

#define SER_IN_UINT8_PTR (n)\
	{(n), SER_PTR | 1, 1 | SER_IN, do_serialize_uint8, NULL}
#define SER_IN_UINT16_PTR(n)\
	{(n), SER_PTR | 1, 1 | SER_IN, do_serialize_uint16, NULL}
#define SER_IN_UINT32_PTR(n)\
	{(n), SER_PTR | 1, 1 | SER_IN, do_serialize_uint32, NULL}
#define SER_IN_BOOL_PTR(n)\
	{(n), SER_PTR | 1, 1 | SER_IN, do_serialize_bool, NULL}

#define SER_IN_STR(n)\
	{(n), SER_PTR | 1, 1 | SER_IN, do_serialize_string, NULL}

#define SER_IN_STRUCT_PTR(n, t)\
	{(n), SER_PTR | 1, 1 | SER_IN, do_serialize_Struct, t##_TypeItems}


#define SER_OUT_UINT8 (n)\
	{(n), 1, 1 | SER_OUT, do_serialize_uint8, NULL}
#define SER_OUT_UINT16 (n)\
	{(n), 1, 1 | SER_OUT, do_serialize_uint16, NULL}
#define SER_OUT_UINT32(n)\
	{(n), 1, 1 | SER_OUT, do_serialize_uint32, NULL}
#define SER_OUT_BOOL(n)\
	{(n), 1, 1 | SER_OUT, do_serialize_bool, NULL}

#define SER_OUT_UINT8_PTR(n)\
	{(n), SER_PTR | 1, 1 | SER_OUT, do_serialize_uint8, NULL}
#define SER_OUT_UINT16_PTR(n)\
	{(n), SER_PTR | 1, 1 | SER_OUT, do_serialize_uint16, NULL}
#define SER_OUT_UINT32_PTR(n)\
	{(n), SER_PTR | 1, 1 | SER_OUT, do_serialize_uint32, NULL}
#define SER_OUT_BOOL_PTR(n)\
	{(n), SER_PTR | 1, 1 | SER_OUT, do_serialize_bool, NULL}

#define SER_OUT_STR(n)\
	{(n), SER_PTR | 1, 1 | SER_OUT, do_serialize_string, NULL}

#define SER_OUT_STRUCT_PTR(n, t)\
	{(n), SER_PTR | 1, 1 | SER_OUT, do_serialize_struct, t##_TypeItems}


#define SER_INOUT_UINT8 (n)\
	{(n), 1, 1 | SER_INOUT, do_serialize_uint8, NULL}
#define SER_INOUT_UINT16 (n)\
	{(n), 1, 1 | SER_INOUT, do_serialize_uint16, NULL}
#define SER_INOUT_UINT32(n)\
	{(n), 1, 1 | SER_INOUT, do_serialize_uint32, NULL}
#define SER_INOUT_BOOL(n)\
	{(n), 1, 1 | SER_INOUT, do_serialize_bool, NULL}

#define SER_INOUT_UINT8_PTR (n)\
	{(n), SER_INOUT_PTR | 1, 1 | SER_INOUT, do_serialize_uint8, NULL}
#define SER_INOUT_UINT16_PTR (n)\
	{(n), SER_INOUT_PTR | 1, 1 | SER_INOUT, do_serialize_uint16, NULL}
#define SER_INOUT_UINT32_PTR(n)\
	{(n), SER_INOUT_PTR | 1, 1 | SER_INOUT, do_serialize_uint32, NULL}
#define SER_INOUT_BOOL_PTR(n)\
	{(n), SER_INOUT_PTR | 1, 1 | SER_INOUT, do_serialize_bool, NULL}

#define SER_INOUT_STR(n)\
	{(n), SER_INOUT_PTR | 1, 1 | SER_INOUT, do_serialize_string, NULL}

#define SER_INOUT_STRUCT_PTR(n, t)\
	{(n), SER_PTR | 1, 1 | SER_INOUT, do_serialize_struct, t##_TypeItems}


#define SER_RET_VAL_UINT8 (n)\
	{(n), 1, 1 | SER_RET_VAL, do_serialize_uint8, NULL}
#define SER_RET_VAL_UINT16 (n)\
	{(n), 1, 1 | SER_RET_VAL, do_serialize_uint16, NULL}
#define SER_RET_VAL_UINT32(n)\
	{(n), 1, 1 | SER_RET_VAL, do_serialize_uint32, NULL}
#define SER_RET_VAL_BOOL(n)\
	{(n), 1, 1 | SER_RET_VAL, do_serialize_bool, NULL}

#define SER_RET_VAL_UINT8_PTR (n)\
	{(n), SER_RET_VAL_PTR | 1, 1 | SER_RET_VAL, do_serialize_uint8, NULL}
#define SER_RET_VAL_UINT16_PTR (n)\
	{(n), SER_RET_VAL_PTR | 1, 1 | SER_RET_VAL, do_serialize_uint16, NULL}
#define SER_RET_VAL_UINT32_PTR(n)\
	{(n), SER_RET_VAL_PTR | 1, 1 | SER_RET_VAL, do_serialize_uint32, NULL}
#define SER_RET_VAL_BOOL_PTR(n)\
	{(n), SER_RET_VAL_PTR | 1, 1 | SER_RET_VAL, do_serialize_bool, NULL}

#define SER_RET_VAL_STR(n)\
	{(n), SER_RET_VAL_PTR | 1, 1 | SER_RET_VAL, do_serialize_string, NULL}

#define SER_RET_VAL_STRUCT_PTR(n, t)\
	{(n), SER_PTR | 1, 1 | SER_RET_VAL, do_serialize_struct, t##_TypeItems}

#define SER_TYPE_STRUCT(n, t)\
struct __XmlSerializerInfo t##_TypeInfo[] = {\
{(n), 1, 1, do_serialize_struct, t##_TypeItems} }

#define SER_START_ITEMS(n, t)\
struct __XmlSerializerInfo t##_TypeItems[] = {

#define SER_END_ITEMS(n, t)\
	{NULL, 0, 0, NULL, NULL} };\
	SER_TYPE_STRUCT(n, t)

These macros are used to create an array of items with name 
StateDescription_TypeInfo 

for example:
SER_START_ITEMS("This", WsManThis)
SER_STR("Vendor", 1, 1), 
SER_STR("Version", 1, 1),
SER_END_ITEMS("This", WsManThis);

After the preprocessing stage, the result is 
struct __XmlSerializerInfo WsManThis_TypeItems[] = {
       {("Vendor"), 0x8000 | (1), (1), do_serialize_string, 0},
       {("Version"), 0x8000 | (1), (1), do_serialize_string, 0},
       {0, 0, 0, 0, 0} };
struct __XmlSerializerInfo WsManThis_TypeInfo[] = {
       {(this), 1, 1, do_serialize_struct, WsManThis_TypeItems} };
================================================================================
#define ADD_SELECTOR(n,t,d)\
	{ n, NULL, t, d}
	  
#define SELECTOR_LAST { NULL, NULL, NULL, NULL }

#define START_TRANSFER_GET_SELECTORS(t) WsSelector t##_Get_Selectors[] = {

#define FINISH_TRANSFER_GET_SELECTORS(t) SELECTOR_LAST }

These macros are used to create array of items with name WsSelector.

for example:
START_TRANSFER_GET_SELECTORS(WsManThis)
	ADD_SELECTOR("CreationClassName", "string", "Creation Class Name"),
FINISH_TRANSFER_GET_SELECTORS(IpmiSel);

After the preprocessing stage, the result is

struct WsSelector WsManThis_Get_Selectors[] = {
       { "CreationClassName", NULL, "string", "Creation Class Name" },
       { 0, 0, 0, 0}
};
================================================================================
#define END_POINT_TRANSFER_GET(t, ns)\
	{ WS_DISP_TYPE_GET, NULL, NULL, TRANSFER_ACTION_GET, NULL,\
	  t##_TypeInfo, (WsProcType)t##_Get_EP, ns, t##_Get_Selectors}

#define END_POINT_TRANSFER_GET_RAW(t, ns)\
	{ WS_DISP_TYPE_GET_RAW, NULL, NULL, TRANSFER_ACTION_GET, NULL,\
	  t##_TypeInfo, (WsProcType)t##_Get_EP, ns, t##_Get_Selectors}	  

#define END_POINT_TRANSFER_PUT(t, ns)\
	{ WS_DISP_TYPE_PUT, NULL, NULL, TRANSFER_ACTION_PUT, NULL,\
	  t##_TypeInfo, (WsProcType)t##_Put_EP, ns, NULL}




#define END_POINT_TRANSFER_ENUMERATE(t, ns)\
	{ WS_DISP_TYPE_ENUMERATE, NULL, NULL, ENUM_ACTION_ENUMERATE, NULL,\
	  t##_TypeInfo, (WsProcType)t##_Enumerate_EP, ns, NULL}

#define END_POINT_TRANSFER_RELEASE(t, ns)\
	{ WS_DISP_TYPE_RELEASE, NULL, NULL, ENUM_ACTION_RELEASE, NULL,\
	  t##_TypeInfo, (WsProcType)t##_Release_EP, ns, NULL}

#define END_POINT_TRANSFER_PULL(t, ns)\
	{ WS_DISP_TYPE_PULL, NULL, NULL, ENUM_ACTION_PULL, NULL,\
	  t##_TypeInfo, (WsProcType)t##_Pull_EP, ns, NULL}
#define END_POINT_TRANSFER_PULL_RAW(t, ns)\
	{ WS_DISP_TYPE_PULL_RAW, NULL, NULL, ENUM_ACTION_PULL, NULL,\
	  t##_TypeInfo, (WsProcType)t##_Pull_EP, ns, NULL}	  

#define END_POINT_PRIVATE_EP(t, a, m, ns)    \
        { WS_DISP_TYPE_PRIVATE, NULL, NULL, a, NULL, \
          t##_TypeInfo, (WsProcType)t##_##m##_EP, ns, NULL }

#define END_POINT_LAST	{ 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL }

#define SER_START_END_POINTS(t) WsDispatchEndPointInfo t##_EndPoints[] = {

#define SER_FINISH_END_POINTS(t) END_POINT_LAST }

These macros are used to create an array that describes all endpoints in this class

for example:
SER_START_END_POINTS(WsManThis)
END_POINT_TRANSFER_GET(WsManThis, XML_NS_WS_MAN"/this"),
SER_FINISH_END_POINTS(WsManThis);

After the preprocessing stage, the result is:
WsDispatchEndPointInfo WsManThis_EndPoints[] = {
	{ 1, 0, 0, "http://schemas.xmlsoap.org/ws/2004/09/transfer/Get", 
          WsManThis_TypeInfo, 
          (WsProcType)WsManThis_Get_EP, 
          "http://schemas.xmlsoap.org/ws/2005/06/management/this",
          WsMan_Get_Selectors},
          { 0, 0, 0, 0, 0, 0, 0, 0 }};
================================================================================

3. write a plugin
~~~~~~~~~~~~~~~~~
requisite interfaces:

int init(GModule *self, void **data);
    parameters:
          self   a pointer to this module
          data   reference to a user data structure. used to initial this 
                 plugin.
    return value:
          On  error, 0 is returned, On success, a no_zerro value is returned.

After loading a plugin, The Plugin Framework use this interface to initialize 
this plugin.

================================================================================
void get_endpoints(GModule *self, void **data);
     parameters:
          self    a pointer to this module
          data    reference to a WsDispatchEndPointInfo structure.

This is the only way that the plugin framework collects all endpoints
information about this plugin, so in this interface body, the plugin should
initialize the WsDispatchEndPointInfo structre pointed by data.

for example:
void get_endpoints(GModule *self, void **data) 
{		 
    WsDispatchInterfaceInfo *itf = (WsDispatchInterfaceInfo *)*data;

    itf->flags = 0;
    itf->actionUriBase = XML_NS_WS_MAN;
    itf->wsmanSystemUri = NULL;
    itf->wsmanResourceUri = WS_MAN_THIS_RESOURCE_URI;
    itf->extraData = NULL;
    itf->endPoints = WsManThis_EndPoints;			
}

================================================================================
optional interface:

void cleanup( GModule *self, void *data );
     parameters:
            self    a pointer to this module
            data    reference to a user data structure.

When the Plugin Framework free a plugin, it call this interface.

================================================================================
endpoint action interface:
xxx* xxx_Get_EP(WsContextH cntx);
     parameter:
        cntx:   It is a context about this require. The plugin can get some 
                useful information from cntx, such as selector.

     return value:
               The xxx structure is declared in this plugin, it is invisible 
               to the framework, but its fields must be identical with the 
               items of an array with name StateDescription_TypeInfo

The Plugin Framework call this api to get all properties of this resource.

================================================================================
int xxx_Put_EP(WsContextH cntx, void *data, void **outData)
     parameter:
        cntx:   It is a context about this require. The plugin can get some 
                useful information from cntx, such as selector.

        data:   BTD

        outDdata: reference to buffer, used to store response information 
                  from plugin.

     return value:
                On success, return 0, on error, return non-zero value.

The Plugin Framework call this api to model an update of an entire item.
================================================================================
int xxx_Enumerate_EP(WsContextH cntx, WsEnumerateInfo* enumInfo);
    parameter:
        cntx:   It is a context about this require. The plugin can get some 
                useful information from cntx, such as selector.

        enumInfo: output parameter.

    return value:
                On success, return 0, on error, reuturn non-zero value.     
         
The Plugin Framework call this api to begin an enumeration or query.
================================================================================
int xxx_Release_EP(WsContextH cntx, WsEnumerateInfo* enumInfo);
    parameter:
        cntx:   It is a context about this require. The plugin can get some 
                useful information from cntx, such as selector.

        enumInfo: the index field specifies an instance.

    return value:
                On success, return 0, on error, reuturn non-zero value.     

The Plugin Framework call this api to release an active enumerator
================================================================================
int xxx_Pull_EP(WsContextH cntx, WsEnumerateInfo* enumInfo);
    parameter:
        cntx:   It is a context about this require. The plugin can get some 
                useful information from cntx, such as selector.

        enumInfo: specify the enumeration information

    return value:
                On success, return 0, on error, reuturn non-zero value.     

The Plugin Framework call this api to retrieve the next batch of result from 
enumeration
================================================================================
int xxx_xxx_EP(SoapOpH soaph, void *data);
    parameter: 
        soaph:  pointer to a SOAP_OP_ENTRY structure, The plugin can get the 
                context info from this pointer.
        
        data:   pointer to this endpoint structure.

We add a private endpoint to this plugin by 'The 'END_POINT_PRIVATE_EP' macro, 
WS_DISP_TYPE_PRIVATE flag is assigned to this endpoint. A function whose 
prototype is like as 'int xxx_xxx_EP(SoapOpH soaph, void *data)' is needed. 
The Plugin Framework will call this api to realize plugin's private action.

for example:
#define CATCH_RESP      "CatchResponse"
#define PLUGIN_INFO     "This plugin is designed for IPMI_SEL class"
int IpmiSel_Catch_EP(SoapOpH op, void* appData)
{
	wsman_debug (WSMAN_DEBUG_LEVEL_DEBUG, "Catch Endpoint Called"); 
        
        // get the context from op
        SoapH soap = soap_get_op_soap(op);	
        WsContextH cntx = ws_create_ep_context(soap, soap_get_op_doc(op, 1));    

        // get endpoint information
        WsDispatchEndPointInfo* info = (WsDispatchEndPointInfo*)appData;
        XmlSerializerInfo* typeInfo = info->serializationInfo;

        void* data;
        WsXmlDocH doc = NULL;

        // add some code for private endpoint

        // create response doc
        wsman_debug (WSMAN_DEBUG_LEVEL_ERROR, "Creating Response doc");
        doc = ws_create_response_envelope(cntx, soap_get_op_doc(op, 1), NULL);

        if ( doc )
        {
                WsXmlNodeH body = ws_xml_get_soap_body(doc);
                WsXmlNodeH node = ws_xml_add_child(body, 
                                                   XML_NS_DOEM_TEST,
                                                   CATCH_RESP,
                                                   PLUGIN_INFO);
        }

        if ( doc )
        {
                wsman_debug (WSMAN_DEBUG_LEVEL_ERROR, "Setting operation document");
                soap_set_op_doc(op, doc, 0);
                soap_submit_op(op, soap_get_op_channel_id(op), NULL);
                ws_xml_destroy_doc(doc);
        }

        ws_serializer_free_all(cntx);
        return 0;
}




