Wrong EmbeddedInstances from CIMOM callback
Jan Safranek <[email protected]> Tue, 02 Apr 2013 17:17:26 +0200
| Newsgroups | gmane.network.open-pegasus.general |
|---|---|
| Message-ID | <[email protected]> |
I'm still working on the job control and I've found out that if I call
CBGetInstance() from inside my CMPI provider to get an instance of
CIM_MethodResult, I get instance with wrong properties. It's quite hard
to describe the bug, I'm sure I'm hitting some weird corner case here.
CIM_MethodResult has two properties Pre/PosCallIndication, which are
embedded instances of CIM_MethodCall. And the CIM_MethodCall has Error
property with embedded instance of CIM_Error class. All this seems to be
somewhat important to reproduce the bug.
Attached is a sample CMPI provider & MOF file. Implemented are only
these intrinsic methods:
EnumerateInstances - in TST_MethodResultEnumInstances ()
GetInstance - in TST_MethodResultGetInstance()
InvokeMethod - TST_MethodResultInvokeMethod ()
There is very little checking, e.g. GetInstance does not check the
instance ObjectPath etc. Also only few properties are implemented, this
is the smallest provider to reproduce the bug.
GetInstance works well if it is called from outside, i.e. from a WBEM
client. It returns a TST_MethodResult instance with PreCallIndication
and PostCallIndication properties, both embedded instances of
CIM_InstMethodCall class. So far so good.
If I call GetInstance from inside the provider via CIMOM using
CBGetInstance, I can get good PostCallIndication, but PreCallIndication
has wrong class, CIM_Error instead of CIM_InstMethodCall. You can try to
call DoTest() method of my TST_MethodResult class - it calls
CBGetInstance to get instance of TST_MethodResult and prints all its
property names it gets and dives into embedded instances.
To reproduce the bug, run Pegasus this way, it will print debug output
to stderr:
$ cimserver daemon=false
Then call DoTest() on a TST_MethodResult instance and you should get
output similar to bad.log. Note the class names of embedded instances of
TST_MethodResult properties:
...
Property: PreCallIndication
class: CIM_Error <--- should be CIM_InstMethodCall
...
Property: PostCallIndication
class: CIM_InstMethodCall
...
Property: Error
array 1{
class: CIM_InstMethodCall <---should be CIM_Error
...
If the cimserver is started with forceProviderProcesses=false, the bug
disappears, see good.log:
...
Property: PreCallIndication
class: CIM_InstMethodCall
...
Property: PostCallIndication
class: CIM_InstMethodCall
...
Property: Error
array 1{
class: CIM_Error
...
Working 'forceProviderProcesses' indicates the bug is related to
communication between CIMOM and the provider process, but I haven't
found any way how to debug this.
In addition, if I switch the order, in which my provider sets
PreCallIndication and PostCallIndication properties (= switch lines 133
and 135 in methodresult.c), it starts working too.
That's where I stopped debugging, I wasn't able to find any logging
related to inter process communication.
I hope this report does make some sense, feel free to ask if you need
additional information.
Jan
bad.log
(text/x-log, 2.7 KB)
TST_MethodResultGetInstance() called, ctx 0x7f8192b01910, rslt 0x7f8192b01970, op 0x7f8192b018f0, properties (nil)
Entering TST get_instance()
Creating error
error created
Creating PreCall
PreCall created
Creating array of errors
array created
Creating PostCall
PostCall created
Creating MethodResult
Set PreCall
Set PostCall
TST finished
TST_MethodResultGetInstance() succeeded
class: TST_MethodResult
Property: Caption
Property: Description
Property: ElementName
Property: Generation
Property: InstanceID
Property: PreCallIndication
class: CIM_Error
Property: OwningEntity
Property: MessageID
Property: ContinuedInNextMessage
Property: Message
Property: MessageArguments
Property: ErrorType
Property: OtherErrorType
Property: PerceivedSeverity
Property: ProbableCause
Property: ProbableCauseDescription
Property: RecommendedActions
Property: ErrorSource
Property: ErrorSourceFormat
Property: OtherErrorSourceFormat
Property: CIMStatusCode
Property: CIMStatusCodeDescription
Property: PostCallIndication
class: CIM_InstMethodCall
Property: IndicationIdentifier
Property: CorrelatedIndications
Property: IndicationTime
Property: PerceivedSeverity
Property: OtherSeverity
Property: IndicationFilterName
Property: SequenceContext
Property: SequenceNumber
Property: SourceInstance
(NULL)
Property: SourceInstanceModelPath
Property: SourceInstanceHost
Property: MethodName
Property: MethodParameters
(NULL)
Property: ReturnValue
Property: ReturnValueType
Property: Error
array 1{
class: CIM_InstMethodCall
Property: IndicationIdentifier
Property: CorrelatedIndications
Property: IndicationTime
Property: PerceivedSeverity
Property: OtherSeverity
Property: IndicationFilterName
Property: SequenceContext
Property: SequenceNumber
Property: SourceInstance
(NULL)
Property: SourceInstanceModelPath
Property: SourceInstanceHost
Property: MethodName
Property: MethodParameters
(NULL)
Property: ReturnValue
Property: ReturnValueType
Property: Error
(empty array)
Property: PreCall
} array
Property: PreCall
invokeMethod() succeeded
embedded.mof
(text/x-mof, 68 B)
class TST_MethodResult : CIM_MethodResult
{
uint32 DoTest();
};
good.log
(text/x-log, 2.6 KB)
TST_MethodResultGetInstance() called, ctx 0x7f24374fa3e0, rslt 0x7f24374fa440, op 0x7f24374fa3c0, properties (nil)
Entering TST get_instance()
Creating error
error created
Creating PreCall
PreCall created
Creating array of errors
array created
Creating PostCall
PostCall created
Creating MethodResult
Set PreCall
Set PostCall
TST finished
TST_MethodResultGetInstance() succeeded
class: TST_MethodResult
Property: Caption
Property: Description
Property: ElementName
Property: Generation
Property: InstanceID
Property: PreCallIndication
class: CIM_InstMethodCall
Property: IndicationIdentifier
Property: CorrelatedIndications
Property: IndicationTime
Property: PerceivedSeverity
Property: OtherSeverity
Property: IndicationFilterName
Property: SequenceContext
Property: SequenceNumber
Property: SourceInstance
(NULL)
Property: SourceInstanceModelPath
Property: SourceInstanceHost
Property: MethodName
Property: MethodParameters
(NULL)
Property: ReturnValue
Property: ReturnValueType
Property: Error
(empty array)
Property: PreCall
Property: PostCallIndication
class: CIM_InstMethodCall
Property: IndicationIdentifier
Property: CorrelatedIndications
Property: IndicationTime
Property: PerceivedSeverity
Property: OtherSeverity
Property: IndicationFilterName
Property: SequenceContext
Property: SequenceNumber
Property: SourceInstance
(NULL)
Property: SourceInstanceModelPath
Property: SourceInstanceHost
Property: MethodName
Property: MethodParameters
(NULL)
Property: ReturnValue
Property: ReturnValueType
Property: Error
array 1{
class: CIM_Error
Property: OwningEntity
Property: MessageID
Property: ContinuedInNextMessage
Property: Message
Property: MessageArguments
Property: ErrorType
Property: OtherErrorType
Property: PerceivedSeverity
Property: ProbableCause
Property: ProbableCauseDescription
Property: RecommendedActions
Property: ErrorSource
Property: ErrorSourceFormat
Property: OtherErrorSourceFormat
Property: CIMStatusCode
Property: CIMStatusCodeDescription
} array
Property: PreCall
invokeMethod() succeeded
make.sh
(application/x-shellscript, 243 B)
gcc -c methodresult.c -g -O0 -fPIC -Wall gcc -fPIC -std=c99 -Wall -pedantic -g -O0 -Wextra -Wno-unused-parameter -Wformat -Wparentheses -Wl,--no-undefined -shared -Wl,-soname,libcmpiMethodResult.so -o libcmpiMethodResult.so methodresult.o
methodresult.c
(text/plain, 14.5 KB)
/* Public domain. */
#include <stdio.h>
#include <stdarg.h>
#include <cmpi/cmpidt.h>
#include <cmpi/cmpift.h>
#include <cmpi/cmpimacs.h>
/* A simple stderr logging/tracing facility. */
#ifndef _CMPI_TRACE
#define _CMPI_TRACE(tracelevel,args) _logstderr args
static void _logstderr(char *fmt,...)
{
va_list ap;
va_start(ap,fmt);
vfprintf(stderr,fmt,ap);
va_end(ap);
fprintf(stderr,"\n");
}
#endif
/* Global handle to the CIM broker. This is initialized by the CIMOM when
* the provider is loaded */
static const CMPIBroker * _broker = NULL;
static CMPIStatus TST_MethodResultCleanup(
CMPIInstanceMI * self,
const CMPIContext * ctx,
CMPIBoolean terminating)
{
CMPIStatus st = { CMPI_RC_OK, NULL };
return st;
}
static CMPIStatus TST_MethodResultMethodCleanup(
CMPIMethodMI * self,
const CMPIContext * ctx,
CMPIBoolean terminating)
{
CMPIStatus st = { CMPI_RC_OK, NULL };
return st;
}
static CMPIStatus TST_MethodResultEnumInstanceNames(
CMPIInstanceMI * self,
const CMPIContext * ctx,
const CMPIResult * rslt,
const CMPIObjectPath * op)
{
_CMPI_TRACE(1, ("TST_MethodResultEnumInstanceNames() called, ctx %p,"
" result %p, op %p", ctx, rslt, op));
CMPIStatus status = {CMPI_RC_OK, NULL};
_CMPI_TRACE(1,("TST_MethodResultEnumInstanceNames() %s",
(status.rc == CMPI_RC_OK)? "succeeded":"failed"));
return status;
}
CMPIInstance *get_instance(
const CMPIBroker *_broker,
const CMPIContext * ctx,
const CMPIObjectPath * op)
{
CMPIInstance *ipost, *ipre, *imresult, *ierror;
CMPIObjectPath *ppost, *ppre, *pmresult, *perror;
CMPIValue vmname, vpostindication, vpreindication, vinstanceid, verror, vstatuscode, vmessage, verrors, vprecall;
CMPIString *ns;
CMPIArray *aerrors;
CMPIStatus status;
fprintf(stderr, "Entering TST get_instance()\n");
fprintf(stderr, "Creating error\n");
/* Create Error embedded instance */
ns=CMGetNameSpace(op, &status);
perror = CMNewObjectPath(_broker, CMGetCharPtr(ns), "CIM_Error", &status);
ierror = CMNewInstance(_broker, perror, &status);
vstatuscode.uint32 = 1; // TST_ERR_FAILED
CMSetProperty(ierror, "CIMStatusCode", &vstatuscode, CMPI_uint32);
vmessage.string = CMNewString(_broker, "Test error message", &status);
CMSetProperty(ierror, "Message", &vmessage, CMPI_string);
fprintf(stderr, "error created\n");
fprintf(stderr, "Creating PreCall\n");
/* create PreCallIndication embedded instance */
ppre = CMNewObjectPath(_broker, CMGetCharPtr(ns), "CIM_InstMethodCall", &status);
ipre = CMNewInstance(_broker, ppre, &status);
/* set MethodName */
vmname.string = CMNewString(_broker, "TestMethod", &status);
CMSetProperty(ipre, "MethodName", &vmname, CMPI_string);
/* set PreCall */
vprecall.boolean = 0;
CMSetProperty(ipre, "PreCall", &vprecall, CMPI_boolean);
fprintf(stderr, "PreCall created\n");
fprintf(stderr, "Creating array of errors\n");
/* create array with the Error instance */
aerrors = CMNewArray(_broker, 1, CMPI_instance, &status);
verror.inst = ierror;
CMSetArrayElementAt(aerrors, 0, &verror, CMPI_instance);
fprintf(stderr, "array created\n");
fprintf(stderr, "Creating PostCall\n");
/* create PostCallIndication embedded instance */
ns=CMGetNameSpace(op, &status);
ppost = CMNewObjectPath(_broker,CMGetCharPtr(ns),"CIM_InstMethodCall",&status);
ipost = CMNewInstance(_broker, ppost, &status);
/* set MethodName */
vmname.string = CMNewString(_broker, "TestMethod", &status);
CMSetProperty(ipost, "MethodName", &vmname, CMPI_string);
/* set Error */
verrors.array = aerrors;
CMSetProperty(ipost, "Error", &verrors, CMPI_instanceA);
/* set PreCall */
vprecall.boolean = 1;
CMSetProperty(ipost, "PreCall", &vprecall, CMPI_boolean);
fprintf(stderr, "PostCall created\n");
fprintf(stderr, "Creating MethodResult\n");
/* create MethodResult instance */
ns=CMGetNameSpace(op, &status);
pmresult = CMNewObjectPath(_broker, CMGetCharPtr(ns), "TST_MethodResult", &status);
vinstanceid.string = CMNewString(_broker, "TestInstanceID", &status);
CMAddKey(pmresult, "InstanceID", &vinstanceid, CMPI_string);
imresult = CMNewInstance(_broker, pmresult, &status);
CMSetProperty(imresult, "InstanceID", &vinstanceid, CMPI_string);
/* store PostCallIndication in the property */
vpostindication.inst = ipost;
vpreindication.inst = ipre;
fprintf(stderr, "Set PreCall\n");
CMSetProperty(imresult, "PreCallIndication", &vpreindication, CMPI_instance);
fprintf(stderr, "Set PostCall\n");
CMSetProperty(imresult, "PostCallIndication", &vpostindication, CMPI_instance);
fprintf(stderr, "TST finished\n");
return imresult;
}
static CMPIStatus TST_MethodResultEnumInstances(
CMPIInstanceMI * self,
const CMPIContext * ctx,
const CMPIResult * rslt,
const CMPIObjectPath * op,
const char ** properties)
{
CMPIStatus status = {CMPI_RC_OK, NULL};
_CMPI_TRACE(1, ("TST_MethodResultEnumInstances() called, ctx %p, rslt %p,"
" op %p, properties %p", ctx, rslt, op, properties));
CMReturnInstance(rslt, get_instance(_broker, ctx, op));
CMReturnDone(rslt);
status.rc = CMPI_RC_OK;
status.msg = NULL;
_CMPI_TRACE(1, ("TST_MethodResultEnumInstances() %s",
(status.rc == CMPI_RC_OK)? "succeeded":"failed"));
return status;
}
static CMPIStatus TST_MethodResultGetInstance(
CMPIInstanceMI * self,
const CMPIContext * ctx,
const CMPIResult * rslt,
const CMPIObjectPath * op,
const char ** properties)
{
CMPIStatus status = {CMPI_RC_OK, NULL};
_CMPI_TRACE(1, ("TST_MethodResultGetInstance() called, ctx %p, rslt %p,"
" op %p, properties %p", ctx, rslt, op, properties));
CMReturnInstance(rslt, get_instance(_broker, ctx, op));
CMReturnDone(rslt);
status.rc = CMPI_RC_OK;
status.msg = NULL;
_CMPI_TRACE(1, ("TST_MethodResultGetInstance() %s",
(status.rc == CMPI_RC_OK)? "succeeded":"failed"));
return status;
}
static CMPIStatus TST_MethodResultCreateInstance(
CMPIInstanceMI * self,
const CMPIContext * ctx,
const CMPIResult * rslt,
const CMPIObjectPath * op,
const CMPIInstance * inst)
{
CMPIStatus status = {CMPI_RC_ERR_NOT_SUPPORTED, NULL};
_CMPI_TRACE(1, ("TST_MethodResultCreateInstance() called, ctx %p, rslt %p,"
" op %p, inst %p", ctx, rslt, op, inst));
_CMPI_TRACE(1, ("TST_MethodResultCreateInstance() %s",
(status.rc == CMPI_RC_OK) ? "succeeded":"failed"));
return status;
}
// ----------------------------------------------------------------------------
#ifdef CMPI_VER_100
#define TST_MethodResultSetInstance TST_MethodResultModifyInstance
#endif
static CMPIStatus TST_MethodResultSetInstance(
CMPIInstanceMI * self,
const CMPIContext * ctx,
const CMPIResult * rslt,
const CMPIObjectPath * op,
const CMPIInstance * inst,
const char ** properties)
{
CMPIStatus status = {CMPI_RC_ERR_NOT_SUPPORTED, NULL};
_CMPI_TRACE(1, ("TST_MethodResultSetInstance() called, ctx %p, rslt %p,"
" op %p, inst %p, properties %p", ctx, rslt, op, inst, properties));
_CMPI_TRACE(1, ("TST_MethodResultSetInstance() %s",
(status.rc == CMPI_RC_OK)? "succeeded":"failed"));
return status;
}
// ----------------------------------------------------------------------------
/* DeleteInstance() - delete/remove the specified instance. */
static CMPIStatus TST_MethodResultDeleteInstance(
CMPIInstanceMI * self,
const CMPIContext * ctx,
const CMPIResult * rslt,
const CMPIObjectPath * op)
{
CMPIStatus status = {CMPI_RC_ERR_NOT_SUPPORTED, NULL};
_CMPI_TRACE(1, ("TST_MethodResultDeleteInstance() called, ctx %p, rslt %p,"
" op %p", ctx, rslt, op));
_CMPI_TRACE(1, ("TST_MethodResultDeleteInstance() %s",
(status.rc == CMPI_RC_OK)? "succeeded":"failed"));
return status;
}
// ----------------------------------------------------------------------------
static CMPIStatus TST_MethodResultExecQuery(
CMPIInstanceMI * self,
const CMPIContext * ctx,
const CMPIResult * rslt,
const CMPIObjectPath * op,
const char * query,
const char * lang)
{
/* Return status of CIM operations. */
CMPIStatus status = {CMPI_RC_ERR_NOT_SUPPORTED, NULL};
_CMPI_TRACE(1, ("TST_MethodResultExecQuery() called, ctx %p, rslt %p, op %p,"
" query %s, lang %s", ctx, rslt, op, query, lang));
_CMPI_TRACE(1, ("TST_MethodResultExecQuery() %s",
(status.rc == CMPI_RC_OK)? "succeeded":"failed"));
return status;
}
// associatorMIFT
//
CMPIStatus TST_MethodResultAssociatorNames(
CMPIAssociationMI* self,
const CMPIContext* ctx,
const CMPIResult* rslt,
const CMPIObjectPath* op,
const char* assocClass,
const char* resultClass,
const char* role,
const char* resultRole)
{
CMPIStatus status = {CMPI_RC_ERR_NOT_SUPPORTED, NULL};
_CMPI_TRACE(1, ("associatorNames() called, ctx %p, rslt %p, op %p,"
" assocClass %s, resultClass %s, role %s, resultRole %s",
ctx, rslt, op, assocClass, resultClass, role, resultRole));
_CMPI_TRACE(1, ("associatorNames() %s",
(status.rc == CMPI_RC_OK)? "succeeded":"failed"));
return status;
}
/***************************************************************************/
CMPIStatus TST_MethodResultAssociators(
CMPIAssociationMI* self,
const CMPIContext* ctx,
const CMPIResult* rslt,
const CMPIObjectPath* op,
const char* assocClass,
const char* resultClass,
const char* role,
const char* resultRole,
const char** properties)
{
CMPIStatus status = {CMPI_RC_ERR_NOT_SUPPORTED, NULL};
_CMPI_TRACE(1, ("associators() called, ctx %p, rslt %p, op %p,"
" assocClass %s, resultClass %s, role %s, resultRole %s",
ctx, rslt, op, assocClass, resultClass, role, resultRole));
_CMPI_TRACE(1, ("associators() %s",
(status.rc == CMPI_RC_OK)? "succeeded":"failed"));
return status;
}
/***************************************************************************/
CMPIStatus TST_MethodResultReferenceNames(
CMPIAssociationMI* self,
const CMPIContext* ctx,
const CMPIResult* rslt,
const CMPIObjectPath* op,
const char* resultClass,
const char* role)
{
CMPIStatus status = {CMPI_RC_ERR_NOT_SUPPORTED, NULL};
_CMPI_TRACE(1, ("referenceNames() called, ctx %p, rslt %p, op %p,"
" resultClass %s, role %s", ctx, rslt, op, resultClass, role));
_CMPI_TRACE(1, ("referenceNames() %s",
(status.rc == CMPI_RC_OK)? "succeeded":"failed"));
return status;
}
/***************************************************************************/
CMPIStatus TST_MethodResultReferences(
CMPIAssociationMI* self,
const CMPIContext* ctx,
const CMPIResult* rslt,
const CMPIObjectPath* op,
const char* resultClass,
const char* role,
const char** properties)
{
CMPIStatus status = {CMPI_RC_ERR_NOT_SUPPORTED, NULL};
_CMPI_TRACE(1, ("references() called, ctx %p, rslt %p, op %p,"
" resultClass %s, role %s, properties %p",
ctx, rslt, op, resultClass, role, properties));
_CMPI_TRACE(1, ("references() %s",
(status.rc == CMPI_RC_OK)? "succeeded":"failed"));
return status;
}
static void print_instance(CMPIInstance *inst, int indent)
{
int i, j;
CMPIStatus st;
CMPIData p;
CMPIString *str;
CMPIObjectPath *path;
if (inst == NULL) {
for (j=0; j<indent; j++) fprintf(stderr, " ");
fprintf(stderr, "(NULL)\n");
return;
}
path = inst->ft->getObjectPath(inst, &st);
str = path->ft->getClassName(path, &st);
for (j=0; j<indent; j++) fprintf(stderr, " ");
fprintf(stderr, "class: %s\n", CMGetCharPtr(str));
for (i=0; i<inst->ft->getPropertyCount(inst, &st); i++) {
p = inst->ft->getPropertyAt(inst, i, &str, &st);
for (j=0; j<indent; j++) fprintf(stderr, " ");
fprintf(stderr, "Property: %s\n", CMGetCharPtr(str));
if (p.type == CMPI_instance)
print_instance(p.value.inst, indent + 4);
if (p.type == (CMPI_instance | CMPI_ARRAY)){
CMPIArray *a = p.value.array;
int k, siz;
if (!a) {
for (j=0; j<indent+4; j++) fprintf(stderr, " ");
fprintf(stderr, "(empty array)\n");
continue;
}
siz = a->ft->getSize(a, &st);
for (j=0; j<indent+4; j++) fprintf(stderr, " ");
fprintf(stderr, "array %d{\n", siz);
for (k=0; k<siz; k++){
CMPIData q = a->ft->getElementAt(a, k, &st);
print_instance(q.value.inst, indent+8);
}
for (j=0; j<indent+4; j++) fprintf(stderr, " ");
fprintf(stderr, "} array\n");
}
}
}
static void get_inst(const CMPIObjectPath *op, const CMPIContext *ctx, const char* classname)
{
CMPIStatus status = {CMPI_RC_OK, NULL};
CMPIObjectPath *path;
CMPIInstance *inst;
CMPIString *ns;
CMPIValue vid;
ns=CMGetNameSpace(op, &status);
path = CMNewObjectPath(_broker, CMGetCharPtr(ns), classname, &status);
vid.string = CMNewString(_broker, "TestInstanceID", &status);
CMAddKey(path, "InstanceID", &vid, CMPI_string);
/* call GetInstance */
inst = CBGetInstance(_broker, ctx, path, NULL, &status);
print_instance(inst, 4);
}
/***************************************************************************/
CMPIStatus TST_MethodResultInvokeMethod(
CMPIMethodMI* self,
const CMPIContext* ctx,
const CMPIResult* rslt,
const CMPIObjectPath* op,
const char* method,
const CMPIArgs* in,
CMPIArgs* out)
{
CMPIStatus status = {CMPI_RC_OK, NULL};
get_inst(op, ctx, "TST_MethodResult");
_CMPI_TRACE(1, ("invokeMethod() %s",
(status.rc == CMPI_RC_OK)? "succeeded":"failed"));
return status;
}
/***************************************************************************/
CMMethodMIStub( TST_MethodResult, TST_MethodResult, _broker, CMNoHook);
CMInstanceMIStub( TST_MethodResult, TST_MethodResult, _broker, CMNoHook);
//CMAssociationMIStub( TST_MethodResult, TST_MethodResult, _broker, CMNoHook);
register.mof
(text/x-mof, 673 B)
instance of PG_ProviderModule
{
Name = "cmpiMethodResult";
Location = "cmpiMethodResult";
Vendor = "RedHat";
Version = "0.0.1";
InterfaceType = "CMPI";
InterfaceVersion = "2.0.0";
ModuleGroupName = "cmpiMethodResult";
};
instance of PG_Provider
{
Name = "TST_MethodResult";
ProviderModuleName = "cmpiMethodResult";
};
instance of PG_ProviderCapabilities
{
ProviderModuleName = "cmpiMethodResult";
ProviderName = "TST_MethodResult";
CapabilityID = "TST_MethodResult";
ClassName = "TST_MethodResult";
Namespaces = { "root/cimv2" };
ProviderType = { 2,5 };
SupportedProperties = NULL;
SupportedMethods = NULL;
};