WvStreams
wvmoniker.cc
00001 /*
00002  * Worldvisions Weaver Software:
00003  *   Copyright (C) 1997-2002 Net Integration Technologies, Inc.
00004  * 
00005  * Support for monikers, which are strings that you can pass to a magic
00006  * factory to get objects supporting a particular interface.  See wvmoniker.h.
00007  */
00008 #include "wvmonikerregistry.h"
00009 #include "strutils.h"
00010 #include <wvassert.h>
00011 #include <stdio.h>
00012 #include "wvscatterhash.h"
00013 
00014 #if 0
00015 # define DEBUGLOG(fmt, args...) fprintf(stderr, fmt, ## args)
00016 #else
00017 #ifndef _MSC_VER
00018 # define DEBUGLOG(fmt, args...)
00019 #else  // MS Visual C++ doesn't support varags preproc macros
00020 # define DEBUGLOG
00021 #endif
00022 #endif
00023 
00024 
00025 static unsigned WvHash(const UUID &_uuid)
00026 {
00027     unsigned val = 0;
00028     unsigned int *uuid = (unsigned int *)&_uuid;
00029     int max = sizeof(UUID)/sizeof(*uuid);
00030     
00031     for (int count = 0; count < max; count++)
00032         val += uuid[count];
00033     
00034     return val;
00035 }
00036 
00037 
00038 DeclareWvScatterDict(WvMonikerRegistry, UUID, reg_iid);
00039 static WvMonikerRegistryDict *regs;
00040   
00041 
00042 
00043 WvMonikerRegistry::WvMonikerRegistry(const UUID &iid) 
00044     : reg_iid(iid)
00045 {
00046     DEBUGLOG("WvMonikerRegistry creating.\n");
00047     refcount = 0;
00048 }
00049 
00050 
00051 WvMonikerRegistry::~WvMonikerRegistry()
00052 {
00053     DEBUGLOG("WvMonikerRegistry destroying.\n");
00054 }
00055 
00056 
00057 void WvMonikerRegistry::add(WvStringParm id, WvMonikerCreateFunc *func,
00058                             const bool override)
00059 {
00060     DEBUGLOG("WvMonikerRegistry register(%s).\n", id.cstr());
00061     if (!override) {
00062         RegistrationList::Iter i(list);
00063         for (i.rewind(); i.next(); )
00064             assert(i.ptr()->id != id); //no duplicates without override
00065     }
00066     list.prepend(new Registration(id, func), true);
00067 }
00068 
00069 
00070 void WvMonikerRegistry::del(WvStringParm id)
00071 {
00072     DEBUGLOG("WvMonikerRegistry unregister(%s).\n", id.cstr());
00073     RegistrationList::Iter i(list);
00074     for (i.rewind(); i.next(); )
00075     {
00076         if (i.ptr()->id == id) {
00077             i.unlink();
00078             return;
00079         }
00080     }
00081 
00082     //We should never get here, as we should never be removing elements which don't exist
00083     assert(false);
00084 }
00085 
00086 
00087 void *WvMonikerRegistry::create(WvStringParm _s, IObject *obj)
00088 {
00089     WvString t(_s);
00090     WvString s(trim_string(t.edit()));
00091 
00092     char *cptr = strchr(s.edit(), ':');
00093     if (cptr)
00094         *cptr++ = 0;
00095     else
00096         cptr = (char*)"";
00097     
00098     DEBUGLOG("WvMonikerRegistry create object ('%s' '%s').\n", s.cstr(), cptr);
00099     
00100     RegistrationList::Iter i(list);
00101     for (i.rewind(); i.next(); )
00102     {
00103         if (i.ptr()->id == s)
00104             return i.ptr()->func(cptr, obj);
00105     }
00106 
00107     return NULL;
00108 }
00109 
00110 
00111 WvMonikerRegistry *WvMonikerRegistry::find_reg(const UUID &iid)
00112 {
00113     DEBUGLOG("WvMonikerRegistry find_reg.\n");
00114     
00115     if (!regs)
00116         regs = new WvMonikerRegistryDict(10);
00117     
00118     WvMonikerRegistry *reg = (*regs)[iid];
00119     
00120     if (!reg)
00121     {
00122         // we have to make one!
00123         reg = new WvMonikerRegistry(iid);
00124         regs->add(reg, true);
00125         reg->addRef(); // one reference for being in the list at all
00126     }
00127     
00128     reg->addRef();
00129     return reg;
00130 }
00131 
00132 
00133 IObject *WvMonikerRegistry::getInterface(const UUID &uuid)
00134 {
00135 #if 0
00136     if (uuid.equals(IObject_IID))
00137     {
00138         addRef();
00139         return this;
00140     }
00141 #endif
00142     
00143     // we don't really support any interfaces for now.
00144     
00145     return 0;
00146 }
00147 
00148 
00149 unsigned int WvMonikerRegistry::addRef()
00150 {
00151     DEBUGLOG("WvMonikerRegistry addRef.\n");
00152     return ++refcount;
00153 }
00154 
00155 
00156 unsigned int WvMonikerRegistry::release()
00157 {
00158     DEBUGLOG("WvMonikerRegistry release.\n");
00159     
00160     if (--refcount > 1)
00161         return refcount;
00162     
00163     if (refcount == 1)
00164     {
00165         // the list has one reference to us, but it's no longer needed.
00166         // Note: remove() will delete this object!
00167         regs->remove(this);
00168         if (regs->isempty())
00169         {
00170             delete regs;
00171             regs = NULL;
00172         }
00173         return 0;
00174     }
00175     
00176     /* protect against re-entering the destructor */
00177     refcount = 1;
00178     delete this;
00179     return 0;
00180 }
00181 
00182 
00183 WvMonikerBase::WvMonikerBase(const UUID &iid, WvStringParm _id, 
00184                              WvMonikerCreateFunc *func, const bool override)
00185     : id(_id)
00186 {
00187     DEBUGLOG("WvMoniker creating(%s).\n", id.cstr());
00188     reg = WvMonikerRegistry::find_reg(iid);
00189     if (reg)
00190         reg->add(id, func, override);
00191 }
00192 
00193 
00194 WvMonikerBase::~WvMonikerBase()
00195 {
00196     DEBUGLOG("WvMoniker destroying(%s).\n", id.cstr());
00197     if (reg)
00198     {
00199         reg->del(id);
00200         WVRELEASE(reg);
00201     }
00202 }
00203 
00204 
00205 void *wvcreate(const UUID &iid, WvStringParm moniker, IObject *obj)
00206 {
00207     assert(!moniker.isnull());
00208     // fprintf(stderr, "wvcreate: Looking for '%s'\n", moniker.cstr());
00209     WvMonikerRegistry *reg = WvMonikerRegistry::find_reg(iid);
00210     if (reg)
00211     {
00212         void *ret = reg->create(moniker, obj);
00213         WVRELEASE(reg);
00214         return ret;
00215     }
00216     else
00217         return NULL;
00218 }