<?xml version="1.0" encoding="UTF-8"?>
<commit>
  <added type="array"/>
  <modified type="array">
    <modified>
      <diff>@@ -60,26 +60,49 @@ of this class.
     ipr_hash_table_destroy (&amp;self-&gt;queues);
 &lt;/method&gt;
 
-&lt;method name = &quot;set store&quot; template = &quot;function&quot;&gt;
+&lt;method name = &quot;store create&quot; return = &quot;store&quot;&gt;
     &lt;doc&gt;
-    Registers a store instance with the engine.  The caller is responsible
-    for creating the store using a xump_store_xyz_xump_store_new () method.
-    The engine will automatically destroy the store instance at shutdown
-    time.
+    Creates a new store instance of the specified type, and with the
+    specified name.  The caller must unlink the store when finished
+    using it.  The store is deleted only at exit; the caller can use
+    store_fetch to find it again, by name.  Returns null if the type
+    was not valid.
     &lt;/doc&gt;
-    &lt;argument name = &quot;store&quot; type = &quot;xump_store_t *&quot; /&gt;
+    &lt;argument name = &quot;self&quot; type = &quot;$(selftype) *&quot;&gt;Reference to self&lt;/argument&gt;
+    &lt;argument name = &quot;store type&quot; type = &quot;char *&quot;&gt;Name of factory&lt;/argument&gt;
+    &lt;argument name = &quot;store name&quot; type = &quot;char *&quot;&gt;Name of new store&lt;/argument&gt;
+    &lt;declare name = &quot;store&quot; type = &quot;xump_store_t *&quot; default = &quot;NULL&quot; /&gt;
+    &lt;local&gt;
+    ipr_looseref_t
+        *looseref;                      //  Store portals are in looseref list
+    &lt;/local&gt;
     //
-    xump__xump_store_bind (self, store);
-    xump_store_request_announce (store);
-    xump_store_unlink (&amp;store);
+    //  Look for factory and if we find it, create store portal
+    looseref = ipr_looseref_list_first (self-&gt;xump_store_factory_list);
+    while (looseref) {
+        xump_store_t
+            *factory = (xump_store_t *) (looseref-&gt;object);
+        if (streq (xump_store_name (factory), store_type)) {
+            store = xump_store_factory (factory, store_name);
+            break;                  //  Have a match
+        }
+        looseref = ipr_looseref_list_next (&amp;looseref);
+    }
+    if (store) {
+        xump__xump_store_bind (self, store);
+        xump_store_request_announce (store, TRUE);
+    }
+    //  Todo: we should interrogate the store to find out all the
+    //  queues it has, for stores that are persistent.
 &lt;/method&gt;
 
-&lt;method name = &quot;store&quot; return = &quot;store&quot;&gt;
+&lt;method name = &quot;store fetch&quot; return = &quot;store&quot;&gt;
     &lt;doc&gt;
     Returns the named store instance, or NULL if no such store was registered.
+    The caller gets a store reference that it must unlink when finished using.
     &lt;/doc&gt;
     &lt;argument name = &quot;self&quot; type = &quot;$(selftype) *&quot;&gt;Reference to self&lt;/argument&gt;
-    &lt;argument name = &quot;name&quot; type = &quot;char *&quot; /&gt;
+    &lt;argument name = &quot;store name&quot; type = &quot;char *&quot; /&gt;
     &lt;declare name = &quot;store&quot; type = &quot;xump_store_t *&quot; default = &quot;NULL&quot; /&gt;
     &lt;local&gt;
     ipr_looseref_t
@@ -88,21 +111,90 @@ of this class.
     //
     looseref = ipr_looseref_list_first (self-&gt;xump_store_list);
     while (looseref) {
-        store = (xump_store_t *) (looseref-&gt;object);
-        if (streq (store-&gt;name, name))
+        xump_store_t
+            *portal = (xump_store_t *) (looseref-&gt;object);
+        if (streq (xump_store_name (portal), store_name)) {
+            store = xump_store_link (portal);
+            break;                      //  We've found the matching store
+        }
+        looseref = ipr_looseref_list_next (&amp;looseref);
+    }
+&lt;/method&gt;
+
+&lt;method name = &quot;store delete&quot; template = &quot;function&quot;&gt;
+    &lt;doc&gt;
+    Delete a store specified by name.  Returns 0 if store was deleted, -1 if
+    the store did not exist.
+    &lt;/doc&gt;
+    &lt;argument name = &quot;store name&quot; type = &quot;char *&quot; /&gt;
+    &lt;local&gt;
+    ipr_looseref_t
+        *looseref;                      //  Store portals are in looseref list
+    &lt;/local&gt;
+    //
+    looseref = ipr_looseref_list_first (self-&gt;xump_store_list);
+    while (looseref) {
+        xump_store_t
+            *store = (xump_store_t *) (looseref-&gt;object);
+        if (streq (xump_store_name (store), store_name)) {
+            //  Need to explicitly destroy client looseref, portal
+            //  implementation does not do this properly.
+            //  Todo: fix portals.
+            ipr_looseref_destroy (&amp;store-&gt;client_looseref);
+            xump_store_request_announce (store, FALSE);
+            xump_store_destroy (&amp;store);
             break;                      //  We've found the matching store
-        store = NULL;
+        }
         looseref = ipr_looseref_list_next (&amp;looseref);
     }
+    if (!looseref)
+        rc = -1;                        //  Hit end of list with no match
+&lt;/method&gt;
+
+&lt;method name = &quot;queue create&quot; return = &quot;queue&quot;&gt;
+    &lt;doc&gt;
+    Create or fetch a queue in a specific store.  This method acts as a queue
+    constructor and returns a new queue object when successful.  The caller
+    must unlink the returned queue object when finished using it.  If the
+    queue name is null, invents a random queue name.
+    &lt;/doc&gt;
+    &lt;argument name = &quot;self&quot; type = &quot;$(selftype) *&quot; /&gt;
+    &lt;argument name = &quot;store name&quot; type = &quot;char *&quot; /&gt;
+    &lt;argument name = &quot;queue name&quot; type = &quot;char *&quot; /&gt;
+    &lt;declare name = &quot;queue&quot; type = &quot;xump_queue_t *&quot; /&gt;
+    &lt;local&gt;
+    xump_store_t
+        *store;
+    icl_shortstr_t
+        random_name;
+    &lt;/local&gt;
+    //
+    if (queue_name == NULL) {
+        queue_name = random_name;
+        do {
+            ipr_str_random (queue_name, &quot;Q-AAAAAA&quot;);
+        } until (ipr_hash_lookup (self-&gt;queues, queue_name) == NULL);
+    }
+    //
+    //  Todo: check for and prevent two queues with same name in different
+    //  stores.  Requires that self-&gt;queues is fully populated.
+    store = xump_store_fetch (self, store_name);
+    if (store) {
+        xump_store_request_queue_create (store, &amp;queue, queue_name);
+        //  We track the store for each known queue
+        ipr_hash_insert (self-&gt;queues, queue_name, store);
+        xump_store_unlink (&amp;store);
+    }
 &lt;/method&gt;
 
-&lt;method name = &quot;cache queue lookup&quot; return = &quot;queue&quot;&gt;
+&lt;method name = &quot;queue fetch&quot; return = &quot;queue&quot;&gt;
     &lt;doc&gt;
-    Looks for a queue among all store instances, using the queue name
-    cache.  Returns a new xump_queue object, or NULL.
+    Fetch a queue from any store.  This method acts as a queue constructor
+    and returns a new queue object when successful.  The caller must unlink
+    the returned queue object when finished using it.
     &lt;/doc&gt;
     &lt;argument name = &quot;self&quot; type = &quot;$(selftype) *&quot; /&gt;
-    &lt;argument name = &quot;name&quot; type = &quot;char *&quot; /&gt;
+    &lt;argument name = &quot;queue name&quot; type = &quot;char *&quot; /&gt;
     &lt;declare name = &quot;queue&quot; type = &quot;xump_queue_t *&quot; default = &quot;NULL&quot; /&gt;
     &lt;local&gt;
     xump_store_t
@@ -111,19 +203,19 @@ of this class.
         *looseref;                      //  Store portals are in looseref list
     &lt;/local&gt;
     //
-    //  Check in local queue cache, then ask each store
-    store = ipr_hash_lookup (self-&gt;queues, name);
-    if (store) {
-        queue = xump_queue_fetch (store, name);
-        icl_console_print (&quot;Queue found in store&quot;);
-    }
+    //  Check in local queue cache, then ask each store, since queue may
+    //  exist from a previous incarnation, if the store is persistent
+    store = ipr_hash_lookup (self-&gt;queues, queue_name);
+    if (store)
+        xump_store_request_queue_fetch (store, &amp;queue, queue_name);
     else {
         looseref = ipr_looseref_list_first (self-&gt;xump_store_list);
         while (looseref) {
             store = (xump_store_t *) (looseref-&gt;object);
-            queue = xump_queue_fetch (store, name);
+            xump_store_request_queue_fetch (store, &amp;queue, queue_name);
             if (queue) {
-                icl_console_print (&quot;Queue found by store&quot;);
+                //  We track the store for each known queue
+                ipr_hash_insert (self-&gt;queues, queue_name, store);
                 break;                      //  Found our queue
             }
             looseref = ipr_looseref_list_next (&amp;looseref);
@@ -131,10 +223,31 @@ of this class.
     }
 &lt;/method&gt;
 
+&lt;method name = &quot;queue delete&quot; template = &quot;function&quot;&gt;
+    &lt;doc&gt;
+    Delete a queue specified by name.  Returns 0 if queue was deleted, -1 if
+    the queue did not exist.
+    &lt;/doc&gt;
+    &lt;argument name = &quot;queue name&quot; type = &quot;char *&quot; /&gt;
+    &lt;local&gt;
+    xump_queue_t
+        *queue;
+    &lt;/local&gt;
+    //
+    queue = xump_queue_fetch (self, queue_name);
+    if (queue) {
+        ipr_hash_delete (self-&gt;queues, xump_queue_name (queue));
+        xump_store_request_queue_delete (xump_queue_store (queue), queue);
+        xump_queue_unlink (&amp;queue);
+    }
+    else
+        rc = -1;
+&lt;/method&gt;
+
 &lt;method name = &quot;selftest&quot;&gt;
     &lt;local&gt;
     xump_t
-        *xump;
+        *engine;
     xump_store_t
         *store;
     xump_queue_t
@@ -148,41 +261,64 @@ of this class.
     int count;
     &lt;/local&gt;
     //
-    xump = xump_new ();
-    xump_set_store (xump, xump_store_ram__xump_store_new (NULL, &quot;RAM1&quot;));
-    xump_set_store (xump, xump_store_ram__xump_store_new (NULL, &quot;RAM2&quot;));
+    //  Create new engine instance
+    engine = xump_new ();
+
+    //  Create portal factory for each store implementation
+    store = xump_store_ram__xump_store_factory (&quot;RAM&quot;);
+    xump__xump_store_bind (engine, store);
+    xump_store_unlink (&amp;store);
 
-    assert (xump_store (xump, &quot;RAM1&quot;) != NULL);
-    assert (xump_store (xump, &quot;RAM0&quot;) == NULL);
-    store = xump_store (xump, &quot;RAM1&quot;);
+    //  Check portal factory in action
+    store = xump_store_create (engine, &quot;ROM&quot;, &quot;store-0&quot;);
+    assert (!store);                    //  ROM is not a defined type
+    store = xump_store_create (engine, &quot;RAM&quot;, &quot;store-1&quot;);
+    assert (store);                     //  This should have worked
+    xump_store_unlink (&amp;store);
+
+    //  Check we can fetch store by name
+    store = xump_store_fetch (engine, &quot;store-0&quot;);
+    assert (!store);                    //  No such store
+    store = xump_store_fetch (engine, &quot;store-1&quot;);
+    assert (store);                     //  This should have worked
 
-    //  Check that the methods work
-    queue = xump_queue_create (store, &quot;Test queue&quot;);
+    //  Check queue methods
+    queue = xump_queue_create (engine, &quot;store-1&quot;, &quot;Test queue&quot;);
     assert (queue);
     xump_queue_unlink (&amp;queue);
-
-    queue = xump_queue_fetch (store, &quot;Test queue&quot;);
+    queue = xump_queue_fetch (engine, &quot;Test queue&quot;);
     assert (queue);
-    xump_queue_delete (&amp;queue);
-    assert (queue == NULL);
-    queue = xump_queue_fetch (store, &quot;Test queue&quot;);
+    xump_queue_unlink (&amp;queue);
+
+    assert (xump_queue_delete (engine, &quot;Test queue&quot;) == 0);
+    assert (xump_queue_delete (engine, &quot;Test queue&quot;) == -1);
+    queue = xump_queue_fetch (engine, &quot;Test queue&quot;);
     assert (queue == NULL);
 
-    //  Check methods on auto-named queue
-    queue = xump_queue_create (store, NULL);
+    //  Check auto-named queue creation
+    queue = xump_queue_create (engine, &quot;store-1&quot;, NULL);
     assert (queue);
     icl_shortstr_cpy (queue_name, xump_queue_name (queue));
     xump_queue_unlink (&amp;queue);
 
-    queue = xump_queue_fetch (store, queue_name);
-    assert (queue);
-    xump_queue_delete (&amp;queue);
-    assert (queue == NULL);
-    queue = xump_queue_fetch (store, queue_name);
+    assert (xump_queue_delete (engine, queue_name) == 0);
+    queue = xump_queue_fetch (engine, queue_name);
     assert (queue == NULL);
 
+    //  Check that we can work with selectors
+    queue = xump_queue_create (engine, &quot;store-1&quot;, NULL);
+    selector = xump_selector_create (queue, &quot;dest&quot;, &quot;EQ&quot;, &quot;address&quot;, XUMP_SELECTOR_COPY);
+    assert (selector);
+    xump_selector_unlink (&amp;selector);
+    selector = xump_selector_fetch (queue, 0);
+    assert (selector);
+    assert (xump_selector_operation (selector) == XUMP_SELECTOR_COPY);
+    xump_selector_delete (&amp;selector);
+    xump_queue_unlink (&amp;queue);
+
+#if 0
     //  Create a queue and post messages to it
-    queue = xump_queue_create (store, NULL);
+    queue = xump_queue_create (engine, &quot;store-1&quot;, NULL);
     icl_shortstr_cpy (queue_name, xump_queue_name (queue));
     message = xump_message_create (queue, &quot;address1&quot;, NULL, &quot;abc&quot;, 4);
     xump_message_unlink (&amp;message);
@@ -203,7 +339,7 @@ of this class.
     xump_queue_unlink (&amp;queue);
 
     //  Delete the messages and check they are gone
-    queue = xump_queue_fetch (store, queue_name);
+    queue = xump_queue_fetch (engine, queue_name);
     assert (xump_queue_size (queue) == 2);
 
     message = xump_message_fetch (queue, 0);
@@ -217,26 +353,17 @@ of this class.
     message = xump_message_fetch (queue, 0);
     assert (message == NULL);
     xump_queue_unlink (&amp;queue);
-    queue = xump_queue_fetch (store, queue_name);
+    queue = xump_queue_fetch (engine, queue_name);
     assert (xump_queue_size (queue) == 0);
+#endif
 
-    //  Check that we can work with selectors
-    selector = xump_selector_create (queue, &quot;dest&quot;, &quot;EQ&quot;, &quot;address&quot;, XUMP_SELECTOR_COPY);
-    assert (selector);
-    xump_selector_unlink (&amp;selector);
-    selector = xump_selector_fetch (queue, 0);
-    assert (selector);
-    assert (xump_selector_operation (selector) == XUMP_SELECTOR_COPY);
-    xump_selector_delete (&amp;selector);
-    xump_queue_unlink (&amp;queue);
+    xump_store_unlink (&amp;store);
 
-    //  Check engine API
-    queue = xump_cache_queue_lookup (xump, queue_name);
-    assert (queue);
-    assert (streq (xump_queue_name (queue), queue_name));
-    xump_queue_unlink (&amp;queue);
+    //  Check we can delete store by name
+    assert (xump_store_delete (engine, &quot;store-1&quot;) == 0);
+    assert (xump_store_delete (engine, &quot;store-1&quot;) == -1);
 
-    xump_destroy (&amp;xump);
+    xump_destroy (&amp;engine);
 &lt;/method&gt;
 
 &lt;/class&gt;</diff>
      <filename>xump.icl</filename>
    </modified>
    <modified>
      <diff>@@ -34,6 +34,8 @@ This class implements the create/fetch/delete access methods on the message.
     &lt;option name = &quot;links&quot; value = &quot;1&quot; /&gt;
 &lt;/inherit&gt;
 
+&lt;todo&gt;Queue reference must be name, not object&lt;/todo&gt;
+
 &lt;import class = &quot;xump&quot; /&gt;
 
 &lt;context readonly = &quot;1&quot;&gt;</diff>
      <filename>xump_message.icl</filename>
    </modified>
    <modified>
      <diff>@@ -61,52 +61,12 @@ This class implements the create/fetch/delete access methods on the queue.
     self-&gt;size = size;
 &lt;/method&gt;
 
-&lt;method name = &quot;destroy&quot; private = &quot;1&quot;&gt;
+&lt;method name = &quot;destroy&quot;&gt;
     xump_store_unlink (&amp;self-&gt;store);
     icl_mem_free (self-&gt;name);
     icl_mem_free (self-&gt;context);
 &lt;/method&gt;
 
-&lt;method name = &quot;create&quot; return = &quot;self&quot;&gt;
-    &lt;doc&gt;
-    This public method creates or fetches a queue in the store.  It acts
-    as a constructor and returns a new queue object when successful.  The
-    caller must unlink this queue object when finished using it.
-    &lt;/doc&gt;
-    &lt;argument name = &quot;store&quot; type = &quot;xump_store_t *&quot;&gt;Enclosing store&lt;/argument&gt;
-    &lt;argument name = &quot;name&quot; type = &quot;char *&quot;&gt;Queue name, if any&lt;/argument&gt;
-    &lt;declare name = &quot;self&quot; type = &quot;$(selftype) *&quot; /&gt;
-    //
-    xump_store_request_queue_create (store, &amp;self, name);
-&lt;/method&gt;
-
-&lt;method name = &quot;fetch&quot; return = &quot;self&quot;&gt;
-    &lt;doc&gt;
-    This public method fetches a queue from the store.  It acts as a
-    constructor and returns a new queue object when successful.  The
-    caller must unlink this queue object when finished using it.
-    &lt;/doc&gt;
-    &lt;argument name = &quot;store&quot; type = &quot;xump_store_t *&quot;&gt;Enclosing store&lt;/argument&gt;
-    &lt;argument name = &quot;name&quot; type = &quot;char *&quot;&gt;Queue name, if any&lt;/argument&gt;
-    &lt;declare name = &quot;self&quot; type = &quot;$(selftype) *&quot; /&gt;
-    //
-    xump_store_request_queue_fetch (store, &amp;self, name);
-&lt;/method&gt;
-
-&lt;method name = &quot;delete&quot;&gt;
-    &lt;doc&gt;
-    This public method deletes a queue in the store.  It acts as a
-    destructor and nullifies the provided queue object reference.
-    The queue object may already be destroyed.
-    &lt;/doc&gt;
-    &lt;argument name = &quot;self_p&quot; type = &quot;$(selftype) **&quot;&gt;Queue object ref&lt;/argument&gt;
-    assert (self_p);
-    if (*self_p) {
-        xump_store_request_queue_delete ((*self_p)-&gt;store, *self_p);
-        self_unlink (self_p);
-    }
-&lt;/method&gt;
-
 &lt;method name = &quot;selftest&quot; /&gt;
 
 &lt;/class&gt;</diff>
      <filename>xump_queue.icl</filename>
    </modified>
    <modified>
      <diff>@@ -31,6 +31,8 @@ selector. Note: probably needs addition of headers object for header based
 routing.
 &lt;/doc&gt;
 
+&lt;todo&gt;Queue reference must be name, not object&lt;/todo&gt;
+
 &lt;inherit class = &quot;icl_object&quot;&gt;
     &lt;option name = &quot;alloc&quot; value = &quot;cache&quot; /&gt;
     &lt;option name = &quot;links&quot; value = &quot;1&quot; /&gt;</diff>
      <filename>xump_selector.icl</filename>
    </modified>
    <modified>
      <diff>@@ -36,12 +36,13 @@
 &lt;import class = &quot;xump&quot; /&gt;
 
 &lt;context&gt;
-    icl_shortstr_t
-        name;                           //  Store name
+    &lt;property name = &quot;name&quot; type = &quot;char *&quot; readonly = &quot;1&quot; /&gt;
 &lt;/context&gt;
 
 &lt;data&gt;
-    &lt;request name = &quot;announce&quot; /&gt;
+    &lt;request name = &quot;announce&quot;&gt;
+        &lt;field name = &quot;opening&quot; type = &quot;Bool&quot;&gt;Or, closing&lt;/field&gt;
+    &lt;/request&gt;
 
     &lt;request name = &quot;queue create&quot;&gt;
         &lt;doc&gt;
@@ -153,7 +154,12 @@
     Creates a new store instance object.
     &lt;/doc&gt;
     &lt;argument name = &quot;name&quot; type = &quot;char *&quot; /&gt;
-    icl_shortstr_cpy (self-&gt;name, name);
+    //
+    self-&gt;name = icl_mem_strdup (name);
+&lt;/method&gt;
+
+&lt;method name = &quot;destroy&quot;&gt;
+    icl_mem_free (self-&gt;name);
 &lt;/method&gt;
 
 &lt;/class&gt;</diff>
      <filename>xump_store.icl</filename>
    </modified>
    <modified>
      <diff>@@ -49,34 +49,25 @@ xump_store_ram_message.icl class.
 &lt;/method&gt;
 
 &lt;method name = &quot;announce&quot;&gt;
-    icl_console_print (&quot;I: initializing RAM-based storage instance '%s'&quot;, portal-&gt;name);
+    icl_console_print (&quot;I: %s RAM-based storage instance '%s'&quot;,
+        opening? &quot;initializing&quot;: &quot;destroying&quot;, portal-&gt;name);
 &lt;/method&gt;
 
 &lt;method name = &quot;queue create&quot;&gt;
     &lt;local&gt;
-    icl_shortstr_t
-        queue_name;
     xump_store_ram_queue_t
         *ram_queue;
     &lt;/local&gt;
     //
     assert (queue_p);
-    //  If queue is unnamed, invent a unique random name now
-    if (name)
-        icl_shortstr_cpy (queue_name, name);
-    else
-        do {
-            ipr_str_random (queue_name, &quot;Q-AAAAAA&quot;);
-        } until (ipr_hash_lookup (self-&gt;queues, queue_name) == NULL);
-
     //  Either create or fetch RAM queue
-    ram_queue = ipr_hash_lookup (self-&gt;queues, queue_name);
+    ram_queue = ipr_hash_lookup (self-&gt;queues, name);
     if (ram_queue == NULL) {
-        ram_queue = xump_store_ram_queue_new (queue_name);
-        ipr_hash_insert (self-&gt;queues, queue_name, ram_queue);
+        ram_queue = xump_store_ram_queue_new (name);
+        ipr_hash_insert (self-&gt;queues, name, ram_queue);
     }
     //  Create queue object for caller
-    *queue_p = xump_queue_new (portal, queue_name, 0);
+    *queue_p = xump_queue_new (portal, name, 0);
 &lt;/method&gt;
 
 &lt;method name = &quot;queue fetch&quot;&gt;</diff>
      <filename>xump_store_ram.icl</filename>
    </modified>
  </modified>
  <removed type="array"/>
  <parents type="array">
    <parent>
      <id>c823aa05744257d8a7c7a298649918c472200474</id>
    </parent>
  </parents>
  <author>
    <name>pieterh</name>
    <email>ph@imatix.com</email>
  </author>
  <url>http://github.com/pieterh/xump/commit/a9219f1f1bd9d03cc736c1e643883e0513ddda4f</url>
  <id>a9219f1f1bd9d03cc736c1e643883e0513ddda4f</id>
  <committed-date>2009-06-16T01:15:07-07:00</committed-date>
  <authored-date>2009-06-16T01:15:07-07:00</authored-date>
  <message>Reworking engine api for queues and stores</message>
  <tree>97e1d901172abf9376f7d8503418c02c4a0594d5</tree>
  <committer>
    <name>pieterh</name>
    <email>ph@imatix.com</email>
  </committer>
</commit>
