With parameters in ContractIDs I mean something like this:
"@xyz.com/some-module/foobar;1?param1=small;param2=blue"
where param1 and param2 can take values of some predefined
sets {'small', 'medium', 'big'} and {'red', 'blue'}.
Further, it should be acceptable that a client may _not_ resort
parameters like this:
"@xyz.com/some-module/foobar;1?param2=blue;param1=small"
1. Are there established patterns of design to realize such stuff?
a) .. where there is one implementing class and the ContractID
parameters are used to initialize some member vars of the
implementing class
b) .. where there are multiple implementing classes and the
parameters are used to choose the appropriate implementation
i) .. and the different implementations are manually programmed
implementation classes
ii) .. and the different implementations are compile time
generated via C++ template classes
2. If there are different ways of doing it, what questions should
I ask myself in choosing my way?
I did find no dox for XPCOM regarding this special topic .. consequently
read
through the Mozilla sources. The results of this journey are documented
below,
which got a bit lengthy -- sorry. There are fundamental questions left which
puzzle me.
The only case which is quite clear to me is 1.b.i - where nothing special
happens
at all, in essence.
Any hints would be greatly appreciated.
Tobias
P.S. Regarding 1.b.ii, I did manage to get it going by defining a slightly
extended macro:
#define NS_IMPL_ISUPPORTS1_TEMPL(_template, _class, _interface) \
_template NS_IMPL_ADDREF(_class) \
_template NS_IMPL_RELEASE(_class) \
_template NS_IMPL_QUERY_INTERFACE1(_class, _interface)
Full details can be found below. I did not manage to get this stuff going
with
the nsIClassInfo support, facilitating interface flattening and such.
Note: I'm refering to the sources of Mozilla-0.9.7-RELEASE.
Different CONTRACTIDs - same CLSID - GenericFactory
****************************************************************************
********
Please consider ..
@mozilla.org/uriloader/content-handler;1?type=text/plain
CLSID c2343730-dc2c-11d3-98b3-001083010e9b
@mozilla.org/uriloader/content-handler;1?type=text/xml
CLSID c2343730-dc2c-11d3-98b3-001083010e9b
@mozilla.org/uriloader/content-handler;1?type=image/jpeg
CLSID c2343730-dc2c-11d3-98b3-001083010e9b
I want to understand how the ?type=.. CONTRACTID "parameter"
gets mapped to the right implementation. My naive thinking was, that
the value for this parameter must somehow be provided as an argument
to an constructor of the implementation class behind the single CLSID.
nsBrowserInstance.cpp declares a
class nsBrowserContentHandler : public nsIContentHandler, public
nsICmdLineHandler
(Line 832) with a plain standard constructor:
nsBrowserContentHandler::nsBrowserContentHandler()
{
NS_INIT_ISUPPORTS();
}
On line 1012, a standard macro from nsIGenericFactory.h expands
to a static constructor function, which again calls
nsBrowserContentHandler::nsBrowserContentHandler()
NS_GENERIC_FACTORY_CONSTRUCTOR(nsBrowserContentHandler)
and the handler components for different types are declared just below
static nsModuleComponentInfo components[] = {
...
{ "Browser Content Handler",
NS_BROWSERCONTENTHANDLER_CID,
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"text/html",
nsBrowserContentHandlerConstructor
},
...
{ "Browser Content Handler",
NS_BROWSERCONTENTHANDLER_CID,
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"text/xml",
nsBrowserContentHandlerConstructor
},
...
{ "Browser Content Handler",
NS_BROWSERCONTENTHANDLER_CID,
NS_CONTENT_HANDLER_CONTRACTID_PREFIX"image/jpeg",
nsBrowserContentHandlerConstructor
},
...
};
NS_CONTENT_HANDLER_CONTRACTID_PREFIX is #defined in nsCURLILoader.idl as
#define NS_CONTENT_HANDLER_CONTRACTID_PREFIX NS_CONTENT_HANDLER_CONTRACTID
"?type="
#define NS_CONTENT_HANDLER_CONTRACTID
"@mozilla.org/uriloader/content-handler;1"
Obviously, all handlers are registered with the same CLSID and use
the same constructor, which takes _no_ arguments and essentially does
nothing
(but init ISupports). The only difference seems to be the contract IDs. But
how
get these passed in via nsGenericFactory or the ComponentManager ??
In other words, what puzzles me is how these different contract IDs get
disptached to different content handler implementations??
A minor point is, that obviously this breaks a one-to-one correspondence
between CLSIDs and CONTRACTIDs (if this was ever a goal).
****************************************************************************
********
Different CONTRACTIDs - different CLSIDs - GenericFactory
****************************************************************************
********
This seems to be the case 1.b.i. - essentially nothing magically is
happening here.
Please consider ..
@mozilla.org/intl/unicode/decoder;1?charset=ISO-8859-1
CLSID a3254cb0-8e20-11d2-8a98-00600811a836
@mozilla.org/intl/unicode/decoder;1?charset=windows-1252
CLSID 7c657d15-ec5e-11d2-8aac-00600811a836
@mozilla.org/intl/unicode/decoder;1?charset=UTF-8
CLSID 5534ddc0-dd96-11d2-8aac-00600811a836
and ..
@mozilla.org/intl/unicode/decoder;1?charset=windows-1250
CLSID 7c657d14-ec5e-11d2-8aac-00600811a836
@mozilla.org/intl/unicode/decoder;1?charset=us-ascii
CLSID ba6151b9-1dfa-11d3-b3bf-00805f8a6670
The ContractIDs of the former 3 are defined in ..
http://lxr.mozilla.org/seamonkey/source/intl/uconv/src/nsCP1252ToUnicode.h
#define NS_CP1252TOUNICODE_CONTRACTID
"@mozilla.org/intl/unicode/decoder;1?charset=windows-1252"
http://lxr.mozilla.org/seamonkey/source/intl/uconv/src/nsISO88591ToUnicode.h
#define NS_ISO88591TOUNICODE_CONTRACTID
"@mozilla.org/intl/unicode/decoder;1?charset=ISO-8859-1"
http://lxr.mozilla.org/seamonkey/source/intl/uconv/src/nsUTF8ToUnicode.h
#define NS_UTF8TOUNICODE_CONTRACTID
"@mozilla.org/intl/unicode/decoder;1?charset=UTF-8"
.. and assembled into a module in ..
http://lxr.mozilla.org/seamonkey/source/intl/uconv/src/nsUConvModule.cpp
94 NS_GENERIC_FACTORY_CONSTRUCTOR(nsISO88591ToUnicode)
95 NS_GENERIC_FACTORY_CONSTRUCTOR(nsCP1252ToUnicode)
96 NS_GENERIC_FACTORY_CONSTRUCTOR(nsMacRomanToUnicode)
97 NS_GENERIC_FACTORY_CONSTRUCTOR(nsUTF8ToUnicode)
113 static nsModuleComponentInfo components[] =
114 {
115 {
...
155 {
156 "ISO-8859-1 To Unicode Converter", NS_ISO88591TOUNICODE_CID,
157 NS_ISO88591TOUNICODE_CONTRACTID,
158 nsISO88591ToUnicodeConstructor,
159 nsISO88591ToUnicodeRegSelf, nsISO88591ToUnicodeUnRegSelf
160 },
161 {
162 "windows-1252 To Unicode Converter", NS_CP1252TOUNICODE_CID,
163 NS_CP1252TOUNICODE_CONTRACTID,
164 nsCP1252ToUnicodeConstructor,
165 nsCP1252ToUnicodeRegSelf, nsCP1252ToUnicodeUnRegSelf
166 },
...
173 {
174 "UTF-8 To Unicode Converter", NS_UTF8TOUNICODE_CID,
175 NS_UTF8TOUNICODE_CONTRACTID,
176 nsUTF8ToUnicodeConstructor,
177 nsUTF8ToUnicodeRegSelf, nsUTF8ToUnicodeUnRegSelf
178 },
...
The ContractIDs of the latter 2 are defined on the basis of ..
http://lxr.mozilla.org/seamonkey/source/intl/uconv/public/nsIUnicodeDecoder.
h
#define NS_UNICODEDECODER_CONTRACTID_BASE
"@mozilla.org/intl/unicode/decoder;1?charset="
.. and assembled into a module in ..
http://lxr.mozilla.org/seamonkey/source/intl/uconv/ucvlatin/nsUCvLatinModule
.cpp
309 NS_GENERIC_FACTORY_CONSTRUCTOR(nsAsciiToUnicode);
329 NS_GENERIC_FACTORY_CONSTRUCTOR(nsCP1250ToUnicode);
431 static nsModuleComponentInfo components[] =
432 {
433 {
434 DECODER_NAME_BASE "us-ascii" , NS_ASCIITOUNICODE_CID,
435 NS_UNICODEDECODER_CONTRACTID_BASE "us-ascii",
436 nsAsciiToUnicodeConstructor ,
437 nsAsciiToUnicodeRegSelf , nsAsciiToUnicodeUnRegSelf
438 },
...
553 {
554 DECODER_NAME_BASE "windows-1250" , NS_CP1250TOUNICODE_CID,
555 NS_UNICODEDECODER_CONTRACTID_BASE "windows-1250",
556 nsCP1250ToUnicodeConstructor ,
557 nsCP1250ToUnicodeRegSelf , nsCP1250ToUnicodeUnRegSelf
558 },
****************************************************************************
********
Different CONTRACTIDs - different CLSIDs - GenericFactory - Template Classes
****************************************************************************
********
I defined a sligtly extended variant of NS_IMPL_ISUPPORTS1
http://lxr.mozilla.org/seamonkey/source/xpcom/base/nsISupportsImpl.h#754
#define NS_IMPL_ISUPPORTS1_TEMPL(_template, _class, _interface) \
_template NS_IMPL_ADDREF(_class) \
_template NS_IMPL_RELEASE(_class) \
_template NS_IMPL_QUERY_INTERFACE1(_class, _interface)
This will expand to templated member functions for addref, release and QI.
/**
* NS_IMPL_ISUPPORTS1_TEMPL expands to a simple implementation of nsISupports
* for template classes
*/
NS_IMPL_ISUPPORTS1_TEMPL(template<class VT>, btCSequenceSeries<VT>,
btISequenceSeries)
Now I typedef'ed my template class for all the parameters (that are type
traits)
I support:
template<class VT> class btCSequenceSeries;
typedef btCSequenceSeries<VtBool> btCSequenceSeriesVtBool;
typedef btCSequenceSeries<VtUint8> btCSequenceSeriesVtUint8;
typedef btCSequenceSeries<VtUint16> btCSequenceSeriesVtUint16;
typedef btCSequenceSeries<VtUint32> btCSequenceSeriesVtUint32;
typedef btCSequenceSeries<VtDouble> btCSequenceSeriesVtDouble;
.. and plainly defined different CLSIDs ..
#define BT_SEQUENCE_SERIES_BOOL_CID \
{ 0x83cba871, 0x24c7, 0x46ba, { 0xa3, 0xb9, 0x8f, 0xc3, 0xf9, 0x49, 0x00,
0xd7 } }
#define BT_SEQUENCE_SERIES_UINT8_CID \
{ 0x325dce7b, 0x1a9f, 0x480f, { 0x84, 0xe2, 0x3d, 0x85, 0xec, 0xb5, 0xe5,
0x74 } }
#define BT_SEQUENCE_SERIES_UINT16_CID \
{ 0x31fdd1e0, 0x04b8, 0x4bd3, { 0x88, 0x2f, 0x0b, 0x0e, 0xf0, 0xdd, 0x18,
0x99 } }
#define BT_SEQUENCE_SERIES_UINT32_CID \
{ 0x1884b872, 0x2a01, 0x47fa, { 0x9b, 0x22, 0x7a, 0x1b, 0xfe, 0x29, 0x95,
0x0a } }
#define BT_SEQUENCE_SERIES_DOUBLE_CID \
{ 0x6faa0d74, 0x5d27, 0x47b4, { 0xaf, 0xdb, 0x5b, 0x0b, 0xf6, 0x74, 0xe1,
0xba } }
and CONTRACTIDs for all supported implementations :
#define BT_SEQUENCE_SERIES_BOOL_CONTRACTID \
"@xyz.com/omk/sequence-series;1?vtype=bool"
#define BT_SEQUENCE_SERIES_UINT8_CONTRACTID \
"@xyz.com/omk/sequence-series;1?vtype=uint8"
#define BT_SEQUENCE_SERIES_UINT16_CONTRACTID \
"@xyz.com/omk/sequence-series;1?vtype=uint16"
#define BT_SEQUENCE_SERIES_UINT32_CONTRACTID \
"@xyz.com/omk/sequence-series;1?vtype=uint32"
#define BT_SEQUENCE_SERIES_DOUBLE_CONTRACTID \
"@xyz.com/omk/sequence-series;1?vtype=double"
The module containing these components builds standard factory-ctors:
NS_GENERIC_FACTORY_CONSTRUCTOR(btCSequenceSeriesVtBool)
NS_GENERIC_FACTORY_CONSTRUCTOR(btCSequenceSeriesVtUint8)
NS_GENERIC_FACTORY_CONSTRUCTOR(btCSequenceSeriesVtUint16)
NS_GENERIC_FACTORY_CONSTRUCTOR(btCSequenceSeriesVtUint32)
NS_GENERIC_FACTORY_CONSTRUCTOR(btCSequenceSeriesVtDouble)
.. and registers all components:
static nsModuleComponentInfo components[] =
{
{
"BT Sequence-Series Component",
BT_SEQUENCE_SERIES_BOOL_CID,
BT_SEQUENCE_SERIES_BOOL_CONTRACTID,
btCSequenceSeriesVtBoolConstructor,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0
},
{
"BT Sequence-Series Component",
BT_SEQUENCE_SERIES_UINT8_CID,
BT_SEQUENCE_SERIES_UINT8_CONTRACTID,
btCSequenceSeriesVtUint8Constructor,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
0
},
...
}
Quiet straightforward. Providing for a templated variant of
NS_IMPL_ISUPPORTS1_CI
is not that straight - I'm still wading throu the preprocessor stuff.
****************************************************************************
*******