Explorar o código

Promoted Zend_Queue and Zend_Service_Amazon_Sqs to trunk

git-svn-id: http://framework.zend.com/svn/framework/standard/trunk@16590 44c647ce-9c0f-0410-b52a-842ac1e357ba
matthew %!s(int64=16) %!d(string=hai) anos
pai
achega
8c9b602570
Modificáronse 61 ficheiros con 10535 adicións e 0 borrados
  1. 11 0
      documentation/manual/en/manual.xml.in
  2. 426 0
      documentation/manual/en/module_specs/Zend_Queue-Adapters.xml
  3. 135 0
      documentation/manual/en/module_specs/Zend_Queue-Custom.xml
  4. 49 0
      documentation/manual/en/module_specs/Zend_Queue-Example.xml
  5. 175 0
      documentation/manual/en/module_specs/Zend_Queue-Framework.xml
  6. 55 0
      documentation/manual/en/module_specs/Zend_Queue-Introduction.xml
  7. 48 0
      documentation/manual/en/module_specs/Zend_Queue-Stomp.xml
  8. 308 0
      documentation/manual/en/module_specs/Zend_Service_Amazon_Sqs.xml
  9. 571 0
      library/Zend/Queue.php
  10. 191 0
      library/Zend/Queue/Adapter/AdapterAbstract.php
  11. 174 0
      library/Zend/Queue/Adapter/AdapterInterface.php
  12. 333 0
      library/Zend/Queue/Adapter/Apachemq.php
  13. 352 0
      library/Zend/Queue/Adapter/Array.php
  14. 482 0
      library/Zend/Queue/Adapter/Db.php
  15. 51 0
      library/Zend/Queue/Adapter/Db/Message.php
  16. 51 0
      library/Zend/Queue/Adapter/Db/Queue.php
  17. 75 0
      library/Zend/Queue/Adapter/Db/queue.sql
  18. 404 0
      library/Zend/Queue/Adapter/Memcacheq.php
  19. 174 0
      library/Zend/Queue/Adapter/Null.php
  20. 35 0
      library/Zend/Queue/Exception.php
  21. 230 0
      library/Zend/Queue/Message.php
  22. 285 0
      library/Zend/Queue/Message/Iterator.php
  23. 173 0
      library/Zend/Queue/Stomp/Client.php
  24. 274 0
      library/Zend/Queue/Stomp/Client/Connection.php
  25. 103 0
      library/Zend/Queue/Stomp/Client/ConnectionInterface.php
  26. 361 0
      library/Zend/Queue/Stomp/Frame.php
  27. 154 0
      library/Zend/Queue/Stomp/FrameInterface.php
  28. 436 0
      library/Zend/Service/Amazon/Sqs.php
  29. 38 0
      library/Zend/Service/Amazon/Sqs/Exception.php
  30. 23 0
      tests/TestConfiguration.php.dist
  31. 2 0
      tests/Zend/AllTests.php
  32. 887 0
      tests/Zend/Queue/Adapter/AdapterTest.php
  33. 82 0
      tests/Zend/Queue/Adapter/ApachemqTest.php
  34. 120 0
      tests/Zend/Queue/Adapter/ArrayTest.php
  35. 143 0
      tests/Zend/Queue/Adapter/DbTest.php
  36. 41 0
      tests/Zend/Queue/Adapter/Iterator2.php
  37. 113 0
      tests/Zend/Queue/Adapter/MemcacheqTest.php
  38. 25 0
      tests/Zend/Queue/Adapter/MessageTestClass.php
  39. 98 0
      tests/Zend/Queue/Adapter/NullTest.php
  40. 194 0
      tests/Zend/Queue/Adapter/StompIOTest.php
  41. 102 0
      tests/Zend/Queue/Adapter/StompTest.php
  42. 5 0
      tests/Zend/Queue/Adapter/WARNING.txt
  43. 103 0
      tests/Zend/Queue/AllTests.php
  44. 128 0
      tests/Zend/Queue/Custom/DbForUpdate.php
  45. 121 0
      tests/Zend/Queue/Custom/Message.php
  46. 181 0
      tests/Zend/Queue/Custom/Messages.php
  47. 98 0
      tests/Zend/Queue/Custom/Queue.php
  48. 161 0
      tests/Zend/Queue/CustomTest.php
  49. 107 0
      tests/Zend/Queue/FactoryTest.php
  50. 168 0
      tests/Zend/Queue/Message/IteratorTest.php
  51. 206 0
      tests/Zend/Queue/MessageTest.php
  52. 62 0
      tests/Zend/Queue/Queue1Test.php
  53. 60 0
      tests/Zend/Queue/Queue2Test.php
  54. 274 0
      tests/Zend/Queue/QueueBaseTest.php
  55. 290 0
      tests/Zend/Queue/QueueTest.php
  56. 154 0
      tests/Zend/Queue/Stomp/ClientTest.php
  57. 149 0
      tests/Zend/Queue/Stomp/FrameTest.php
  58. 5 0
      tests/Zend/Service/Amazon/AllTests.php
  59. 93 0
      tests/Zend/Service/Amazon/Sqs/AllTests.php
  60. 45 0
      tests/Zend/Service/Amazon/Sqs/OfflineTest.php
  61. 141 0
      tests/Zend/Service/Amazon/Sqs/OnlineTest.php

+ 11 - 0
documentation/manual/en/manual.xml.in

@@ -383,6 +383,16 @@
         <xi:include href="module_specs/Zend_ProgressBar.xml" />
     </chapter>
 
+    <chapter id="zend.queue">
+        <title>Zend_Queue</title>
+        <xi:include href="module_specs/Zend_Queue-Introduction.xml" />
+        <xi:include href="module_specs/Zend_Queue-Example.xml" />
+        <xi:include href="module_specs/Zend_Queue-Framework.xml" />
+        <xi:include href="module_specs/Zend_Queue-Adapters.xml" />
+        <xi:include href="module_specs/Zend_Queue-Custom.xml" />
+        <xi:include href="module_specs/Zend_Queue-Stomp.xml" />
+    </chapter>
+
     <chapter id="zend.reflection">
         <title>Zend_Reflection</title>
         <xi:include href="module_specs/Zend_Reflection-Introduction.xml" />
@@ -439,6 +449,7 @@
         <xi:include href="module_specs/Zend_Service_Amazon_Ec2-RegionsAndAvalibilityZones.xml" />
         <xi:include href="module_specs/Zend_Service_Amazon_Ec2-Securitygroups.xml" />
         <xi:include href="module_specs/Zend_Service_Amazon_S3.xml" />
+        <xi:include href="module_specs/Zend_Service_Amazon_Sqs.xml" />
         <xi:include href="module_specs/Zend_Service_Audioscrobbler.xml" />
         <xi:include href="module_specs/Zend_Service_Delicious.xml" />
         <xi:include href="module_specs/Zend_Service_Flickr.xml" />

+ 426 - 0
documentation/manual/en/module_specs/Zend_Queue-Adapters.xml

@@ -0,0 +1,426 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Reviewed: no -->
+<sect1 id="zend.queue.adapters">
+    <title>Adapters</title>
+
+    <para>
+        <classname>Zend_Queue</classname> supports all queues implementing the
+        interface <classname>Zend_Queue_Adapter_AdapterInterface</classname>.
+        The following Message Queue services are supported:
+    </para>
+
+    <itemizedlist>
+        <listitem>
+            <para>
+                <ulink url="http://activemq.apache.org/">ApacheMQ</ulink>.
+            </para>
+        </listitem>
+
+        <listitem>
+            <para>
+                A database driven queue via <classname>Zend_Db</classname>.
+            </para>
+        </listitem>
+
+        <listitem>
+            <para>
+                A <ulink url="http://memcachedb.org/memcacheq/">MemcacheQ</ulink>
+                queue driven via <classname>Memcache</classname>.
+            </para>
+        </listitem>
+
+        <listitem>
+            <para>
+                A local array. Useful for unit testing.
+            </para>
+        </listitem>
+    </itemizedlist>
+
+    <note id="zend.queue.adapters.limitations">
+        <title>Limitations</title>
+
+        <para>
+            Message transaction handling is not supported.
+        </para>
+    </note>
+
+    <sect2 id="zend.queue.adapters.configuration">
+        <title>Specific Adapters - Configuration settings</title>
+
+        <para>
+            If a default setting is indicated then the parameter is optional.
+            If a default setting is not specified then the parameter is
+            required.
+        </para>
+
+        <sect3 id="zend.queue.adapters.configuration.Apachemq">
+            <title>ApacheMQ - <classname>Zend_Queue_Adapter_Apachemq</classname></title>
+
+            <para>
+                Options here listed here are known requirements.  Not all
+                messaging servers require username or password.
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                         <code>$options['name'] = '/temp/queue1';</code>
+                    </para>
+
+                    <para>
+                        This is the name of the queue that you wish to start
+                        using. (Required)
+                    </para>
+                </listitem>
+
+                <listitem>
+                    <para>
+                        <code>$options['driverOptions']['host'] = 'host.domain.tld';</code>
+                    </para>
+
+                    <para>
+                        <code>$options['driverOptions']['host'] = '127.0.0.1';</code>
+                    </para>
+
+                    <para>
+                        You may set host to an IP address or a hostname.
+                    </para>
+
+                    <para>
+                        Default setting for host is '127.0.0.1'.
+                    </para>
+                </listitem>
+
+                <listitem>
+                    <para>
+                        <code>$options['driverOptions']['port'] = 61613;</code>
+                    </para>
+
+                    <para>Default setting for port is 61613.</para>
+                </listitem>
+
+                <listitem>
+                    <para>
+                         <code>$options['driverOptions']['username'] = 'username';</code>
+                    </para>
+
+                    <para>
+                        Optional for some messaging servers.  Read the manual
+                        for your messaging server.
+                    </para>
+                </listitem>
+
+                <listitem>
+                    <para>
+                        <code>$options['driverOptions']['password'] = 'password';</code>
+                    </para>
+
+                    <para>
+                        Optional for some messaging servers.  Read the manual
+                        for your messaging server.
+                    </para>
+                </listitem>
+
+                <listitem>
+                    <para>
+                        <code>$options['driverOptions']['timeout_sec'] = 2;</code>
+                    </para>
+
+                    <para>
+                        <code>$options['driverOptions']['timeout_usec'] = 0;</code>
+                    </para>
+
+                    <para>
+                        This is the amount of time that Zend_Queue_Adapter_Activemq
+                        will wait for read activity on a socket before returning
+                        no messages.
+                    </para>
+                </listitem>
+            </itemizedlist>
+        </sect3>
+
+        <sect3 id="zend.queue.adapters.configuration.Db">
+            <title>Db - <code>Zend_Queue_Adapter_Db</code></title>
+
+            <para>
+                Driver options are checked for a few required options such
+                as <code>type</code>, <code>host</code>, <code>username</code>,
+                <code>password</code>, and <code>dbname</code>.  You may pass along
+                additional parameters for <methodname>Zend_DB::factory()</methodname> as parameters
+                in <code>$options['driverOptions']</code>.  An example of an additional
+                option not listed here, but could be passed would be <code>port</code>.
+            </para>
+
+            <programlisting role="php"><![CDATA[
+$options = array(
+    'driverOptions' => array(
+        'host'      => 'db1.domain.tld',
+        'username'  => 'my_username',
+        'password'  => 'my_password',
+        'dbname'    => 'messaging',
+        'type'      => 'pdo_mysql',
+        'port'      => 3306, // optional parameter.
+    ),
+    'options' => array(
+        // use Zend_Db_Select for update, not all databases can support this
+        // feature.
+        Zend_Db_Select::FOR_UPDATE => true
+    )
+);
+
+// Create a database queue.
+$queue = Zend_Queue::factory('Db', $options);
+]]></programlisting>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                         <code>$options['name'] = 'queue1';</code>
+                    </para>
+
+                    <para>
+                        This is the name of the queue that you wish to start using. (Required)
+                    </para>
+                </listitem>
+
+                <listitem>
+                    <para>
+                        <code>$options['driverOptions']['type'] = 'Pdo';</code>
+                    </para>
+
+                    <para>
+                        <code>type</code> is the adapter you wish to have
+                        <methodname>Zend_Db::factory</methodname> use. This is
+                        the first parameter for the
+                        <methodname>Zend::Db::factory()</methodname> class
+                        method call.
+                    </para>
+                </listitem>
+
+                <listitem>
+                    <para>
+                        <code>$options['driverOptions']['host'] = 'host.domain.tld';</code>
+                    </para>
+
+                    <para>
+                        <code>$options['driverOptions']['host'] = '127.0.0.1';</code>
+                    </para>
+
+                    <para>You may set host to an IP address or a hostname.</para>
+
+                    <para>Default setting for host is '127.0.0.1'.</para>
+                </listitem>
+
+                <listitem>
+                    <para>
+                         <code>$options['driverOptions']['username'] = 'username';</code>
+                    </para>
+                </listitem>
+
+                <listitem>
+                    <para>
+                        <code>$options['driverOptions']['password'] = 'password';</code>
+                    </para>
+                </listitem>
+
+                <listitem>
+                    <para>
+                        <code>$options['driverOptions']['dbname'] = 'dbname';</code>
+                    </para>
+
+                    <para>
+                        The database name that you have created the required tables for.
+                        See the notes section below.
+                    </para>
+                </listitem>
+            </itemizedlist>
+        </sect3>
+
+        <sect3 id="zend.queue.adapters.configuration.memcacheq">
+            <title>MemcacheQ - <classname>Zend_Queue_Adapter_Memcacheq</classname></title>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                         <code>$options['name'] = 'queue1';</code>
+                    </para>
+
+                    <para>
+                        This is the name of the queue that you wish to start using. (Required)
+                    </para>
+                </listitem>
+
+                <listitem>
+                    <para>
+                         <code>$options['driverOptions']['host'] = 'host.domain.tld';</code>
+                    </para>
+
+                    <para>
+                         <code>$options['driverOptions']['host'] = '127.0.0.1;'</code>
+                    </para>
+
+                    <para>You may set host to an IP address or a hostname.</para>
+
+                    <para>Default setting for host is '127.0.0.1'.</para>
+                </listitem>
+
+                <listitem>
+                    <para>
+                        <code>$options['driverOptions']['port'] = 22201;</code>
+                    </para>
+
+                    <para>The default setting for port is 22201.</para>
+                </listitem>
+            </itemizedlist>
+        </sect3>
+
+        <sect3 id="zend.queue.adapters.configuration.array">
+            <title>Array - <classname>Zend_Queue_Adapter_Array</classname></title>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                         <code>$options['name'] = 'queue1';</code>
+                    </para>
+
+                    <para>
+                        This is the name of the queue that you wish to start using. (Required)
+                    </para>
+                </listitem>
+            </itemizedlist>
+        </sect3>
+    </sect2>
+
+    <sect2 id="zend.queue.adapters.notes">
+        <title>Notes for Specific Adapters</title>
+
+        <para>The following adapters have notes:</para>
+
+        <sect3 id="zend.queue.adapters.notes.activemq">
+            <title>ActiveMQ</title>
+
+            <para>
+                Visibility duration for
+                <classname>Zend_Queue_Adapter_ActiveMQ</classname> is not
+                available.
+            </para>
+
+            <para>
+                While Apache's ActiveMQ will support multiple subscriptions, the
+                <classname>Zend_Queue</classname> does not.  You must create a
+                new <classname>Zend_Queue</classname> object for each individual
+                subcription.
+            </para>
+
+            <para>
+                ActiveMQ queue/topic names must begine with one of:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <code>/queue/</code>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <code>/topic/</code>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <code>/temp-queue/</code>
+                    </para>
+                </listitem>
+                <listitem>
+                    <para>
+                        <code>/temp-topic/</code>
+                    </para>
+                </listitem>
+            </itemizedlist>
+
+            <para>
+                For example: <code>/queue/testing</code>
+            </para>
+
+            <para>
+                The following functions are not supported:
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                         <code>create()</code> - create queue.
+                         Calling this function will throw an exception.
+                    </para>
+                </listitem>
+
+                <listitem>
+                    <para>
+                        <code>delete()</code> - delete queue.
+                        Calling this function will throw an exception.
+                    </para>
+                </listitem>
+
+                <listitem>
+                    <para>
+                        <code>getQueues()</code> - list queues.
+                        Calling this function will throw an exception.
+                    </para>
+                </listitem>
+            </itemizedlist>
+        </sect3>
+
+        <sect3 id="zend.queue.adapters.notes.zend_db">
+            <title>Zend_Db</title>
+
+            <para>
+                The database <code>CREATE TABLE ( ... )</code> SQL statement
+                can be found in <filename>Zend/Queue/Adapter/Db/queue.sql</filename>.
+            </para>
+        </sect3>
+
+        <sect3 id="zend.queue.adapters.notes.memcacheQ">
+            <title>MemcacheQ</title>
+
+            <para>
+                Memcache can be downloaded from
+                <ulink url="http://www.danga.com/memcached/">http://www.danga.com/memcached/</ulink>.
+            </para>
+
+            <para>
+                MemcacheQ can be downloaded from
+                A <ulink url="http://memcachedb.org/memcacheq/">http://memcachedb.org/memcacheq/</ulink>.
+            </para>
+
+            <itemizedlist>
+                <listitem>
+                    <para>
+                        <code>deleteMessage()</code> - Messages are deleted upon
+                        reception from the queue.  calling this function would
+                        have no effect. Calling this function will throw an
+                        error.
+                    </para>
+                </listitem>
+
+                <listitem>
+                    <para>
+                        <code>count() or count($adapter)</code> - MemcacheQ does
+                        not support a method for counting the number of items in
+                        a queue.  Calling this function will throw an error.
+                    </para>
+                </listitem>
+            </itemizedlist>
+        </sect3>
+
+        <sect3 id="zend.queue.adapters.notes.array">
+            <title>Array (local)</title>
+
+            <para>
+                The Array queue is a PHP <code>array()</code> in local memory.
+                The <classname>Zend_Queue_Adapter_Array</classname> is good for
+                unit testing.
+            </para>
+        </sect3>
+    </sect2>
+</sect1>

+ 135 - 0
documentation/manual/en/module_specs/Zend_Queue-Custom.xml

@@ -0,0 +1,135 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Reviewed: no -->
+<sect1 id="zend.queue.custom">
+    <title>Customizing Zend_Queue</title>
+
+    <sect2 id="zend.queue.custom.adapter">
+        <title>Creating your own adapter</title>
+
+        <para>
+            <classname>Zend_Queue</classname> will accept any adapter that
+            implements
+            <classname>Zend_Queue_Adapter_AdapterAbstract</classname>.  You can
+            create your own adapter by extending one of the existing adapters,
+            or the abstract class
+            <classname>Zend_Queue_Adapter_AdapterAbstract</classname>.  I
+            suggest reviewing <classname>Zend_Queue_Adapter_Array</classname> as
+            this adapter is the easist to conceptualize.
+        </para>
+
+        <programlisting role="php"><![CDATA[
+class Custom_DbForUpdate extends Zend_Queue_Adapter_Db
+{
+    /**
+     * @see code in tests/Zend/Queue/Custom/DbForUpdate.php
+     *
+     * Custom_DbForUpdate uses the SELECT ... FOR UPDATE to find it's rows.
+     * this is more likely to produce the wanted rows than the existing code.
+     *
+     * However, not all databases have SELECT ... FOR UPDATE as a feature.
+     *
+     * Note: this was later converted to be an option for Zend_Queue_Adapter_Db
+     *
+     * This code still serves as a good example.
+     */
+}
+
+$options = array(
+    'name'          => 'queue1',
+    'driverOptions' => array(
+        'host'      => '127.0.0.1',
+        'port'      => '3306',
+        'username'  => 'queue',
+        'password'  => 'queue',
+        'dbname'    => 'queue',
+        'type'      => 'pdo_mysql'
+    )
+);
+
+$adapter = new Custom_DbForUpdate($options);
+$queue = Zend_Queue($adapter, $options);
+]]></programlisting>
+
+        <para>
+            You can also change the adapter on the fly as well.
+        </para>
+
+        <programlisting role="php"><![CDATA[
+$adapter = new MyCustom_Adapter($options);
+$queue   = Zend_Queue($options);
+$queue->setAdapter($adapter);
+echo "Adapter: ", get_class($queue->getAdapter()), "\n";
+]]></programlisting>
+
+        <para>or</para>
+
+        <programlisting role="php"><![CDATA[
+$options = array(
+    'name'           => 'queue1',
+    'namespace'      => 'Custom',
+    'driverOptions'  => array(
+        'host'       => '127.0.0.1',
+        'port'       => '3306',
+        'username'   => 'queue',
+        'password'   => 'queue',
+        'dbname'     => 'queue',
+        'type'       => 'pdo_mysql'
+    )
+);
+$queue = Zend_Queue('DbForUpdate', $config); // loads Custom_DbForUpdate
+]]></programlisting>
+    </sect2>
+
+    <sect2 id="zend.queue.custom.message">
+        <title>Creating your own message class</title>
+
+        <para>
+            <classname>Zend_Queue</classname> will also accept your own message class.
+            Our variables start with an underscore. For example:
+        </para>
+
+        <programlisting role="php"><![CDATA[
+class Zend_Queue_Message
+{
+    protected $_data = array();
+}
+]]></programlisting>
+
+        <para>
+            You can extend the existing messaging class. See the example code in
+            <filename>tests/Zend/Queue/Custom/Message.php</filename>.
+        </para>
+    </sect2>
+
+    <sect2 id="zend.queue.custom-iterator">
+        <title>Creating your own message iterator class</title>
+
+        <para>
+            <classname>Zend_Queue</classname> will also accept your own message
+            iterator class.  The message iterator class is used to return
+            messages from
+            <methodname>Zend_Queue_Adapter_Abstract::recieve()</methodname>.
+            <methodname>Zend_Queue_Abstract::receive()</methodname> should aways
+            return a container class like
+            <classname>Zend_Queue_Message_Iterator</classname>, even if there is
+            only one message.
+        </para>
+
+        <para>
+            See the example filename in
+            <filename>tests/Zend/Queue/Custom/Messages.php</filename>.
+        </para>
+    </sect2>
+
+    <sect2 id="zend.queue.custom.queue">
+        <title>Creating your own queue class </title>
+
+        <para>
+            <classname>Zend_Queue</classname> can also be overloaded easily.
+        </para>
+
+        <para>
+            See the example filename in <filename>tests/Zend/Queue/Custom/Queue.php</filename>.
+        </para>
+    </sect2>
+</sect1>

+ 49 - 0
documentation/manual/en/module_specs/Zend_Queue-Example.xml

@@ -0,0 +1,49 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Reviewed: no -->
+<sect1 id="zend.queue.example">
+    <title>Example usage</title>
+
+    <para>
+        The below example of <code>Zend_Queue</code> shows a variety of
+        features, including queue creation, queue retrieval, message retrieval,
+        message deletion, and sending messages.
+    </para>
+
+    <programlisting role="php"><![CDATA[
+// For configuration options
+// @see Zend_Queue_Adapater::__construct()
+$options = array(
+    'name' => 'queue1',
+);
+
+// Create an array queue
+$queue = Zend_Queue('Array', $options);
+
+// Get list of queues
+foreach ($queue->getQueues() as $name) {
+    echo $name, "\n";
+}
+
+// Create a new queue
+$queue2 = $queue->create('queue2');
+
+// Get number of messages in a queue (supports Countable interface from SPL)
+echo count($queue);
+
+// Get up to 5 messages from a queue
+$messages = $queue->receive(5);
+
+foreach ($messages as $i => $message) {
+    echo $message->body, "\n";
+
+    // We have processed the message; now we remove it from the queue.
+    $queue->deleteMessage($message);
+}
+
+// Send a message to the currently active queue
+$queue->send('My Test Message');
+
+// Delete a queue we created and all of it's messages
+$queue->delete('queue2');
+]]></programlisting>
+</sect1>

+ 175 - 0
documentation/manual/en/module_specs/Zend_Queue-Framework.xml

@@ -0,0 +1,175 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Reviewed: no -->
+<sect1 id="zend.queue.framework">
+    <title>Framework</title>
+
+    <para>
+        The <classname>Zend_Queue</classname> is a proxy that hides the details
+        of the queue services. The queue services are represented by
+        <classname>Zend_Queue_Adapter_(service)</classname>.  For example,
+        <classname>Zend_Queue_Adapter_Db</classname> is a queue that will use
+        database tables to store and retrieve messages.
+    </para>
+
+    <para>
+        Below is an example for using database tables for a queuing system:
+    </para>
+
+    <programlisting role="php"><![CDATA[
+$options = array(
+    'name'          => 'queue1',
+    'driverOptions' => array(
+        'host'      => '127.0.0.1',
+        'port'      => '3306',
+        'username'  => 'queue',
+        'password'  => 'queue',
+        'dbname'    => 'queue',
+        'type'      => 'pdo_mysql'
+    )
+);
+
+// Create a database queue.
+// Zend_Queue will prepend Zend_Queue_Adapter_ to 'Db' for the class name.
+$queue = Zend_Queue('Db', $options);
+]]></programlisting>
+
+    <para>
+        The <classname>Zend_Queue</classname> constructor will create a
+        <classname>Zend_Queue_Adapter_Db</classname> and initialize the adapter
+        with the configuration settings.
+    </para>
+
+    <para>
+        The accepted configuration settings for each adapter are provided
+        in the <xref linkend="zend.queue.adapters">adapter notes</xref>.
+    </para>
+
+    <para>
+        <classname>Zend_Queue</classname> returns messages using the class
+        <classname>Zend_Queue_Message_Iterator</classname>, which is an
+        implementation of SPL <classname>Iterator</classname> and
+        <classname>Countable</classname>.
+        <classname>Zend_Queue_Message_Iterator</classname> contains an array of
+        <classname>Zend_Queue_Message</classname> objects.
+    </para>
+
+    <programlisting role="php"><![CDATA[
+$messages = $queue->receive(5);
+foreach ($messages as $i => $message) {
+    echo "$i) Message => ", $message->body, "\n";
+}
+]]></programlisting>
+
+    <para>
+        Any exceptions thrown are of class
+        <classname>Zend_Queue_Exception</classname>.
+    </para>
+
+    <sect2 id="zend.queue.framework.basics">
+        <title>Introduction</title>
+
+        <para>
+            <classname>Zend_Queue</classname> is a proxy class that represents
+            an adapter.
+        </para>
+
+        <para>
+            The <methodname>send()</methodname>,
+            <methodname>count($queue)</methodname>, and
+            <methodname>receive()</methodname> methods are employed by each
+            adapter to interact with queues.
+        </para>
+
+        <para>
+            The <methodname>createQueue()</methodname>,
+            <methodname>deleteQueue()</methodname> methods are used to manage
+            queues.
+        </para>
+    </sect2>
+
+    <sect2 id="zend.queue.framework.support">
+        <title>Commonality among adapters</title>
+
+        <para>
+            The queue services supported by <classname>Zend_Queue</classname> do
+            not all support the same functions.  For example,
+            <classname>Zend_Queue_Adapter_Array</classname>,
+            <classname>Zend_Queue_Adapter_Db</classname>, support all functions,
+            while <classname>Zend_Queue_Adapter_Activemq</classname> does not
+            support queue listing, queue deletion, or counting of messages.
+        </para>
+
+        <para>
+            You can determine what functions are supported by using
+            <methodname>Zend_Queue::isSupported()</methodname> or
+            <methodname>Zend_Queue::getCapabilities()</methodname>.
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <code>create</code> - create a queue
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <code>delete</code> - delete a queue
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <code>send</code> - send a message
+                </para>
+
+                <para>
+                    <code>send</code> is not available in all adapters; the
+                    <classname>Zend_Queue_Adapter_Null</classname> does not
+                    support <code>send</code>.
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <code>receive</code> - receive messages
+                </para>
+
+                <para>
+                    <code>receive</code> is not available in all adapters;
+                    the <classname>Zend_Queue_Adapter_Null</classname> does not
+                    support <code>receive</code>.
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <code>deleteMessage</code> - delete a message
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <code>count</code> - count the number of messages in a queue
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <code>isExists</code> - checks the existance of a queue
+                </para>
+            </listitem>
+        </itemizedlist>
+
+        <para>
+            <methodname>receive()</methodname> methods are employed by each
+            adapter to interact with queues.
+        </para>
+
+        <para>
+            The <methodname>createQueue()</methodname> and
+            <methodname>deleteQueue()</methodname> methods are used to manage
+            queues.
+        </para>
+    </sect2>
+</sect1>

+ 55 - 0
documentation/manual/en/module_specs/Zend_Queue-Introduction.xml

@@ -0,0 +1,55 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Reviewed: no -->
+<sect1 id="zend.queue.introduction">
+    <title>Introduction</title>
+
+    <para>
+        <classname>Zend_Queue</classname> provides a factory function to create
+        specific queue client objects.
+    </para>
+
+    <para>
+        A message queue is a method for distributed processing.  For example, a
+        Job Broker application may accept multiple applications for jobs from
+        a varity of sources.
+    </para>
+
+    <para>
+        You could create a queue "/queue/applications" that would have a sender
+        and a receiver. The sender would be any available source that could
+        connect to your message service or indirectly to an application (web)
+        that could connect to the message service.
+    </para>
+
+    <para>
+        The sender sends a message to the queue:
+    </para>
+
+    <programlisting role="xml"><![CDATA[
+<resume>
+    <name>John Smith</name>
+    <location>
+        <city>San Francisco</city>
+        <state>California</state>
+        <zip>00001</zip>
+    </location>
+    <skills>
+        <programming>PHP</programming>
+        <programming>Perl</programming>
+    </skills>
+</resume>
+]]></programlisting>
+
+    <para>
+        The recipient or consumer of the queue would pick up the message and
+        process the resume.
+    </para>
+
+    <para>
+        There many messaging patterns that can be applied to queues to abstract
+        the flow of control from the code and provide metrics, transformations,
+        and monitoring of messages queues. A good book on messaging patterns is
+        <ulink url="http://www.amazon.com/Enterprise-Integration-Patterns-Designing-Addison-Wesley/dp/0321200683">Enterprise Integration Patterns: Designing, Building, and Deploying Messaging Solutions (Addison-Wesley Signature Series)</ulink>
+        (ISBN-10 0321127420; ISBN-13 978-0321127426).
+    </para>
+</sect1>

+ 48 - 0
documentation/manual/en/module_specs/Zend_Queue-Stomp.xml

@@ -0,0 +1,48 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Reviewed: no -->
+<sect1 id="zend.queue.stomp">
+    <title>Stomp</title>
+
+    <para>
+        <classname>Zend_Queue_Stomp</classname> provides a basic client to
+        communicate with <ulink url="http://stomp.codehaus.org/">Stomp</ulink>
+        compatible servers.  Some servers, such as ApacheMQ and RabbitMQ, will
+        allow you to communicate by other methods, such as HTTP, and XMPP.
+    </para>
+
+    <para>
+        The Stomp protocol provides <ulink
+            url="http://stomp.codehaus.org/StompConnect">StompConnect</ulink>
+        which supports any <ulink url="http://java.sun.com/products/jms/"> Java
+            Message Service (JMS)</ulink> provider.
+        Stomp is supported by
+        <ulink url="http://activemq.apache.org/">Apache ActiveMQ</ulink>,
+        <ulink url="http://www.rabbitmq.com/">RabbitMQ</ulink>,
+        <ulink url="http://stompserver.rubyforge.org/">stompserver</ulink>, and
+        <ulink url="http://www.germane-software.com/software/Java/Gozirra/">Gozirra</ulink>.
+    </para>
+
+    <sect2 id="zend.queue.adapters-configuration.stomp">
+        <title>Stomp - Supporting classes</title>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <classname>Zend_Queue_Stomp_Frame</classname>. This class
+                    provides the basic functions for manipulating a Stomp Frame.
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <classname>Zend_Queue_Stomp_Client</classname>. This class
+                    provides the basic functions to
+                    <methodname>send()</methodname> and
+                    <methodname>receive()</methodname>
+                    <classname>Zend_Queue_Stomp_Frame</classname>s to and from a
+                    Stomp compatible server.
+                </para>
+            </listitem>
+        </itemizedlist>
+    </sect2>
+</sect1>

+ 308 - 0
documentation/manual/en/module_specs/Zend_Service_Amazon_Sqs.xml

@@ -0,0 +1,308 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- Reviewed: no -->
+<sect1 id="zend.service.amazon.sqs">
+    <title>Zend_Service_Amazon_Sqs</title>
+
+    <sect2 id="zend.service.amazon.sqs.introduction">
+        <title>Introduction</title>
+
+        <para>
+            <ulink url="http://aws.amazon.com/sqs/">Amazon Simple Queue Service
+                (Amazon SQS)</ulink> offers a reliable, highly scalable, hosted
+            queue for storing messages as they travel between computers. By
+            using Amazon SQS, developers can simply move data between
+            distributed components of their applications that perform different
+            tasks, without losing messages or requiring each component to be
+            always available. Amazon SQS makes it easy to build an automated
+            workflow, working in close conjunction with the Amazon Elastic
+            Compute Cloud (Amazon EC2) and the other AWS infrastructure web
+            services.
+        </para>
+
+        <para>
+            Amazon SQS works by exposing Amazon’s web-scale messaging
+            infrastructure as a web service. Any computer on the Internet can
+            add or read messages without any installed software or special
+            firewall configurations. Components of applications using Amazon SQS
+            can run independently, and do not need to be on the same network,
+            developed with the same technologies, or running at the same time.
+        </para>
+    </sect2>
+
+    <sect2 id="zend.service.amazon.sqs.registering">
+        <title>Registering with Amazon SQS</title>
+
+        <para>
+            Before you can get started with
+            <classname>Zend_Service_Amazon_Sqs</classname>, you must first
+            register for an account. Please see the <ulink
+                url="http://aws.amazon.com/sqs/faqs/">SQS FAQ</ulink> page on
+            the Amazon website for more information.
+        </para>
+
+        <para>
+            After registering, you will receive an application key and a secret key.
+            You will need both to access the SQS service.
+        </para>
+    </sect2>
+
+    <sect2 id="zend.service.amazon.sqs.apiDocumentation">
+        <title>API Documentation</title>
+
+        <para>
+            The <classname>Zend_Service_Amazon_Sqs</classname> class provides
+            the PHP wrapper to the Amazon SQS REST interface. Please consult the
+            <ulink
+                url="http://developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=31">Amazon
+                SQS documentation</ulink> for detailed description of the
+            service. You will need to be familiar with basic concepts in order
+            to use this service.
+        </para>
+
+    </sect2>
+
+    <sect2 id="zend.service.amazon.sqs.features">
+        <title>Features</title>
+
+        <para>
+            <classname>Zend_Service_Amazon_Sqs</classname> provides the
+            following functionality:
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    A single point for configuring your amazon.sqs
+                    authentication credentials that can be used across the
+                    amazon.sqs namespaces.
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    A proxy object that is more convenient to use than an HTTP
+                    client alone, mostly removing the need to manually construct
+                    HTTP POST requests to access the REST service.
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    A response wrapper that parses each response body and throws
+                    an exception if an error occurred, alleviating the need to
+                    repeatedly check the success of many commands.
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    Additional convenience methods for some of the more common
+                    operations.
+                </para>
+            </listitem>
+        </itemizedlist>
+    </sect2>
+
+    <sect2 id="zend.service.amazon.sqs.storing-your-first">
+        <title>Getting Started</title>
+
+        <para>
+            Once you have registered with Amazon SQS, you're ready to create
+            your queue and store some messages on SQS. Each queue can contain
+            unlimited amount of messages, identified by name.
+        </para>
+
+        <para>
+            The following example demonstrates creating a queue, storing and
+            retrieving messages.
+        </para>
+
+        <example id="zend.service.amazon.sqs.storing-your-first.example">
+            <title>Zend_Service_Amazon_Sqs Usage Example</title>
+
+            <programlisting language="php"><![CDATA[
+$sqs = new Zend_Service_Amazon_Sqs($my_aws_key, $my_aws_secret_key);
+
+$queue_url = $sqs->create('test');
+
+$message = 'this is a test';
+$message_id = $sqs->send($queue_url, $message);
+
+foreach ($sqs->receive($queue_url) as $message) {
+    echo $message['body'].'<br/>';
+}
+]]></programlisting>
+        </example>
+
+        <para>
+            Since the <classname>Zend_Service_Amazon_Sqs</classname> service
+            requires authentication, you should pass your credentials (AWS key
+            and secret key) to the constructor.  If you only use one account,
+            you can set default credentials for the service:
+        </para>
+
+        <programlisting language="php"><![CDATA[
+Zend_Service_Amazon_Sqs::setKeys($my_aws_key, $my_aws_secret_key);
+$sqs = new Zend_Service_Amazon_Sqs();
+]]></programlisting>
+    </sect2>
+
+    <sect2 id="zend.service.amazon.sqs.queues">
+        <title>Queue operations</title>
+
+        <para>
+            All messages SQS are stored in queues. A queue has to be created
+            before any message operations. Queue names must be unique under your
+            access key and secret key.
+        </para>
+
+        <para>
+            Queue names can contain lowercase letters, digits, periods (.),
+            underscores (_), and dashes (-).  No other symbols allowed. Queue
+            names can be a maximum of 80 characters.
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <methodname>create()</methodname> creates a new queue.
+                </para>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <methodname>delete()</methodname> removes all messages in
+                    the queue.
+                </para>
+
+                <example id="zend.service.amazon.sqs.queues.removalExample">
+                    <title>Zend_Service_Amazon_Sqs Queue Removal Example</title>
+
+                    <programlisting language="php"><![CDATA[
+$sqs = new Zend_Service_Amazon_Sqs($my_aws_key, $my_aws_secret_key);
+$queue_url = $sqs->create('test_1');
+$sqs->delete($queue_url);
+]]></programlisting>
+                </example>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <methodname>count()</methodname> gets the approximate number
+                    of messages in the queue.
+                </para>
+
+                <example id="zend.service.amazon.sqs.queues.countExample">
+                    <title>Zend_Service_Amazon_Sqs Queue Count Example</title>
+
+                    <programlisting language="php"><![CDATA[
+$sqs = new Zend_Service_Amazon_Sqs($my_aws_key, $my_aws_secret_key);
+$queue_url = $sqs->create('test_1');
+$sqs->send($queue_url, 'this is a test');
+$count = $sqs->count($queue_url); // Returns '1'
+]]></programlisting>
+                </example>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <methodname>getQueues()</methodname> returns the list of the
+                    names of all queues belonging to the user.
+                </para>
+
+                <example id="zend.service.amazon.sqs.queues.listExample">
+                    <title>Zend_Service_Amazon_Sqs Queue Listing Example</title>
+
+                    <programlisting language="php"><![CDATA[
+$sqs = new Zend_Service_Amazon_Sqs($my_aws_key, $my_aws_secret_key);
+$list = $sqs->getQueues();
+foreach($list as $queue) {
+   echo "I have queue $queue\n";
+}
+]]></programlisting>
+                </example>
+            </listitem>
+        </itemizedlist>
+    </sect2>
+
+    <sect2 id="zend.service.amazon.sqs.messages">
+        <title>Message operations</title>
+
+        <para>
+            After a queue is created, simple messages can be sent into the queue
+            then received at a later point in time. Messages can be up to 8KB in
+            length.  If longer messages are needed please see <ulink
+                url="http://framework.zend.com/manual/en/zend.service.amazon.s3.html">S3</ulink>.
+            There is no limit to the number of messages a queue can contain.
+        </para>
+
+        <itemizedlist>
+            <listitem>
+                <para>
+                    <methodname>sent($queue_url, $message)</methodname> send the
+                    <code>$message</code> to the <code>$queue_url</code> SQS
+                    queue URL.
+                </para>
+
+                <example id="zend.service.amazon.sqs.messages.sendExample">
+                    <title>Zend_Service_Amazon_Sqs Message Send Example</title>
+
+                    <programlisting language="php"><![CDATA[
+$sqs = new Zend_Service_Amazon_Sqs($my_aws_key, $my_aws_secret_key);
+$queue_url = $sqs->create('test_queue');
+$sqs->send($queue_url, 'this is a test message');
+]]></programlisting>
+                </example>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <methodname>receive($queue_url)</methodname> retrieves
+                    messages from the queue.
+                </para>
+
+                <example id="zend.service.amazon.sqs.messages.receiveExample">
+                    <title>Zend_Service_Amazon_Sqs Message Receive Example</title>
+
+                    <programlisting language="php"><![CDATA[
+$sqs = new Zend_Service_Amazon_Sqs($my_aws_key, $my_aws_secret_key);
+$queue_url = $sqs->create('test_queue');
+$sqs->send($queue_url, 'this is a test message');
+foreach ($sqs->receive($queue_url) as $message) {
+    echo "got message ".$message['body'].'<br/>';
+}
+]]></programlisting>
+                </example>
+            </listitem>
+
+            <listitem>
+                <para>
+                    <methodname>deleteMessage($queue_url, $handle)</methodname>
+                    deletes a message from a queue.  A message must first be
+                    received using the <methodname>receive()</methodname> method
+                    before it can be deleted.
+                </para>
+
+                <example id="zend.service.amazon.sqs.messages.deleteExample">
+                    <title>Zend_Service_Amazon_Sqs Message Delete Example</title>
+
+                    <programlisting language="php"><![CDATA[
+$sqs = new Zend_Service_Amazon_Sqs($my_aws_key, $my_aws_secret_key);
+$queue_url = $sqs->create('test_queue');
+$sqs->send($queue_url, 'this is a test message');
+foreach ($sqs->receive($queue_url) as $message) {
+    echo "got message ".$message['body'].'<br/>';
+
+    if ($sqs->deleteMessage($queue_url, $message['handle'])) {
+        echo "Message deleted";
+    }
+    else {
+        echo "Message not deleted";
+    }
+}
+]]></programlisting>
+                </example>
+            </listitem>
+       </itemizedlist>
+    </sect2>
+</sect1>

+ 571 - 0
library/Zend/Queue.php

@@ -0,0 +1,571 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * Class for connecting to queues performing common operations.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Queue implements Countable
+{
+    /**
+     * Use the TIMEOUT constant in the config of a Zend_Queue
+     */
+    const TIMEOUT = 'timeout';
+
+    /**
+     * Default visibility passed to count
+     */
+    const VISIBILITY_TIMEOUT = 30;
+
+    /**
+     * Use the NAME constant in the config of Zend_Queue
+     */
+    const NAME = 'name';
+
+    /**
+     * @var Zend_Queue_Adapter_AdapterInterface
+     */
+    protected $_adapter = null;
+
+    /**
+     * User-provided configuration
+     *
+     * @var array
+     */
+    protected $_options = array();
+
+    /**
+     * Zend_Queue_Message class
+     *
+     * @var string
+     */
+    protected $_messageClass = 'Zend_Queue_Message';
+
+    /**
+     * Zend_Queue_Message_Iterator class
+     *
+     * @var string
+     */
+    protected $_messageSetClass = 'Zend_Queue_Message_Iterator';
+
+    /**
+     * @var Zend_Log
+     */
+    protected $_logger = null;
+
+    /**
+     * Constructor
+     *
+     * Can be called as
+     * $queue = new Zend_Queue($config);
+     * - or -
+     * $queue = new Zend_Queue('array', $config);
+     * - or -
+     * $queue = new Zend_Queue(null, $config); // Zend_Queue->createQueue();
+     *
+     * @param  string|Zend_Queue_Adapter|array|Zend_Config|null String or adapter instance, or options array or Zend_Config instance
+     * @param  Zend_Config|array $options Zend_Config or a configuration array
+     * @return void
+     */
+    public function __construct($spec, $options = array())
+    {
+        $adapter = null;
+        if ($spec instanceof Zend_Queue_Adapter_AdapterInterface) {
+            $adapter = $spec;
+        } elseif (is_string($spec)) {
+            $adapter = $spec;
+        } elseif ($spec instanceof Zend_Config) {
+            $options = $spec->toArray();
+        } elseif (is_array($spec)) {
+            $options = $spec;
+        }
+
+        // last minute error checking
+        if ((null === $adapter)
+            && (!is_array($options) && (!$options instanceof Zend_Config))
+        ) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('No valid params passed to constructor');
+        }
+
+        // Now continue as we would if we were a normal constructor
+        if ($options instanceof Zend_Config) {
+            $options = $options->toArray();
+        } elseif (!is_array($options)) {
+            $options = array();
+        }
+
+        // Make sure we have some defaults to work with
+        if (!isset($options[self::TIMEOUT])) {
+            $options[self::TIMEOUT] = self::VISIBILITY_TIMEOUT;
+        }
+
+        // Make sure all defaults are appropriately set.
+        if (!array_key_exists('timeout', $options)) {
+            $options[self::TIMEOUT] = self::VISIBILITY_TIMEOUT;
+        }
+        if (array_key_exists('messageClass', $options)) {
+            $this->setMessageClass($options['messageClass']);
+        }
+        if (array_key_exists('messageSetClass', $options)) {
+            $this->setMessageSetClass($options['messageSetClass']);
+        }
+
+        $this->setOptions($options);
+
+        // if we were passed an adapter we either build the $adapter or use it
+        if (null !== $adapter) {
+            $this->setAdapter($adapter);
+        }
+    }
+
+    /**
+     * Set queue options 
+     * 
+     * @param  array $options 
+     * @return Zend_Queue
+     */
+    public function setOptions(array $options)
+    {
+        $this->_options = array_merge($this->_options, $options);
+        return $this;
+    }
+
+    /**
+     * Set an individual configuration option
+     * 
+     * @param  string $name 
+     * @param  mixed $value 
+     * @return Zend_Queue
+     */
+    public function setOption($name, $value)
+    {
+        $this->_options[(string) $name] = $value;
+        return $this;
+    }
+
+    /**
+     * Returns the configuration options for the queue
+     *
+     * @return array
+     */
+    public function getOptions()
+    {
+        return $this->_options;
+    }
+
+    /**
+     * Determine if a requested option has been defined
+     * 
+     * @param  string $name 
+     * @return bool
+     */
+    public function hasOption($name)
+    {
+        return array_key_exists($name, $this->_options);
+    }
+
+    /**
+     * Retrieve a single option
+     * 
+     * @param  string $name 
+     * @return null|mixed Returns null if option does not exist; option value otherwise
+     */
+    public function getOption($name)
+    {
+        if ($this->hasOption($name)) {
+            return $this->_options[$name];
+        }
+        return null;
+    }
+
+    /**
+     * Set the adapter for this queue
+     *
+     * @param  string|Zend_Queue_Adapter_AdapterInterface $adapter
+     * @return Zend_Queue Provides a fluent interface
+     */
+    public function setAdapter($adapter)
+    {
+        if (is_string($adapter)) {
+            if (null === ($adapterNamespace = $this->getOption('adapterNamespace'))) {
+                $adapterNamespace = 'Zend_Queue_Adapter';
+            }
+
+            $adapterName = str_replace(
+                ' ', 
+                '_',
+                ucwords(
+                    str_replace(
+                        '_', 
+                        ' ',
+                        strtolower($adapterNamespace . '_' . $adapter)
+                    )
+                )
+            );
+
+            if (!class_exists($adapterName)) {
+                require_once 'Zend/Loader.php';
+                Zend_Loader::loadClass($adapterName);
+            }
+
+            /*
+             * Create an instance of the adapter class.
+             * Pass the configuration to the adapter class constructor.
+             */
+            $adapter = new $adapterName($this->getOptions(), $this);
+        } 
+        
+        if (!$adapter instanceof Zend_Queue_Adapter_AdapterInterface) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception("Adapter class '" . get_class($adapterName) . "' does not implement Zend_Queue_Adapter_AdapterInterface");
+        }
+
+        $this->_adapter = $adapter;
+
+        $this->_adapter->setQueue($this);
+        $this->_setName($this->getOption(self::NAME));
+
+        return $this;
+    }
+
+    /**
+     * Get the adapter for this queue
+     *
+     * @return Zend_Queue_Adapter_AdapterInterface
+     */
+    public function getAdapter()
+    {
+        return $this->_adapter;
+    }
+
+    /**
+     * @param  string $className
+     * @return Zend_Queue Provides a fluent interface
+     */
+    public function setMessageClass($className)
+    {
+        $this->_messageClass = (string) $className;
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getMessageClass()
+    {
+        return $this->_messageClass;
+    }
+
+    /**
+     * @param  string $className
+     * @return Zend_Queue Provides a fluent interface
+     */
+    public function setMessageSetClass($className)
+    {
+        $this->_messageSetClass = (string) $className;
+        return $this;
+    }
+
+    /**
+     * @return string
+     */
+    public function getMessageSetClass()
+    {
+        return $this->_messageSetClass;
+    }
+
+    /**
+     * Get the name of the queue
+     *
+     * Note: _setName() used to exist, but it caused confusion with createQueue
+     * Will evaluate later to see if we should add it back in.
+     *
+     * @return string
+     */
+    public function getName()
+    {
+        return $this->getOption(self::NAME);
+    }
+
+    /**
+     * Create a new queue
+     *
+     * @param  string           $name    queue name
+     * @param  integer          $timeout default visibility timeout
+     * @return Zend_Queue|false
+     * @throws Zend_Queue_Exception
+     */
+    public function createQueue($name, $timeout = null)
+    {
+        if (!is_string($name)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$name is not a string');
+        }
+
+        if ((null !== $timeout) && !is_integer($timeout)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$timeout must be an integer');
+        }
+
+        // Default to standard timeout
+        if (null === $timeout) {
+            $timeout = $this->getOption(self::TIMEOUT);
+        }
+
+        // Some queues allow you to create on the fly, but cannot return
+        // a list of queues.  Stomp protocol for example.
+        if ($this->isSupported('create')) {
+            if ($this->getAdapter()->isExists($name)) {
+                return false;
+            }
+
+            if (!$this->getAdapter()->create($name, $timeout)) {
+                return false;
+            }
+        }
+
+        $options = array(
+            self::NAME  => $name,
+            'timeout'   => $timeout
+        );
+
+        return new self($this->getAdapter(), $options);
+    }
+
+    /**
+     * Delete the queue this object is working on.
+     *
+     * This queue is disabled, regardless of the outcome of the deletion
+     * of the queue, because the programmers intent is to disable this queue.
+     *
+     * @return boolean
+     */
+    public function deleteQueue()
+    {
+        if ($this->isSupported('delete')) {
+            $deleted = $this->getAdapter()->delete($this->getName());
+        }
+        else {
+            $deleted = true;
+        }
+
+        /**
+         * @see Zend_Queue_Adapter_Null
+         */
+        require_once('Zend/Queue/Adapter/Null.php');
+        $this->setAdapter(new Zend_Queue_Adapter_Null($this->getOptions()));
+
+        return $deleted;
+    }
+
+    /**
+     * Delete a message from the queue
+     *
+     * Returns true if the message is deleted, false if the deletion is
+     * unsuccessful.
+     *
+     * Returns true if the adapter doesn't support message deletion.
+     *
+     * @param  Zend_Queue_Message $message
+     * @return boolean
+     * @throws Zend_Queue_Exception
+     */
+    public function deleteMessage(Zend_Queue_Message $message)
+    {
+        if ($this->getAdapter()->isSupported('deleteMessage')) {
+            return $this->getAdapter()->deleteMessage($message);
+        }
+        return true;
+    }
+
+    /**
+     * Send a message to the queue
+     *
+     * @param  string             $message message
+     * @return Zend_Queue_Message
+     * @throws Zend_Queue_Exception
+     */
+    public function send($message)
+    {
+        if (!is_string($message)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$message is not a string');
+        }
+
+        return $this->getAdapter()->send($message);
+    }
+
+    /**
+     * Returns the approximate number of messages in the queue
+     *
+     * @return integer
+     */
+    public function count()
+    {
+        if ($this->getAdapter()->isSupported('count')) {
+            return $this->getAdapter()->count();
+        }
+        return 0;
+    }
+
+    /**
+     * Return the first element in the queue
+     *
+     * @param  integer $maxMessages
+     * @param  integer $timeout
+     * @return Zend_Queue_Message_Iterator
+     */
+    public function receive($maxMessages=null, $timeout=null)
+    {
+        if (($maxMessages !== null) && !is_integer($maxMessages)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$maxMessages must be an integer or null');
+        }
+
+        if (($timeout !== null) && !is_integer($timeout)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$timeout must be an integer or null');
+        }
+
+        // Default to returning only one message
+        if ($maxMessages === null) {
+            $maxMessages = 1;
+        }
+
+        // Default to standard timeout
+        if ($timeout === null) {
+            $timeout = $this->getOption(self::TIMEOUT);
+        }
+
+        return $this->getAdapter()->receive($maxMessages, $timeout);
+    }
+
+    /**
+     * Return a list of queue capabilities functions
+     *
+     * $array['function name'] = true or false
+     * true is supported, false is not supported.
+     *
+     * @param  string $name
+     * @return array
+     */
+    public function getCapabilities()
+    {
+        return $this->getAdapter()->getCapabilities();
+    }
+
+    /**
+     * Indicates if a function is supported or not.
+     *
+     * @param  string $name
+     * @return boolean
+     */
+    public function isSupported($name)
+    {
+        $translation = array(
+            'deleteQueue' => 'delete',
+            'createQueue' => 'create'
+        );
+
+        if (isset($translation[$name])) {
+            $name = $translation[$name];
+        }
+
+        return $this->getAdapter()->isSupported($name);
+    }
+
+    /**
+     * Get an array of all available queues
+     *
+     * @return array
+     * @throws Zend_Queue_Exception
+     */
+    public function getQueues()
+    {
+        if (!$this->isSupported('getQueues')) {
+            throw new Zend_Queue_Exception( __FUNCTION__ . '() is not supported by ' . get_class($this->getAdapter()));
+        }
+
+        return $this->getAdapter()->getQueues();
+    }
+
+    /**
+     * Set the name of the queue
+     *
+     * This is AN UNSUPPORTED FUNCTION
+     *
+     * @param  string           $name
+     * @return Zend_Queue|false Provides a fluent interface
+     */
+    protected function _setName($name)
+    {
+        if (!is_string($name)) {
+            /**
+             * @see Zend_Queue_Exception
+             */
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$name is not a string');
+        }
+
+        if ($this->getAdapter()->isSupported('create')) {
+            if (!$this->getAdapter()->isExists($name)) {
+                $timeout = $this->getOption(self::TIMEOUT);
+
+                if (!$this->getAdapter()->create($name, $timeout)) {
+                    // Unable to create the new queue
+                    return false;
+                }
+            }
+        }
+
+        $this->setOption(self::NAME, $name);
+
+        return $this;
+    }
+
+    /**
+     * returns a listing of Zend_Queue details.
+     * useful for debugging
+     *
+     * @return array
+     */
+    public function debugInfo()
+    {
+        $info = array();
+        $info['self']                     = get_class($this);
+        $info['adapter']                  = get_class($this->getAdapter());
+        foreach ($this->getAdapter()->getCapabilities() as $feature => $supported) {
+            $info['adapter-' . $feature]  = ($supported) ? 'yes' : 'no';
+        }
+        $info['options']                  = $this->getOptions();
+        $info['options']['driverOptions'] = '[hidden]';
+        $info['currentQueue']             = $this->getName();
+        $info['messageClass']             = $this->getMessageClass();
+        $info['messageSetClass']          = $this->getMessageSetClass();
+
+        return $info;
+    }
+}

+ 191 - 0
library/Zend/Queue/Adapter/AdapterAbstract.php

@@ -0,0 +1,191 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Queue
+ */
+require_once 'Zend/Queue.php';
+
+/**
+ * @see Zend_Queue_Adapter_AdapterInterface
+ */
+require_once 'Zend/Queue/Adapter/AdapterInterface.php';
+
+/**
+ * Class for connecting to queues performing common operations.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+abstract class Zend_Queue_Adapter_AdapterAbstract
+    implements Zend_Queue_Adapter_AdapterInterface
+{
+    /**
+     * Default timeout for createQueue() function
+     */
+    const CREATE_TIMEOUT_DEFAULT = 30;
+
+    /**
+     * Default timeout for recieve() function
+     */
+    const RECEIVE_TIMEOUT_DEFAULT = 30;
+
+    /**
+     * User-provided options
+     *
+     * @var array
+     */
+    protected $_options = array();
+
+    /**
+     * Internal array of queues to save on lookups
+     *
+     * @var array
+     */
+    protected $_queues = array();
+
+    /**
+     * Contains the Zend_Queue that this object
+     *
+     * @var Zend_Queue_Adapter_Abstract
+     */
+    protected $_queue = null;
+
+    /**
+     * Constructor.
+     *
+     * $options is an array of key/value pairs or an instance of Zend_Config
+     * containing configuration options.  These options are common to most adapters:
+     *
+     * See the Zend_Queue Adapter Notes documentation for example configurations.
+     *
+     * Some options are used on a case-by-case basis by adapters:
+     *
+     * access_key     => (string) Amazon AWS Access Key
+     * secret_key     => (string) Amazon AWS Secret Key
+     * dbname         => (string) The name of the database to user
+     * username       => (string) Connect to the database as this username.
+     * password       => (string) Password associated with the username.
+     * host           => (string) What host to connect to, defaults to localhost
+     * port           => (string) The port of the database
+     *
+     * @param  array|Zend_Config $config An array having configuration data
+     * @param  Zend_Queue The Zend_Queue object that created this class
+     * @return void
+     * @throws Zend_Queue_Exception
+     */
+    public function __construct($options, Zend_Queue $queue = null)
+    {
+        if ($options instanceof Zend_Config) {
+            $options = $options->toArray();
+        }
+
+        /*
+         * Verify that adapter parameters are in an array.
+         */
+        if (!is_array($options)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('Adapter options must be an array or Zend_Config object');
+        }
+
+        // set the queue
+        if ($queue !== null) {
+            $this->setQueue($queue);
+        }
+
+        $adapterOptions = array();
+        $driverOptions  = array();
+
+        // Normalize the options and merge with the defaults
+        if (array_key_exists('options', $options)) {
+            if (!is_array($options['options'])) {
+                require_once 'Zend/Queue/Exception.php';
+                throw new Zend_Queue_Exception("Configuration array 'options' must be an array");
+            }
+
+            // Can't use array_merge() because keys might be integers
+            foreach ($options['options'] as $key => $value) {
+                $adapterOptions[$key] = $value;
+            }
+        }
+        if (array_key_exists('driverOptions', $options)) {
+            // can't use array_merge() because keys might be integers
+            foreach ((array)$options['driverOptions'] as $key => $value) {
+                $driverOptions[$key] = $value;
+            }
+        }
+        $this->_options = array_merge($this->_options, $options);
+        $this->_options['options']       = $adapterOptions;
+        $this->_options['driverOptions'] = $driverOptions;
+    }
+
+    /********************************************************************
+    * Queue management functions
+     *********************************************************************/
+    /**
+     * get the Zend_Queue class that is attached to this object
+     *
+     * @return Zend_Queue|null
+     */
+    public function getQueue()
+    {
+        return $this->_queue;
+    }
+
+    /**
+     * set the Zend_Queue class for this object
+     *
+     * @param  Zend_Queue $queue
+     * @return Zend_Queue_Adapter_AdapterInterface
+     */
+    public function setQueue(Zend_Queue $queue)
+    {
+        $this->_queue = $queue;
+        return $this;
+    }
+
+    /**
+     * Returns the configuration options in this adapter.
+     *
+     * @return array
+     */
+    public function getOptions()
+    {
+        return $this->_options;
+    }
+
+    /**
+     * Indicates if a function is supported or not.
+     *
+     * @param  string $name
+     * @return boolean
+     */
+    public function isSupported($name)
+    {
+        $list = $this->getCapabilities();
+
+        return (isset($list[$name]) && $list[$name]);
+     }
+}

+ 174 - 0
library/Zend/Queue/Adapter/AdapterInterface.php

@@ -0,0 +1,174 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * Interface for common queue operations
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+interface Zend_Queue_Adapter_AdapterInterface
+{
+    /**
+     * Constructor
+     * 
+     * @param  array|Zend_Config $options 
+     * @param  Zend_Queue $queue 
+     * @return void
+     */
+    public function __construct($options, Zend_Queue $queue = null);
+
+    /**
+     * Retrieve queue instance
+     * 
+     * @return Zend_Queue
+     */
+    public function getQueue();
+
+    /**
+     * Set queue instnace
+     * 
+     * @param  Zend_Queue $queue 
+     * @return Zend_Queue_Adapter_AdapterInterface
+     */
+    public function setQueue(Zend_Queue $queue);
+
+    /**
+     * Does a queue already exist?
+     *
+     * Use isSupported('isExists') to determine if an adapter can test for
+     * queue existance.
+     *
+     * @param  string $name Queue name
+     * @return boolean
+     */
+    public function isExists($name);
+
+    /**
+     * Create a new queue
+     *
+     * Visibility timeout is how long a message is left in the queue 
+     * "invisible" to other readers.  If the message is acknowleged (deleted) 
+     * before the timeout, then the message is deleted.  However, if the 
+     * timeout expires then the message will be made available to other queue 
+     * readers.
+     *
+     * @param  string  $name Queue name
+     * @param  integer $timeout Default visibility timeout
+     * @return boolean
+     */
+    public function create($name, $timeout=null);
+
+    /**
+     * Delete a queue and all of its messages
+     *
+     * Return false if the queue is not found, true if the queue exists.
+     *
+     * @param  string $name Queue name
+     * @return boolean
+     */
+    public function delete($name);
+
+    /**
+     * Get an array of all available queues
+     *
+     * Not all adapters support getQueues(); use isSupported('getQueues')
+     * to determine if the adapter supports this feature.
+     *
+     * @return array
+     */
+    public function getQueues();
+
+    /**
+     * Return the approximate number of messages in the queue
+     *
+     * @param  Zend_Queue|null $queue
+     * @return integer
+     */
+    public function count(Zend_Queue $queue = null);
+
+    /********************************************************************
+     * Messsage management functions
+     *********************************************************************/
+
+    /**
+     * Send a message to the queue
+     *
+     * @param  string $message Message to send to the active queue
+     * @param  Zend_Queue|null $queue
+     * @return Zend_Queue_Message
+     */
+    public function send($message, Zend_Queue $queue = null);
+
+    /**
+     * Get messages in the queue
+     *
+     * @param  integer|null $maxMessages Maximum number of messages to return
+     * @param  integer|null $timeout Visibility timeout for these messages
+     * @param  Zend_Queue|null $queue
+     * @return Zend_Queue_Message_Iterator
+     */
+    public function receive($maxMessages = null, $timeout = null, Zend_Queue $queue = null);
+
+    /**
+     * Delete a message from the queue
+     *
+     * Return true if the message is deleted, false if the deletion is
+     * unsuccessful.
+     *
+     * @param  Zend_Queue_Message $message
+     * @return boolean
+     */
+    public function deleteMessage(Zend_Queue_Message $message);
+
+    /********************************************************************
+     * Supporting functions
+     *********************************************************************/
+
+    /**
+     * Returns the configuration options in this adapter.
+     *
+     * @return array
+     */
+    public function getOptions();
+
+    /**
+     * Return a list of queue capabilities functions
+     *
+     * $array['function name'] = true or false
+     * true is supported, false is not supported.
+     *
+     * @return array
+     */
+    public function getCapabilities();
+
+    /**
+     * Indicates if a function is supported or not.
+     *
+     * @param  string $name Function name
+     * @return boolean
+     */
+    public function isSupported($name);
+}

+ 333 - 0
library/Zend/Queue/Adapter/Apachemq.php

@@ -0,0 +1,333 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Stomp.php 15165 2009-04-26 14:44:50Z danlo $
+ */
+
+/**
+ * @see Zend_Queue_Adapter_AdapterAbstract
+ */
+require_once 'Zend/Queue/Adapter/AdapterAbstract.php';
+
+/**
+ * @see Zend_Queue_Adapter_Stomp_Client
+ */
+require_once 'Zend/Queue/Stomp/Client.php';
+
+/**
+ * @see Zend_Queue_Adapter_Stomp_Frame
+ */
+require_once 'Zend/Queue/Stomp/Frame.php';
+
+/**
+ * Class for using Stomp to talk to an Stomp compliant server
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Queue_Adapter_Apachemq extends Zend_Queue_Adapter_AdapterAbstract
+{
+    const DEFAULT_SCHEME = 'tcp';
+    const DEFAULT_HOST   = '127.0.0.1';
+    const DEFAULT_PORT   = 61613;
+
+    /**
+     * @var Zend_Queue_Adapter_Stomp_client
+     */
+    private $_client = null;
+
+    /**
+     * Constructor
+     *
+     * @param  array|Zend_Config $config An array having configuration data
+     * @param  Zend_Queue The Zend_Queue object that created this class
+     * @return void
+     */
+    public function __construct($options, Zend_Queue $queue = null)
+    {
+        parent::__construct($options);
+
+        $options = &$this->_options['driverOptions'];
+        if (!array_key_exists('scheme', $options)) {
+            $options['scheme'] = self::DEFAULT_SCHEME;
+        }
+        if (!array_key_exists('host', $options)) {
+            $options['host'] = self::DEFAULT_HOST;
+        }
+        if (!array_key_exists('port', $options)) {
+            $options['port'] = self::DEFAULT_PORT;
+        }
+
+        if (array_key_exists('stompClient', $options)) {
+            $this->_client = $options['stompClient'];
+        } else {
+            $this->_client = new Zend_Queue_Stomp_Client($options['scheme'], $options['host'], $options['port']);
+        }
+
+        $connect = $this->_client->createFrame();
+
+        // Username and password are optional on some messaging servers
+        // such as Apache's ActiveMQ
+        $connect->setCommand('CONNECT');
+        if (isset($options['username'])) {
+            $connect->setHeader('login', $options['username']);
+            $connect->setHeader('passcode', $options['password']);
+        }
+
+        $response = $this->_client->send($connect)->receive();
+
+        if ((false !== $response) 
+            && ($response->getCommand() != 'CONNECTED')
+        ) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception("Unable to authenticate to '".$options['scheme'].'://'.$options['host'].':'.$options['port']."'");
+        }
+    }
+
+    /**
+     * Close the socket explicitly when destructed
+     *
+     * @return void
+     */
+    public function __destruct()
+    {
+        // Gracefully disconnect
+        $frame = $this->_client->createFrame();
+        $frame->setCommand('DISCONNECT');
+        $this->_client->send($frame);
+        unset($this->_client);
+    }
+
+    /**
+     * Create a new queue
+     *
+     * @param  string  $name    queue name
+     * @param  integer $timeout default visibility timeout
+     * @return void
+     * @throws Zend_Queue_Exception
+     */
+    public function create($name, $timeout=null)
+    {
+        require_once 'Zend/Queue/Exception.php';
+        throw new Zend_Queue_Exception('create() is not supported in ' . get_class($this));
+    }
+
+    /**
+     * Delete a queue and all of its messages
+     *
+     * @param  string $name queue name
+     * @return void
+     * @throws Zend_Queue_Exception
+     */
+    public function delete($name)
+    {
+        require_once 'Zend/Queue/Exception.php';
+        throw new Zend_Queue_Exception('delete() is not supported in ' . get_class($this));
+    }
+
+    /**
+     * Delete a message from the queue
+     *
+     * Returns true if the message is deleted, false if the deletion is
+     * unsuccessful.
+     *
+     * @param  Zend_Queue_Message $message
+     * @return boolean
+     */
+    public function deleteMessage(Zend_Queue_Message $message)
+    {
+        $frame = $this->_client->createFrame();
+        $frame->setCommand('ack');
+        $frame->setHeader('message-id', $message->handle);
+
+        $this->_client->send($frame);
+
+        return true;
+    }
+
+    /**
+     * Get an array of all available queues
+     *
+     * @return void
+     * @throws Zend_Queue_Exception
+     */
+    public function getQueues()
+    {
+        require_once 'Zend/Queue/Exception.php';
+        throw new Zend_Queue_Exception('getQueues() is not supported in this adapter');
+    }
+
+    /**
+     * Return the first element in the queue
+     *
+     * @param  integer    $maxMessages
+     * @param  integer    $timeout
+     * @param  Zend_Queue $queue
+     * @return Zend_Queue_Message_Iterator
+     */
+    public function receive($maxMessages=null, $timeout=null, Zend_Queue $queue=null)
+    {
+        if ($maxMessages === null) {
+            $maxMessages = 1;
+        }
+        if ($timeout === null) {
+            $timeout = self::RECEIVE_TIMEOUT_DEFAULT;
+        }
+        if ($queue === null) {
+            $queue = $this->_queue;
+        }
+
+        // signal that we are reading
+        $frame = $this->_client->createFrame();
+        $frame->setCommand('SUBSCRIBE');
+        $frame->setHeader('destination', $queue->getName());
+        $frame->setHeader('ack','client');
+        $this->_client->send($frame);
+
+        // read
+        $data = array();
+        if ($this->_client->canRead()) {
+            for ($i = 0; $i < $maxMessages; $i++) {
+                $response = $this->_client->receive();
+
+                switch ($response->getCommand()) {
+                    case 'MESSAGE':
+                        $datum = array(
+                            'message_id' => $response->getHeader('message-id'),
+                            'handle'     => $response->getHeader('message-id'),
+                            'body'       => $response->getBody(),
+                            'md5'        => md5($response->getBody())
+                        );
+                        $data[] = $datum;
+                        break;
+                    default:
+                        $block = print_r($response, true);
+                        require_once 'Zend/Queue/Exception.php';
+                        throw new Zend_Queue_Exception('Invalid response received: ' . $block);
+                }
+            }
+        }
+
+        $options = array(
+            'queue'        => $queue,
+            'data'         => $data,
+            'messageClass' => $queue->getMessageClass()
+        );
+
+        $classname = $queue->getMessageSetClass();
+
+        if (!class_exists($classname)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($classname);
+        }
+        return new $classname($options);
+    }
+
+    /**
+     * Push an element onto the end of the queue
+     *
+     * @param  string     $message message to send to the queue
+     * @param  Zend_Queue $queue
+     * @return Zend_Queue_Message
+     */
+    public function send($message, Zend_Queue $queue=null)
+    {
+        if ($queue === null) {
+            $queue = $this->_queue;
+        }
+
+        $frame = $this->_client->createFrame();
+        $frame->setCommand('SEND');
+        $frame->setHeader('destination', $queue->getName());
+        $frame->setHeader('content-length', strlen($message));
+        $frame->setBody($message);
+        $this->_client->send($frame);
+
+        $data = array(
+            'message_id' => null,
+            'body'       => $message,
+            'md5'        => md5($message),
+            'handle'     => null
+        );
+
+        $options = array(
+            'queue' => $queue,
+            'data'  => $data
+        );
+
+        $classname = $queue->getMessageClass();
+        if (!class_exists($classname)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($classname);
+        }
+        return new $classname($options);
+    }
+
+    /**
+     * Returns the length of the queue
+     *
+     * @param  Zend_Queue $queue
+     * @return integer
+     * @throws Zend_Queue_Exception (not supported)
+     */
+    public function count(Zend_Queue $queue=null)
+    {
+        require_once 'Zend/Queue/Exception.php';
+        throw new Zend_Queue_Exception('count() is not supported in this adapter');
+    }
+
+    /**
+     * Does a queue already exist?
+     *
+     * @param  string $name
+     * @return boolean
+     * @throws Zend_Queue_Exception (not supported)
+     */
+    public function isExists($name)
+    {
+        require_once 'Zend/Queue/Exception.php';
+        throw new Zend_Queue_Exception('isExists() is not supported in this adapter');
+    }
+
+    /**
+     * Return a list of queue capabilities functions
+     *
+     * $array['function name'] = true or false
+     * true is supported, false is not supported.
+     *
+     * @param  string $name
+     * @return array
+     */
+    public function getCapabilities()
+    {
+        return array(
+            'create'        => false,
+            'delete'        => false,
+            'send'          => true,
+            'receive'       => true,
+            'deleteMessage' => true,
+            'getQueues'     => false,
+            'count'         => false,
+            'isExists'      => false,
+        );
+    }
+}

+ 352 - 0
library/Zend/Queue/Adapter/Array.php

@@ -0,0 +1,352 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Queue_Adapter_AdapterAbstract
+ */
+require_once 'Zend/Queue/Adapter/AdapterAbstract.php';
+
+/**
+ * Class for using a standard PHP array as a queue
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Queue_Adapter_Array extends Zend_Queue_Adapter_AdapterAbstract
+{
+    /**
+     * @var array
+     */
+    protected $_data = array();
+
+    /**
+     * Constructor
+     *
+     * @param  array|Zend_Config $options
+     * @param  Zend_Queue|null $queue
+     * @return void
+     */
+    public function __construct($options, Zend_Queue $queue = null)
+    {
+        parent::__construct($options, $queue);
+    }
+
+    /********************************************************************
+    * Queue management functions
+     *********************************************************************/
+
+    /**
+     * Does a queue already exist?
+     *
+     * Throws an exception if the adapter cannot determine if a queue exists.
+     * use isSupported('isExists') to determine if an adapter can test for
+     * queue existance.
+     *
+     * @param  string $name
+     * @return boolean
+     */
+    public function isExists($name)
+    {
+        return array_key_exists($name, $this->_data);
+    }
+
+    /**
+     * Create a new queue
+     *
+     * Visibility timeout is how long a message is left in the queue "invisible"
+     * to other readers.  If the message is acknowleged (deleted) before the
+     * timeout, then the message is deleted.  However, if the timeout expires
+     * then the message will be made available to other queue readers.
+     *
+     * @param  string  $name    queue name
+     * @param  integer $timeout default visibility timeout
+     * @return boolean
+     */
+    public function create($name, $timeout=null)
+    {
+        if ($this->isExists($name)) {
+            return false;
+        }
+        if ($timeout === null) {
+            $timeout = self::CREATE_TIMEOUT_DEFAULT;
+        }
+        $this->_data[$name] = array();
+
+        return true;
+    }
+
+    /**
+     * Delete a queue and all of it's messages
+     *
+     * Returns false if the queue is not found, true if the queue exists
+     *
+     * @param  string  $name queue name
+     * @return boolean
+     */
+    public function delete($name)
+    {
+        $found = isset($this->_data[$name]);
+
+        if ($found) {
+            unset($this->_data[$name]);
+        }
+
+        return $found;
+    }
+
+    /**
+     * Get an array of all available queues
+     *
+     * Not all adapters support getQueues(), use isSupported('getQueues')
+     * to determine if the adapter supports this feature.
+     *
+     * @return array
+     */
+    public function getQueues()
+    {
+        return array_keys($this->_data);
+    }
+
+    /**
+     * Return the approximate number of messages in the queue
+     *
+     * @param  Zend_Queue $queue
+     * @return integer
+     * @throws Zend_Queue_Exception
+     */
+    public function count(Zend_Queue $queue=null)
+    {
+        if ($queue === null) {
+            $queue = $this->_queue;
+        }
+
+        if (!isset($this->_data[$queue->getName()])) {
+            /**
+             * @see Zend_Queue_Exception
+             */
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('Queue does not exist');
+        }
+
+        return count($this->_data[$queue->getName()]);
+    }
+
+    /********************************************************************
+    * Messsage management functions
+     *********************************************************************/
+
+    /**
+     * Send a message to the queue
+     *
+     * @param  string     $message Message to send to the active queue
+     * @param  Zend_Queue $queue
+     * @return Zend_Queue_Message
+     * @throws Zend_Queue_Exception
+     */
+    public function send($message, Zend_Queue $queue=null)
+    {
+        if ($queue === null) {
+            $queue = $this->_queue;
+        }
+
+        if (!$this->isExists($queue->getName())) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('Queue does not exist:' . $queue->getName());
+        }
+
+        // create the message
+        $data = array(
+            'message_id' => md5(uniqid(rand(), true)),
+            'body'       => $message,
+            'md5'        => md5($message),
+            'handle'     => null,
+            'created'    => time(),
+            'queue_name' => $queue->getName(),
+        );
+
+        // add $data to the "queue"
+        $this->_data[$queue->getName()][] = $data;
+
+        $options = array(
+            'queue' => $queue,
+            'data'  => $data,
+        );
+
+        $classname = $queue->getMessageClass();
+        if (!class_exists($classname)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($classname);
+        }
+        return new $classname($options);
+    }
+
+    /**
+     * Get messages in the queue
+     *
+     * @param  integer    $maxMessages  Maximum number of messages to return
+     * @param  integer    $timeout      Visibility timeout for these messages
+     * @param  Zend_Queue $queue
+     * @return Zend_Queue_Message_Iterator
+     */
+    public function receive($maxMessages = null, $timeout = null, Zend_Queue $queue = null)
+    {
+        if ($maxMessages === null) {
+            $maxMessages = 1;
+        }
+        if ($timeout === null) {
+            $timeout = self::RECEIVE_TIMEOUT_DEFAULT;
+        }
+        if ($queue === null) {
+            $queue = $this->_queue;
+        }
+
+        $data       = array();
+        $start_time = microtime(true);
+
+        $count = 0;
+        $temp = &$this->_data[$queue->getName()];
+        foreach ($temp as $key=>&$msg) {
+            if (($msg['handle'] === null) 
+                || ($msg['timeout'] + $timeout < $start_time)
+            ) {
+                $msg['handle']  = md5(uniqid(rand(), true));
+                $msg['timeout'] = microtime(true);
+                $data[] = $msg;
+                $count++;
+            }
+
+            if ($count >= $maxMessages) {
+                break;
+            }
+        }
+
+        $options = array(
+            'queue'        => $queue,
+            'data'         => $data,
+            'messageClass' => $queue->getMessageClass(),
+        );
+
+        $classname = $queue->getMessageSetClass();
+        if (!class_exists($classname)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($classname);
+        }
+        return new $classname($options);
+    }
+
+    /**
+     * Delete a message from the queue
+     *
+     * Returns true if the message is deleted, false if the deletion is
+     * unsuccessful.
+     *
+     * @param  Zend_Queue_Message $message
+     * @return boolean
+     * @throws Zend_Queue_Exception
+     */
+    public function deleteMessage(Zend_Queue_Message $message)
+    {
+        // load the queue
+        $queue = &$this->_data[$message->queue_name];
+
+        foreach ($queue as $key => &$msg) {
+            if ($msg['handle'] == $message->handle) {
+                unset($queue[$key]);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+    /********************************************************************
+     * Supporting functions
+     *********************************************************************/
+
+    /**
+     * Return a list of queue capabilities functions
+     *
+     * $array['function name'] = true or false
+     * true is supported, false is not supported.
+     *
+     * @param  string $name
+     * @return array
+     */
+    public function getCapabilities()
+    {
+        return array(
+            'create'        => true,
+            'delete'        => true,
+            'send'          => true,
+            'receive'       => true,
+            'deleteMessage' => true,
+            'getQueues'     => true,
+            'count'         => true,
+            'isExists'      => true,
+        );
+    }
+
+    /********************************************************************
+    * Functions that are not part of the Zend_Queue_Adapter_Abstract
+     *********************************************************************/
+
+    /**
+     * serialize
+     */
+    public function __sleep()
+    {
+        return array('_data');
+    }
+
+    /*
+     * These functions are debug helpers.
+     */
+
+    /**
+     * returns underlying _data array
+     *
+     * @example $queue->getAdapter()->getData();
+     *
+     * @return $this;
+     */
+    public function getData()
+    {
+        return $this->_data;
+    }
+
+    /**
+     * sets the underlying _data array
+     *
+     * @example $queue->getAdapter()->setData($data);
+     *
+     * @param $data array
+     * @return $this;
+     */
+    public function setData($data)
+    {
+        $this->_data = $data;
+        return $this;
+    }
+}

+ 482 - 0
library/Zend/Queue/Adapter/Db.php

@@ -0,0 +1,482 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Queue_Adapter_AdapterAbstract
+ */
+require_once 'Zend/Queue/Adapter/AdapterAbstract.php';
+
+/**
+ * @see Zend_Db_Select
+ */
+require_once 'Zend/Db/Select.php';
+
+/**
+ * @see Zend_Db
+ */
+require_once 'Zend/Db.php';
+
+/**
+ * @see Zend_Queue_Adapter_Db_Queue
+ */
+require_once 'Zend/Queue/Adapter/Db/Queue.php';
+
+/**
+ * @see Zend_Queue_Adapter_Db_Message
+ */
+require_once 'Zend/Queue/Adapter/Db/Message.php';
+
+/**
+ * Class for using connecting to a Zend_Db-based queuing system
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Queue_Adapter_Db extends Zend_Queue_Adapter_AdapterAbstract
+{
+    /**
+     * @var Zend_Queue_Adapter_Db_Queue
+     */
+    protected $_queueTable = null;
+
+    /**
+     * @var Zend_Queue_Adapter_Db_Message
+     */
+    protected $_messageTable = null;
+
+    /**
+     * Constructor
+     *
+     * @param  array|Zend_Config $options
+     * @param  Zend_Queue|null $queue
+     * @return void
+     */
+    public function __construct($options, Zend_Queue $queue = null)
+    {
+        parent::__construct($options, $queue);
+
+        if (!isset($this->_options['options'][Zend_Db_Select::FOR_UPDATE])) {
+            // turn off auto update by default
+            $this->_options['options'][Zend_Db_Select::FOR_UPDATE] = false;
+        }
+
+        if (!is_bool($this->_options['options'][Zend_Db_Select::FOR_UPDATE])) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('Options array item: Zend_Db_Select::FOR_UPDATE must be boolean');
+        }
+
+        $options = &$this->_options['driverOptions'];
+        if (!array_key_exists('type', $options)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception("Configuration array must have a key for 'type' for the database type to use");
+        }
+
+        if (!array_key_exists('host', $options)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception("Configuration array must have a key for 'host' for the host to use");
+        }
+
+        if (!array_key_exists('username', $options)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception("Configuration array must have a key for 'username' for the username to use");
+        }
+
+        if (!array_key_exists('password', $options)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception("Configuration array must have a key for 'password' for the password to use");
+        }
+
+        if (!array_key_exists('dbname', $options)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception("Configuration array must have a key for 'dbname' for the database to use");
+        }
+
+        try {
+            $db = Zend_Db::factory($options['type'], $options);
+
+            $this->_queueTable = new Zend_Queue_Adapter_Db_Queue(array(
+                'db' => $db,
+            ));
+
+            $this->_messageTable = new Zend_Queue_Adapter_Db_Message(array(
+                'db' => $db,
+            ));
+        } catch (Zend_Db_Exception $e) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('Error connecting to database: ' . $e->getMessage(), $e->getCode());
+        }
+    }
+
+    /********************************************************************
+     * Queue management functions
+     *********************************************************************/
+
+    /**
+     * Does a queue already exist?
+     *
+     * Throws an exception if the adapter cannot determine if a queue exists.
+     * use isSupported('isExists') to determine if an adapter can test for
+     * queue existance.
+     *
+     * @param  string $name
+     * @return boolean
+     * @throws Zend_Queue_Exception
+     */
+    public function isExists($name)
+    {
+        return in_array($name, $this->getQueues());
+    }
+
+    /**
+     * Create a new queue
+     *
+     * Visibility timeout is how long a message is left in the queue "invisible"
+     * to other readers.  If the message is acknowleged (deleted) before the
+     * timeout, then the message is deleted.  However, if the timeout expires
+     * then the message will be made available to other queue readers.
+     *
+     * @param  string  $name    queue name
+     * @param  integer $timeout default visibility timeout
+     * @return boolean
+     * @throws Zend_Queue_Exception - database error
+     */
+    public function create($name, $timeout = null)
+    {
+        if ($this->isExists($name)) {
+            $this->getLogger()->warn('Create queue failed. Queue already exists: ' . $name);
+            return false;
+        }
+
+        $queue = $this->_queueTable->createRow();
+        $queue->queue_name = $name;
+        $queue->timeout = ($timeout === null) ? self::CREATE_TIMEOUT_DEFAULT : (int)$timeout;
+
+        try {
+            if ($id = $queue->save()) {
+                $this->getLogger()->info('Queue created: ' . $name);
+                return true;
+            }
+        } catch (Exception $e) {
+            $this->getLogger()->err($e->getMessage() . ' code ' . $e->getCode());
+            /**
+             * @see Zend_Queue_Exception
+             */
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception($e->getMessage(), $e->getCode());
+        }
+
+        return false;
+    }
+
+    /**
+     * Delete a queue and all of it's messages
+     *
+     * Returns false if the queue is not found, true if the queue exists
+     *
+     * @param  string  $name queue name
+     * @return boolean
+     * @throws Zend_Queue_Exception - database error
+     */
+    public function delete($name)
+    {
+        $id = $this->getQueueId($name); // get primary key
+
+        // if the queue does not exist then it must already be deleted.
+        $list = $this->_queueTable->find($id);
+        if (count($list) === 0) {
+            return false;
+        }
+        $queue = $list->current();
+
+        if ($queue instanceof Zend_Db_Table_Row_Abstract) {
+            try {
+                $queue->delete();
+            } catch (Exception $e) {
+                require_once 'Zend/Queue/Exception.php';
+                throw new Zend_Queue_Exception($e->getMessage(), $e->getCode());
+            }
+        }
+
+        return true;
+    }
+
+    /*
+     * Get an array of all available queues
+     *
+     * Not all adapters support getQueues(), use isSupported('getQueues')
+     * to determine if the adapter supports this feature.
+     *
+     * @return array
+     * @throws Zend_Queue_Exception - database error
+     */
+    public function getQueues()
+    {
+        $query = $this->_queueTable->select();
+        $query->from($this->_queueTable, array('queue_id', 'queue_name'));
+
+        $list = array();
+        foreach ($this->_queueTable->fetchAll($query) as $queue) {
+            $list[] = $queue->queue_name;
+        }
+
+        return $list;
+    }
+
+    /**
+     * Return the approximate number of messages in the queue
+     *
+     * @param  Zend_Queue $queue
+     * @return integer
+     * @throws Zend_Queue_Exception
+     */
+    public function count(Zend_Queue $queue = null)
+    {
+        if ($queue === null) {
+            $queue = $this->_queue;
+        }
+
+        $info  = $this->_messageTable->info();
+        $db    = $this->_messageTable->getAdapter();
+        $query = $db->select();
+        $query->from($info['name'], array(new Zend_Db_Expr('COUNT(1)')))
+              ->where('queue_id=?', $this->getQueueId($queue->getName()));
+
+        // return count results
+        return (int) $db->fetchOne($query);
+    }
+
+    /********************************************************************
+    * Messsage management functions
+     *********************************************************************/
+
+    /**
+     * Send a message to the queue
+     *
+     * @param  string     $message Message to send to the active queue
+     * @param  Zend_Queue $queue
+     * @return Zend_Queue_Message
+     * @throws Zend_Queue_Exception - database error
+     */
+    public function send($message, Zend_Queue $queue = null)
+    {
+        if ($queue === null) {
+            $queue = $this->_queue;
+        }
+
+        $message = trim($message);
+
+        if (!$this->isExists($queue->getName())) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('Queue does not exist:' . $queue->getName());
+        }
+
+        $msg           = $this->_messageTable->createRow();
+        $msg->queue_id = $this->getQueueId($queue->getName());
+        $msg->created  = time();
+        $msg->body     = $message;
+        $msg->md5      = md5($message);
+        // $msg->timeout = ??? @TODO
+
+        try {
+            $msg->save();
+        } catch (Exception $e) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception($e->getMessage(), $e->getCode());
+        }
+
+        $options = array(
+            'queue' => $queue,
+            'data'  => $msg->toArray(),
+        );
+
+        $classname = $queue->getMessageClass();
+        if (!class_exists($classname)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($classname);
+        }
+        return new $classname($options);
+    }
+
+    /**
+     * Get messages in the queue
+     *
+     * @param  integer    $maxMessages  Maximum number of messages to return
+     * @param  integer    $timeout      Visibility timeout for these messages
+     * @param  Zend_Queue $queue
+     * @return Zend_Queue_Message_Iterator
+     * @throws Zend_Queue_Exception - database error
+     */
+    public function receive($maxMessages = null, $timeout = null, Zend_Queue $queue = null)
+    {
+        if ($maxMessages === null) {
+            $maxMessages = 1;
+        }
+        if ($timeout === null) {
+            $timeout = self::RECEIVE_TIMEOUT_DEFAULT;
+        }
+        if ($queue === null) {
+            $queue = $this->_queue;
+        }
+
+        $msgs      = array();
+        $info      = $this->_messageTable->info();
+        $microtime = microtime(true); // cache microtime
+        $db        = $this->_messageTable->getAdapter();
+
+        // start transaction handling
+        try {
+            $db->beginTransaction();
+
+            $query = $db->select();
+            if ($this->_config['options'][Zend_Db_Select::FOR_UPDATE]) {
+                // turn on forUpdate
+                $query->forUpdate();
+            }
+            $query->from($info['name'], array('*'))
+                  ->where('queue_id=?', $this->getQueueId($queue->getName()))
+                  ->where('handle IS NULL OR timeout+' . (int)$timeout . ' < ' . (int)$microtime)
+                  ->limit($maxMessages);
+
+            foreach ($db->fetchAll($query) as $data) {
+                // setup our changes to the message
+                $data['handle'] = md5(uniqid(rand(), true));
+
+                $update = array(
+                    'handle'  => $data['handle'],
+                    'timeout' => $microtime,
+                );
+
+                // update the database
+                $where   = array();
+                $where[] = $db->quoteInto('message_id=?', $data['message_id']);
+                $where[] = 'handle IS NULL OR timeout+' . (int)$timeout . ' < ' . (int)$microtime;
+
+                $count = $db->update($info['name'], $update, $where);
+
+                // we check count to make sure no other thread has gotten
+                // the rows after our select, but before our update.
+                if ($count > 0) {
+                    $msgs[] = $data;
+                }
+            }
+            $db->commit();
+        } catch (Exception $e) {
+            $db->rollBack();
+
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception($e->getMessage(), $e->getCode());
+        }
+
+        $options = array(
+            'queue'        => $queue,
+            'data'         => $msgs,
+            'messageClass' => $queue->getMessageClass(),
+        );
+
+        $classname = $queue->getMessageSetClass();
+        if (!class_exists($classname)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($classname);
+        }
+        return new $classname($options);
+    }
+
+    /**
+     * Delete a message from the queue
+     *
+     * Returns true if the message is deleted, false if the deletion is
+     * unsuccessful.
+     *
+     * @param  Zend_Queue_Message $message
+     * @return boolean
+     * @throws Zend_Queue_Exception - database error
+     */
+    public function deleteMessage(Zend_Queue_Message $message)
+    {
+        $db    = $this->_messageTable->getAdapter();
+        $where = $db->quoteInto('handle=?', $message->handle);
+
+        if ($this->_messageTable->delete($where)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /********************************************************************
+     * Supporting functions
+     *********************************************************************/
+
+    /**
+     * Return a list of queue capabilities functions
+     *
+     * $array['function name'] = true or false
+     * true is supported, false is not supported.
+     *
+     * @param  string $name
+     * @return array
+     */
+    public function getCapabilities()
+    {
+        return array(
+            'create'        => true,
+            'delete'        => true,
+            'send'          => true,
+            'receive'       => true,
+            'deleteMessage' => true,
+            'getQueues'     => true,
+            'count'         => true,
+            'isExists'      => true,
+        );
+    }
+
+    /********************************************************************
+     * Functions that are not part of the Zend_Queue_Adapter_Abstract
+     *********************************************************************/
+    /**
+     * Get the queue ID
+     *
+     * Returns the queue's row identifier.
+     *
+     * @param  string       $name
+     * @return integer|null
+     * @throws Zend_Queue_Exception
+     */
+    protected function getQueueId($name)
+    {
+        $query = $this->_queueTable->select();
+        $query->from($this->_queueTable, array('queue_id'))
+              ->where('queue_name=?', $name);
+
+        $queue = $this->_queueTable->fetchRow($query);
+
+        if ($queue === null) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('Queue does not exist: ' . $name);
+        }
+
+        return (int)$queue->queue_id;
+    }
+}

+ 51 - 0
library/Zend/Queue/Adapter/Db/Message.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Array.php 2002 2009-03-05 20:02:15Z jplock $
+ */
+
+/**
+ * @see Zend_Db_Table_Abstract
+ */
+require_once 'Zend/Db/Table/Abstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Queue_Adapter_Db_Message extends Zend_Db_Table_Abstract
+{
+    /**
+     * @var string
+     */
+    protected $_name = 'message';
+
+    /**
+     * @var string
+     */
+    protected $_primary = 'message_id';
+
+    /**
+     * @var mixed
+     */
+    protected $_sequence = true;
+}

+ 51 - 0
library/Zend/Queue/Adapter/Db/Queue.php

@@ -0,0 +1,51 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Array.php 2002 2008-03-05 20:02:15Z jplock $
+ */
+
+/**
+ * @see Zend_Db_Table_Abstract
+ */
+require_once 'Zend/Db/Table/Abstract.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Queue_Adapter_Db_Queue extends Zend_Db_Table_Abstract
+{
+    /**
+     * @var string
+     */
+    protected $_name = 'queue';
+
+    /**
+     * @var string
+     */
+    protected $_primary = 'queue_id';
+
+    /**
+     * @var mixed
+     */
+    protected $_sequence = true;
+}

+ 75 - 0
library/Zend/Queue/Adapter/Db/queue.sql

@@ -0,0 +1,75 @@
+-- phpMyAdmin SQL Dump
+-- version 2.11.6
+-- http://www.phpmyadmin.net
+--
+-- Host: localhost:3306
+-- Generation Time: Jun 19, 2008 at 08:09 PM
+-- Server version: 5.0.51
+-- PHP Version: 5.2.3
+
+SET SQL_MODE="NO_AUTO_VALUE_ON_ZERO";
+
+/*
+Sample grant for MySQL
+
+GRANT DELETE, INSERT, SELECT, UPDATE ON queue.* TO 'queue'@'127.0.0.1' IDENTIFIED BY '[CHANGE ME]';
+mysql -u queue -h 127.0.0.1 -p queue
+
+mysqlaccess queue queue --superuser=root -H 127.0.0.1
+
+
+*/
+
+
+/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */;
+/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */;
+/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */;
+/*!40101 SET NAMES utf8 */;
+
+--
+-- Database: `queue`
+--
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `message`
+--
+
+DROP TABLE IF EXISTS `message`;
+CREATE TABLE IF NOT EXISTS `message` (
+  `message_id` bigint(20) unsigned NOT NULL auto_increment,
+  `queue_id` int(10) unsigned NOT NULL,
+  `handle` char(32) default NULL,
+  `body` varchar(8192) NOT NULL,
+  `md5` char(32) NOT NULL,
+  `timeout` decimal(14,4) unsigned default NULL,
+  `created` int(10) unsigned NOT NULL,
+  PRIMARY KEY  (`message_id`),
+  UNIQUE KEY `message_handle` (`handle`),
+  KEY `message_queueid` (`queue_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+-- --------------------------------------------------------
+
+--
+-- Table structure for table `queue`
+--
+
+DROP TABLE IF EXISTS `queue`;
+CREATE TABLE IF NOT EXISTS `queue` (
+  `queue_id` int(10) unsigned NOT NULL auto_increment,
+  `queue_name` varchar(100) NOT NULL,
+  `timeout` smallint(5) unsigned NOT NULL default '30',
+  PRIMARY KEY  (`queue_id`)
+) ENGINE=InnoDB DEFAULT CHARSET=utf8;
+
+--
+-- Constraints for dumped tables
+--
+
+--
+-- Constraints for table `message`
+--
+ALTER TABLE `message`
+  ADD CONSTRAINT `message_ibfk_1` FOREIGN KEY (`queue_id`) REFERENCES `queue` (`queue_id`) ON DELETE CASCADE ON UPDATE CASCADE;

+ 404 - 0
library/Zend/Queue/Adapter/Memcacheq.php

@@ -0,0 +1,404 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Queue_Adapter_AdapterAbstract
+ */
+require_once 'Zend/Queue/Adapter/AdapterAbstract.php';
+
+/**
+ * Class for using connecting to a Zend_Cache-based queuing system
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Queue_Adapter_Memcacheq extends Zend_Queue_Adapter_AdapterAbstract
+{
+    const DEFAULT_HOST = '127.0.0.1';
+    const DEFAULT_PORT = 22201;
+    const EOL          = "\r\n";
+
+    /**
+     * @var Memcache
+     */
+    protected $_cache = null;
+
+    /**
+     * @var string
+     */
+    protected $_host = null;
+
+    /**
+     * @var integer
+     */
+    protected $_port = null;
+
+    /********************************************************************
+    * Constructor / Destructor
+     *********************************************************************/
+
+    /**
+     * Constructor
+     *
+     * @param  array|Zend_Config $options
+     * @param  null|Zend_Queue $queue
+     * @return void
+     */
+    public function __construct($options, Zend_Queue $queue = null)
+    {
+        if (!extension_loaded('memcache')) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('Memcache extension does not appear to be loaded');
+        }
+
+        parent::__construct($options, $queue);
+
+        $options = &$this->_options['driverOptions'];
+
+        if (!array_key_exists('host', $options)) {
+            $options['host'] = self::DEFAULT_HOST;
+        }
+        if (!array_key_exists('port', $options)) {
+            $options['port'] = self::DEFAULT_PORT;
+        }
+
+        $this->_cache = new Memcache();
+
+        $result = $this->_cache->connect($options['host'], $options['port']);
+
+        if ($result === false) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('Could not connect to MemcacheQ');
+        }
+
+        $this->_host = $options['host'];
+        $this->_port = (int)$options['port'];
+    }
+
+    /**
+     * Destructor
+     *
+     * @return void
+     */
+    public function __destruct()
+    {
+        if ($this->_cache instanceof Memcache) {
+            $this->_cache->close();
+        }
+    }
+
+    /********************************************************************
+     * Queue management functions
+     *********************************************************************/
+
+    /**
+     * Does a queue already exist?
+     *
+     * Throws an exception if the adapter cannot determine if a queue exists.
+     * use isSupported('isExists') to determine if an adapter can test for
+     * queue existance.
+     *
+     * @param  string $name
+     * @return boolean
+     * @throws Zend_Queue_Exception
+     */
+    public function isExists($name)
+    {
+        return in_array($name, $this->getQueues());
+    }
+
+    /**
+     * Create a new queue
+     *
+     * Visibility timeout is how long a message is left in the queue "invisible"
+     * to other readers.  If the message is acknowleged (deleted) before the
+     * timeout, then the message is deleted.  However, if the timeout expires
+     * then the message will be made available to other queue readers.
+     *
+     * @param  string  $name    queue name
+     * @param  integer $timeout default visibility timeout
+     * @return boolean
+     * @throws Zend_Queue_Exception
+     */
+    public function create($name, $timeout=null)
+    {
+        if ($this->isExists($name)) {
+            return false;
+        }
+        if ($timeout === null) {
+            $timeout = self::CREATE_TIMEOUT_DEFAULT;
+        }
+
+        // MemcacheQ does not have a method to "create" a queue
+        // queues are created upon sending a packet.
+        // We cannot use the send() and receive() functions because those
+        // depend on the current name.
+        $result = $this->_cache->set($name, 'creating queue', 0, 15);
+        $result = $this->_cache->get($name);
+
+        return true;
+    }
+
+    /**
+     * Delete a queue and all of it's messages
+     *
+     * Returns false if the queue is not found, true if the queue exists
+     *
+     * @param  string  $name queue name
+     * @return boolean
+     * @throws Zend_Queue_Exception
+     */
+    public function delete($name)
+    {
+        $response = $this->_sendCommand('delete ' . $name, array('DELETED', 'NOT_FOUND'), true);
+
+        if (in_array('DELETED', $response)) {
+            return true;
+        }
+
+        return false;
+    }
+
+    /**
+     * Get an array of all available queues
+     *
+     * Not all adapters support getQueues(), use isSupported('getQueues')
+     * to determine if the adapter supports this feature.
+     *
+     * @return array
+     * @throws Zend_Queue_Exception
+     */
+    public function getQueues()
+    {
+        $response = $this->_sendCommand('stats queue', array('END'));
+        $list     = array();
+
+        foreach ($response as $i => $line) {
+            $list[] = str_replace('STAT ', '', $line);
+        }
+
+        return $list;
+    }
+
+    /**
+     * Return the approximate number of messages in the queue
+     *
+     * @param  Zend_Queue $queue
+     * @return integer
+     * @throws Zend_Queue_Exception (not supported)
+     */
+    public function count(Zend_Queue $queue=null)
+    {
+        require_once 'Zend/Queue/Exception.php';
+        throw new Zend_Queue_Exception('count() is not supported in this adapter');
+    }
+
+    /********************************************************************
+     * Messsage management functions
+     *********************************************************************/
+
+    /**
+     * Send a message to the queue
+     *
+     * @param  string     $message Message to send to the active queue
+     * @param  Zend_Queue $queue
+     * @return Zend_Queue_Message
+     * @throws Zend_Queue_Exception
+     */
+    public function send($message, Zend_Queue $queue=null)
+    {
+        if ($queue === null) {
+            $queue = $this->_queue;
+        }
+
+        if (!$this->isExists($queue->getName())) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('Queue does not exist:' . $queue->getName());
+        }
+
+        $data = array(
+            'message_id' => md5(uniqid(rand(), true)),
+            'handle'     => null,
+            'body'       => $message,
+            'md5'        => md5($message),
+        );
+
+        $result = $this->_cache->set($queue->getName(), $message, 0, 0);
+        if ($result === false) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('failed to insert message into queue:' . $queue->getName());
+        }
+
+        $options = array(
+            'queue' => $queue,
+            'data'  => $data,
+        );
+
+        $classname = $queue->getMessageClass();
+        if (!class_exists($classname)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($classname);
+        }
+        return new $classname($options);
+    }
+
+    /**
+     * Get messages in the queue
+     *
+     * @param  integer    $maxMessages  Maximum number of messages to return
+     * @param  integer    $timeout      Visibility timeout for these messages
+     * @param  Zend_Queue $queue
+     * @return Zend_Queue_Message_Iterator
+     * @throws Zend_Queue_Exception
+     */
+    public function receive($maxMessages=null, $timeout=null, Zend_Queue $queue=null)
+    {
+        if ($maxMessages === null) {
+            $maxMessages = 1;
+        }
+        if ($timeout === null) {
+            $timeout = self::RECEIVE_TIMEOUT_DEFAULT;
+        }
+        if ($queue === null) {
+            $queue = $this->_queue;
+        }
+
+        $msgs = array();
+        for ($i = 0; $i < $maxMessages; $i++) {
+            $data = array(
+                'handle' => md5(uniqid(rand(), true)),
+                'body'   => $this->_cache->get($queue->getName()),
+            );
+
+            $msgs[] = $data;
+        }
+
+        $options = array(
+            'queue'        => $queue,
+            'data'         => $msgs,
+            'messageClass' => $queue->getMessageClass(),
+        );
+
+        $classname = $queue->getMessageSetClass();
+        if (!class_exists($classname)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($classname);
+        }
+        return new $classname($config);
+    }
+
+    /**
+     * Delete a message from the queue
+     *
+     * Returns true if the message is deleted, false if the deletion is
+     * unsuccessful.
+     *
+     * @param  Zend_Queue_Message $message
+     * @return boolean
+     * @throws Zend_Queue_Exception (unsupported)
+     */
+    public function deleteMessage(Zend_Queue_Message $message)
+    {
+        require_once 'Zend/Queue/Exception.php';
+        throw new Zend_Queue_Exception('deleteMessage() is not supported in  ' . get_class($this));
+    }
+
+    /********************************************************************
+     * Supporting functions
+     *********************************************************************/
+
+    /**
+     * Return a list of queue capabilities functions
+     *
+     * $array['function name'] = true or false
+     * true is supported, false is not supported.
+     *
+     * @param  string $name
+     * @return array
+     */
+    public function getCapabilities()
+    {
+        return array(
+            'create'        => true,
+            'delete'        => true,
+            'send'          => true,
+            'receive'       => true,
+            'deleteMessage' => false,
+            'getQueues'     => true,
+            'count'         => false,
+            'isExists'      => true,
+        );
+    }
+
+    /********************************************************************
+     * Functions that are not part of the Zend_Queue_Adapter_Abstract
+     *********************************************************************/
+
+    /**
+     * sends a command to MemcacheQ
+     *
+     * The memcache functions by php cannot handle all types of requests
+     * supported by MemcacheQ
+     * Non-standard requests are handled by this function.
+     *
+     * @param  string  $command - command to send to memcacheQ
+     * @param  array   $terminator - strings to indicate end of memcacheQ response
+     * @param  boolean $include_term - include terminator in response
+     * @return array
+     * @throws Zend_Queue_Exception if connection cannot be opened
+     */
+    protected function _sendCommand($command, array $terminator, $include_term=false)
+    {
+        $fp = fsockopen($this->_host, $this->_port, $errno, $errstr, 10);
+        if ($fp === false) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception("Could not open a connection to $this->_host:$this->_port errno=$errno : $errstr");
+        }
+
+        $response = array();
+
+        $cmd = $command . self::EOL;
+        fwrite($fp, $cmd);
+
+        $continue_reading = true;
+        while (!feof($fp) && $continue_reading) {
+            $resp = trim(fgets($fp, 1024));
+            if (in_array($resp, $terminator)) {
+                if ($include_term) {
+                    $response[] = $resp;
+                }
+                $continue_reading = false;
+            } else {
+                $response[] = $resp;
+            }
+        }
+
+        $cmd = 'quit' . self::EOL;
+        fwrite($fp, $cmd);
+        fclose($fp);
+
+        return $response;
+    }
+}

+ 174 - 0
library/Zend/Queue/Adapter/Null.php

@@ -0,0 +1,174 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Array.php 14724 2009-04-07 06:04:37Z danlo $
+ */
+
+/**
+ * @see Zend_Queue_Adapter_AdapterAbstract
+ */
+require_once 'Zend/Queue/Adapter/AdapterAbstract.php';
+
+/**
+ * Class testing.  No supported functions.  Also used to disable a Zend_Queue.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Queue_Adapter_Null extends Zend_Queue_Adapter_AdapterAbstract
+{
+    /**
+     * Constructor
+     *
+     * @param  array|Zend_Config $options
+     * @param  null|Zend_Queue $queue
+     * @return void
+     */
+    public function __construct($options, Zend_Queue $queue = null)
+    {
+        parent::__construct($options, $queue);
+    }
+
+    /********************************************************************
+     * Queue management functions
+     *********************************************************************/
+
+    /**
+     * Does a queue already exist?
+     *
+     * @throws Zend_Queue_Exception - not supported.
+     */
+    public function isExists($name)
+    {
+        require_once 'Zend/Queue/Exception.php';
+        throw new Zend_Queue_Exception(__FUNCTION__ . '() is not supported by ' . get_class($this));
+    }
+
+
+    /**
+     * Create a new queue
+     *
+     * @throws Zend_Queue_Exception - not supported.
+     */
+    public function create($name, $timeout=null)
+    {
+        require_once 'Zend/Queue/Exception.php';
+        throw new Zend_Queue_Exception(__FUNCTION__ . '() is not supported by ' . get_class($this));
+    }
+
+    /**
+     * Delete a queue and all of it's messages
+     *
+     * @throws Zend_Queue_Exception - not supported.
+     */
+    public function delete($name)
+    {
+        require_once 'Zend/Queue/Exception.php';
+        throw new Zend_Queue_Exception(__FUNCTION__ . '() is not supported by ' . get_class($this));
+    }
+
+    /**
+     * Get an array of all available queues
+     *
+     * @throws Zend_Queue_Exception - not supported.
+     */
+    public function getQueues()
+    {
+        require_once 'Zend/Queue/Exception.php';
+        throw new Zend_Queue_Exception(__FUNCTION__ . '() is not supported by ' . get_class($this));
+    }
+
+    /**
+     * Return the approximate number of messages in the queue
+     *
+     * @throws Zend_Queue_Exception - not supported.
+     */
+    public function count(Zend_Queue $queue=null)
+    {
+        require_once 'Zend/Queue/Exception.php';
+        throw new Zend_Queue_Exception(__FUNCTION__ . '() is not supported by ' . get_class($this));
+    }
+
+    /********************************************************************
+     * Messsage management functions
+     *********************************************************************/
+
+    /**
+     * Send a message to the queue
+     *
+     * @throws Zend_Queue_Exception - not supported.
+     */
+    public function send($message, Zend_Queue $queue=null)
+    {
+        require_once 'Zend/Queue/Exception.php';
+        throw new Zend_Queue_Exception(__FUNCTION__ . '() is not supported by ' . get_class($this));
+    }
+
+    /**
+     * Get messages in the queue
+     *
+     * @throws Zend_Queue_Exception - not supported.
+     */
+    public function receive($maxMessages=null, $timeout=null, Zend_Queue $queue=null)
+    {
+        require_once 'Zend/Queue/Exception.php';
+        throw new Zend_Queue_Exception(__FUNCTION__ . '() is not supported by ' . get_class($this));
+    }
+
+    /**
+     * Delete a message from the queue
+     *
+     * @throws Zend_Queue_Exception - not supported.
+     */
+    public function deleteMessage(Zend_Queue_Message $message)
+    {
+        require_once 'Zend/Queue/Exception.php';
+        throw new Zend_Queue_Exception(__FUNCTION__ . '() is not supported by ' . get_class($this));
+    }
+
+    /********************************************************************
+     * Supporting functions
+     *********************************************************************/
+
+    /**
+     * Return a list of queue capabilities functions
+     *
+     * $array['function name'] = true or false
+     * true is supported, false is not supported.
+     *
+     * @param  string $name
+     * @return array
+     */
+    public function getCapabilities()
+    {
+        return array(
+            'create'        => false,
+            'delete'        => false,
+            'send'          => false,
+            'receive'       => false,
+            'deleteMessage' => false,
+            'getQueues'     => false,
+            'count'         => false,
+            'isExists'      => false,
+        );
+    }
+}

+ 35 - 0
library/Zend/Queue/Exception.php

@@ -0,0 +1,35 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Exception
+ */
+require_once 'Zend/Exception.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Queue_Exception extends Zend_Exception
+{
+}

+ 230 - 0
library/Zend/Queue/Message.php

@@ -0,0 +1,230 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Message
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * Class for managing queue messages
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Message
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Queue_Message
+{
+    /**
+     * The data for the queue message
+     *
+     * @var array
+     */
+    protected $_data = array();
+
+     /**
+     * Connected is true if we have a reference to a live
+     * Zend_Queue_Adapter_Abstract object.
+     * This is false after the Message has been deserialized.
+     *
+     * @var boolean
+     */
+    protected $_connected = true;
+
+    /**
+     * Zend_Queue parent class or instance
+     *
+     * @var Zend_Queue
+     */
+    protected $_queue = null;
+
+    /**
+     * Name of the class of the Zend_Queue
+     *
+     * @var string
+     */
+    protected $_queueClass = null;
+
+    /**
+     * Constructor
+     *
+     * @param  array $options
+     * @throws Zend_Queue_Exception
+     */
+    public function __construct(array $options = array())
+    {
+        if (isset($options['queue'])) {
+            if ($options['queue'] instanceof Zend_Queue) {
+                $this->_queue      = $options['queue'];
+                $this->_queueClass = get_class($this->_queue);
+            } else {
+                $result = gettype($options['queue']);
+                if ($result === 'object') {
+                    $result = get_class($options['queue']);
+                }
+
+                require_once 'Zend/Queue/Exception.php';
+                throw new Zend_Queue_Exception(
+                    '$options[\'queue\'] = ' 
+                    . $result 
+                    . ': must be instanceof Zend_Queue'
+                );
+            }
+        }
+        if (isset($options['data'])) {
+            if (!is_array($options['data'])) {
+                require_once 'Zend/Queue/Exception.php';
+                throw new Zend_Queue_Exception('Data must be an array');
+            }
+            $this->_data = $options['data'];
+        }
+    }
+
+    /**
+     * Retrieve message field value
+     *
+     * @param  string $key The user-specified key name.
+     * @return string      The corresponding key value.
+     * @throws Zend_Queue_Exception if the $key is not a column in the message.
+     */
+    public function __get($key)
+    {
+        if (!array_key_exists($key, $this->_data)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception("Specified field \"$key\" is not in the message");
+        }
+        return $this->_data[$key];
+    }
+
+    /**
+     * Set message field value
+     *
+     * @param  string $key   The message key.
+     * @param  mixed  $value The value for the property.
+     * @return void
+     * @throws Zend_Queue_Exception
+     */
+    public function __set($key, $value)
+    {
+        if (!array_key_exists($key, $this->_data)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception("Specified field \"$key\" is not in the message");
+        }
+        $this->_data[$key] = $value;
+    }
+
+    /**
+     * Test existence of message field
+     *
+     * @param  string  $key The column key.
+     * @return boolean
+     */
+    public function __isset($key)
+    {
+        return array_key_exists($key, $this->_data);
+    }
+
+    /*
+     * Serialize
+     */
+
+    /**
+     * Store queue and data in serialized object
+     *
+     * @return array
+     */
+    public function __sleep()
+    {
+        return array('_queueClass', '_data');
+    }
+
+    /**
+     * Setup to do on wakeup.
+     * A de-serialized Message should not be assumed to have access to a live
+     * queue connection, so set _connected = false.
+     *
+     * @return void
+     */
+    public function __wakeup()
+    {
+        $this->_connected = false;
+    }
+
+     /**
+     * Returns the queue object, or null if this is disconnected message
+     *
+     * @return Zend_Queue|null
+     */
+    public function getQueue()
+    {
+        return $this->_queue;
+    }
+
+    /**
+     * Set the queue object, to re-establish a live connection
+     * to the queue for a Message that has been de-serialized.
+     *
+     * @param  Zend_Queue $queue
+     * @return boolean
+     */
+    public function setQueue(Zend_Queue $queue)
+    {
+        $queueClass        = get_class($queue);
+        $this->_queue      = $queue;
+        $this->_queueClass = $queueClass;
+        $this->_connected  = true;
+        return true;
+    }
+
+    /**
+     * Query the class name of the Queue object for which this
+     * Message was created.
+     *
+     * @return string
+     */
+    public function getQueueClass()
+    {
+        return $this->_queueClass;
+    }
+
+    /**
+     * Returns the column/value data as an array.
+     *
+     * @return array
+     */
+    public function toArray()
+    {
+        return $this->_data;
+    }
+
+    /**
+     * Sets all data in the row from an array.
+     *
+     * @param  array $data
+     * @return Zend_Queue_Message Provides a fluent interface
+     */
+    public function setFromArray(array $data)
+    {
+        foreach ($data as $columnName => $value) {
+            $this->$columnName = $value;
+        }
+
+        return $this;
+    }
+}

+ 285 - 0
library/Zend/Queue/Message/Iterator.php

@@ -0,0 +1,285 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Message
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Message
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Queue_Message_Iterator implements Iterator, Countable
+{
+    /**
+     * The data for the queue message
+     *
+     * @var array
+     */
+    protected $_data = array();
+
+     /**
+     * Connected is true if we have a reference to a live
+     * Zend_Queue_Adapter_AdapterInterface object.
+     * This is false after the Message has been deserialized.
+     *
+     * @var boolean
+     */
+    protected $_connected = true;
+
+    /**
+     * Zend_Queue_Adapter_AdapterInterface parent class or instance
+     *
+     * @var Zend_Queue_Adapter_AdapterInterface
+     */
+    protected $_queue = null;
+
+    /**
+     * Name of the class of the Zend_Queue_Adapter_AdapterInterface object.
+     *
+     * @var string
+     */
+    protected $_queueClass = null;
+
+    /**
+     * Zend_Queue_Message class name
+     *
+     * @var string
+     */
+    protected $_messageClass = 'Zend_Queue_Message';
+
+     /**
+     * Iterator pointer.
+     *
+     * @var integer
+     */
+    protected $_pointer = 0;
+
+    /**
+     * Constructor
+     *
+     * @param  array $options ('queue', 'messageClass', 'data'=>array());
+     * @return void
+     */
+    public function __construct(array $options = array())
+    {
+        if (isset($options['queue'])) {
+            $this->_queue      = $options['queue'];
+            $this->_queueClass = get_class($this->_queue);
+            $this->_connected  = true;
+        } else {
+            $this->_connected = false;
+        }
+        if (isset($options['messageClass'])) {
+            $this->_messageClass = $options['messageClass'];
+        }
+
+        if (!is_array($options['data'])) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('array optionsuration must have $options[\'data\'] = array');
+        }
+
+        // load the message class
+        $classname = $this->_messageClass;
+        if (!class_exists($classname)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($classname);
+        }
+
+        // for each of the messages
+        foreach ($options['data'] as $data) {
+            // construct the message parameters
+            $message = array('data' => $data);
+
+            // If queue has not been set, then use the default.
+            if (empty($message['queue'])) {
+                $message['queue'] = $this->_queue;
+            }
+
+            // construct the message and add it to _data[];
+            $this->_data[] = new $classname($message);
+        }
+    }
+
+    /**
+     * Store queue and data in serialized object
+     *
+     * @return array
+     */
+    public function __sleep()
+    {
+        return array('_data', '_queueClass', '_messageClass', '_pointer');
+    }
+
+    /**
+     * Setup to do on wakeup.
+     * A de-serialized Message should not be assumed to have access to a live
+     * queue connection, so set _connected = false.
+     *
+     * @return void
+     */
+    public function __wakeup()
+    {
+        $this->_connected = false;
+    }
+
+    /**
+     * Returns all data as an array.
+     *
+     * Used for debugging.
+     *
+     * @return array
+     */
+    public function toArray()
+    {
+        // @todo This works only if we have iterated through
+        // the result set once to instantiate the messages.
+        foreach ($this->_data as $i => $message) {
+            $this->_data[$i] = $message->toArray();
+        }
+        return $this->_data;
+    }
+
+    /**
+     * Returns the queue object, or null if this is disconnected message set
+     *
+     * @return Zend_Queue|null
+     */
+    public function getQueue()
+    {
+        return $this->_queue;
+    }
+
+    /**
+     * Set the queue object, to re-establish a live connection
+     * to the queue for a Message that has been de-serialized.
+     *
+     * @param  Zend_Queue_Adapter_AdapterInterface $queue
+     * @return boolean
+     * @throws Zend_Queue_Exception
+     */
+    public function setQueue(Zend_Queue $queue)
+    {
+        $this->_queue     = $queue;
+        $this->_connected = false;
+
+        // @todo This works only if we have iterated through
+        // the result set once to instantiate the rows.
+        foreach ($this->_data as $i => $message) {
+            $this->_connected = $this->_connected || $message->setQueue($queue);
+        }
+
+        return $this->_connected;
+    }
+
+    /**
+     * Query the class name of the Queue object for which this
+     * Message was created.
+     *
+     * @return string
+     */
+    public function getQueueClass()
+    {
+        return $this->_queueClass;
+    }
+
+    /*
+     * Iterator implementation
+     */
+
+    /**
+     * Rewind the Iterator to the first element.
+     * Similar to the reset() function for arrays in PHP.
+     * Required by interface Iterator.
+     *
+     * @return void
+     */
+    public function rewind()
+    {
+        $this->_pointer = 0;
+    }
+
+    /**
+     * Return the current element.
+     * Similar to the current() function for arrays in PHP
+     * Required by interface Iterator.
+     *
+     * @return Zend_Queue_Message current element from the collection
+     */
+    public function current()
+    {
+        return (($this->valid() === false) 
+            ? null 
+            : $this->_data[$this->_pointer]); // return the messages object
+    }
+
+    /**
+     * Return the identifying key of the current element.
+     * Similar to the key() function for arrays in PHP.
+     * Required by interface Iterator.
+     *
+     * @return integer
+     */
+    public function key()
+    {
+        return $this->_pointer;
+    }
+
+    /**
+     * Move forward to next element.
+     * Similar to the next() function for arrays in PHP.
+     * Required by interface Iterator.
+     *
+     * @return void
+     */
+    public function next()
+    {
+        ++$this->_pointer;
+    }
+
+    /**
+     * Check if there is a current element after calls to rewind() or next().
+     * Used to check if we've iterated to the end of the collection.
+     * Required by interface Iterator.
+     *
+     * @return bool False if there's nothing more to iterate over
+     */
+    public function valid()
+    {
+        return $this->_pointer < count($this);
+    }
+
+    /*
+     * Countable Implementation
+     */
+
+    /**
+     * Returns the number of elements in the collection.
+     *
+     * Implements Countable::count()
+     *
+     * @return integer
+     */
+    public function count()
+    {
+        return count($this->_data);
+    }
+}

+ 173 - 0
library/Zend/Queue/Stomp/Client.php

@@ -0,0 +1,173 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Stomp.php 14504 2009-03-27 05:32:18Z danlo $
+ */
+
+/**
+ * The Stomp client interacts with a Stomp server.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Stomp
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Queue_Stomp_Client
+{
+    /**
+     * Array of $client Zend_Queue_Stomp_Client_Interface
+     *
+     * @var array
+     */
+    protected $_connection;
+
+    /**
+     * Add a server to connections
+     *
+     * @param string scheme
+     * @param string host
+     * @param integer port
+     */
+    public function __construct(
+        $scheme = null, $host = null, $port = null, 
+        $connectionClass = 'Zend_Queue_Stomp_Client_Connection', 
+        $frameClass = 'Zend_Queue_Stomp_Frame'
+    ) {
+        if (($scheme !== null) 
+            && ($host !== null) 
+            && ($port !== null)
+        ) {
+            $this->addConnection($scheme, $host, $port, $connectionClass);
+            $this->getConnection()->setFrameClass($frameClass);
+        }
+    }
+
+    /**
+     * Shutdown
+     * 
+     * @return void
+     */
+    public function __destruct()
+    {
+        if ($this->getConnection()) {
+            $this->getConnection()->close(true);
+        }
+    }
+
+    /**
+     * Add a connection to this client.
+     *
+     * Attempts to add this class to the client.  Returns a boolean value 
+     * indicating success of operation.
+     *
+     * You cannot add more than 1 connection to the client at this time.
+     *
+     * @param string  $scheme ['tcp', 'udp']
+     * @param string  host
+     * @param integer port
+     * @param string  class - create a connection with this class; class must support Zend_Queue_Stomp_Client_ConnectionInterface
+     * @return boolean
+     */
+    public function addConnection($scheme, $host, $port, $class = 'Zend_Queue_Stomp_Client_Connection')
+    {
+        if (!class_exists($class)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($class);
+        }
+
+        $connection = new $class();
+
+        if ($connection->open($scheme, $host, $port)) {
+            $this->setConnection($connection);
+            return true;
+        }
+
+        $connection->close();
+        return false;
+    }
+
+    /**
+     * Set client connection
+     * 
+     * @param Zend_Queue_Stomp_Client_ConnectionInterface $connection 
+     * @return void
+     */
+    public function setConnection(Zend_Queue_Stomp_Client_ConnectionInterface $connection)
+    {
+        $this->_connection = $connection;
+        return $this;
+    }
+
+    /**
+     * Get client connection
+     * 
+     * @return Zend_Queue_Stomp_Client_ConnectionInterface|null
+     */
+    public function getConnection()
+    {
+        return $this->_connection;
+    }
+
+    /**
+     * Send a stomp frame
+     *
+     * Returns true if the frame was successfully sent.
+     *
+     * @param Zend_Queue_Stomp_FrameInterface $frame
+     * @return boolean
+     */
+    public function send(Zend_Queue_Stomp_FrameInterface $frame)
+    {
+        $this->getConnection()->write($frame);
+        return $this;
+    }
+
+    /**
+     * Receive a frame
+     *
+     * Returns a frame or false if none were to be read.
+     *
+     * @return Zend_Queue_Stomp_FrameInterface|boolean
+     */
+    public function receive()
+    {
+        return $this->getConnection()->read();
+    }
+
+    /**
+     * canRead()
+     *
+     * @return boolean
+     */
+    public function canRead()
+    {
+        return $this->getConnection()->canRead();
+    }
+
+    /**
+     * creates a frame class
+     *
+     * @return Zend_Queue_Stomp_FrameInterface
+     */
+    public function createFrame()
+    {
+        return $this->getConnection()->createFrame();
+    }
+}

+ 274 - 0
library/Zend/Queue/Stomp/Client/Connection.php

@@ -0,0 +1,274 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Stomp.php 14504 2009-03-27 05:32:18Z danlo $
+ */
+
+/**
+ * @see Zend_Queue_Stomp_Client_ConnectionInterface
+ */
+require_once 'Zend/Queue/Stomp/Client/ConnectionInterface.php';
+
+/**
+ * The Stomp client interacts with a Stomp server.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Queue_Stomp_Client_Connection
+    implements Zend_Queue_Stomp_Client_ConnectionInterface
+{
+    const READ_TIMEOUT_DEFAULT_USEC = 0; // 0 microseconds
+    const READ_TIMEOUT_DEFAULT_SEC = 5; // 5 seconds
+
+    /**
+     * Connection options
+     * @var array
+     */
+    protected $_options;
+
+    /**
+     * tcp/udp socket
+     *
+     * @var resource
+     */
+    protected $_socket = false;
+
+    /**
+     * open() opens a socket to the Stomp server
+     *
+     * @param  array $options ('scheme', 'host', 'port')
+     * @param  string $scheme
+     * @param  string $host
+     * @param  int $port
+     * @param  array $options Accepts "timeout_sec" and "timeout_usec" keys
+     * @return true;
+     * @throws Zend_Queue_Exception
+     */
+    public function open($scheme, $host, $port, array $options = array())
+    {
+        $str = $scheme . '://' . $host;
+        $this->_socket = fsockopen($str, $port, $errno, $errstr);
+
+        if ($this->_socket === false) {
+            // aparently there is some reason that fsockopen will return false
+            // but it normally throws an error.
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception("Unable to connect to $str; error = $errstr ( errno = $errno )");
+        }
+
+        stream_set_blocking($this->_socket, 0); // non blocking
+
+        if (!isset($options['timeout_sec'])) {
+            $options['timeout_sec'] = self::READ_TIMEOUT_DEFAULT_SEC;
+        }
+        if (! isset($options['timeout_usec'])) {
+            $options['timeout_usec'] = self::READ_TIMEOUT_DEFAULT_USEC;
+        }
+
+        $this->_options = $options;
+
+        return true;
+    }
+
+    /**
+     * Close the socket explicitly when destructed
+     *
+     * @return void
+     */
+    public function __destruct()
+    {
+    }
+
+    /**
+     * Close connection
+     * 
+     * @param  boolean $destructor 
+     * @return void
+     */
+    public function close($destructor = false)
+    {
+        // Gracefully disconnect
+        if (!$destructor) {
+            $frame = $this->createFrame();
+            $frame->command('DISCONNECT');
+            $this->write($frame->toFrame());
+        }
+
+        if (is_resource($this->_socket)) {
+            fclose($this->_socket);
+        }
+
+        $this->_socket = null;
+    }
+
+    /**
+     * Check whether we are connected to the server
+     *
+     * @return true
+     * @throws Zend_Queue_Exception
+     */
+    public function ping()
+    {
+        if (!is_resource($this->_socket)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('Not connected to Stomp server');
+        }
+        return true;
+    }
+
+    /**
+     * Write a frame to the stomp server
+     *
+     * @example $response = $client->write($frame)->read();
+     *
+     * @param Zend_Queue_Stom_FrameInterface $frame
+     * @return $this
+     */
+    public function write(Zend_Queue_Stomp_FrameInterface $frame)
+    {
+        $this->ping();
+        $output = $frame->toFrame();
+
+        $bytes = fwrite($this->_socket, $output, strlen($output));
+        if ($bytes === false || $bytes == 0) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('No bytes written');
+        }
+
+        return $this;
+    }
+
+    /**
+     * Tests the socket to see if there is data for us
+     *
+     * @return boolean
+     */
+    public function canRead()
+    {
+        $read   = array($this->_socket);
+        $write  = null;
+        $except = null;
+
+        return stream_select(
+            $read, 
+            $write, 
+            $except, 
+            $this->_options['timeout_sec'], 
+            $this->_options['timeout_usec']
+        ) == 1;
+        // see http://us.php.net/manual/en/function.stream-select.php
+    }
+
+    /**
+     * Reads in a frame from the socket or returns false.
+     *
+     * @return Zend_Queue_Stomp_FrameInterface|false
+     * @throws Zend_Queue_Exception
+     */
+    public function read()
+    {
+        $this->ping();
+
+        $response = '';
+        $prev     = '';
+
+        // while not end of file.
+        while (!feof($this->_socket)) {
+            // read in one character until "\0\n" is found
+            $data = fread($this->_socket, 1);
+
+            // check to make sure that the connection is not lost.
+            if ($data === false) {
+                require_once 'Zend/Queue/Exception.php';
+                throw new Zend_Queue_Exception('Connection lost');
+            }
+
+            // append last character read to $response
+            $response .= $data;
+
+            // is this \0 (prev) \n (data)? END_OF_FRAME
+            if (ord($data) == 10 && ord($prev) == 0) {
+                break;
+            }
+            $prev = $data;
+        }
+
+        if ($response === '') {
+            return false;
+        }
+
+        $frame = $this->createFrame();
+        $frame->fromFrame($response);
+        return $frame;
+    }
+
+    /**
+     * Set the frameClass to be used
+     *
+     * This must be a Zend_Queue_Stomp_FrameInterface.
+     *
+     * @param  string $classname - class is an instance of Zend_Queue_Stomp_FrameInterface
+     * @return $this;
+     */
+    public function setFrameClass($classname)
+    {
+        $this->_options['frameClass'] = $classname;
+        return $this;
+    }
+
+    /**
+     * Get the frameClass
+     *
+     * @return string
+     */
+    public function getFrameClass()
+    {
+        return isset($this->_options['frameClass'])
+            ? $this->_options['frameClass']
+            : 'Zend_Queue_Stomp_Frame';
+    }
+
+    /**
+     * Create an empty frame
+     *
+     * @return Zend_Queue_Stomp_FrameInterface
+     */
+    public function createFrame()
+    {
+        $class = $this->getFrameClass();
+
+        if (!class_exists($class)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($class);
+        }
+
+        $frame = new $class();
+
+        if (!$frame instanceof Zend_Queue_Stomp_FrameInterface) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('Invalid Frame class provided; must implement Zend_Queue_Stomp_FrameInterface');
+        }
+
+        return $frame;
+    }
+}

+ 103 - 0
library/Zend/Queue/Stomp/Client/ConnectionInterface.php

@@ -0,0 +1,103 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Stomp.php 14504 2009-03-27 05:32:18Z danlo $
+ */
+
+/**
+ * The Stomp client interacts with a Stomp server.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+interface Zend_Queue_Stomp_Client_ConnectionInterface
+{
+    /**
+     * @param  string  $scheme ['tcp', 'udp']
+     * @param  string  host
+     * @param  integer port
+     * @param  string  class - create a connection with this class; class must support Zend_Queue_Stomp_Client_Connection_Interface
+     * @return boolean
+     */
+    public function open($scheme, $host, $port);
+
+    /**
+     * @param  boolean $destructor 
+     * @return void
+     */
+    public function close($destructor = false);
+
+    /**
+     * Check whether we are connected to the server
+     *
+     * @return true
+     * @throws Zend_Queue_Exception
+     */
+    public function ping();
+
+    /**
+     * write a frame to the stomp server
+     *
+     * @example $response = $client->write($frame)->read();
+     *
+     * @param  Zend_Queue_Stomp_FrameInterface $frame
+     * @return $this
+     */
+    public function write(Zend_Queue_Stomp_FrameInterface $frame);
+
+    /**
+     * tests the socket to see if there is data for us
+     */
+    public function canRead();
+
+    /**
+     * reads in a frame from the socket or returns false.
+     *
+     * @return Zend_Queue_Stomp_Frame|false
+     * @throws Zend_Queue_Exception
+     */
+    public function read();
+
+    /**
+     * Set the frame class to be used
+     *
+     * This must be a Zend_Queue_Stomp_FrameInterface.
+     *
+     * @param  string $class
+     * @return Zend_Queue_Stomp_Client_ConnectionInterface;
+     */
+    public function setFrameClass($class);
+
+    /**
+     * Get the frameClass
+     *
+     * @return string
+     */
+    public function getFrameClass();
+
+    /**
+     * create an empty frame
+     *
+     * @return Zend_Queue_Stomp_FrameInterface class
+     */
+    public function createFrame();
+}

+ 361 - 0
library/Zend/Queue/Stomp/Frame.php

@@ -0,0 +1,361 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Stomp.php 14504 2009-03-27 05:32:18Z danlo $
+ */
+
+/**
+ * This class represents a Stomp Frame
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+require_once 'Zend/Queue/Stomp/FrameInterface.php';
+
+class Zend_Queue_Stomp_Frame
+    implements Zend_Queue_Stomp_FrameInterface
+{
+    const END_OF_FRAME   = "\x00\n";
+    const CONTENT_LENGTH = 'content-length';
+    const EOL            = "\n";
+
+    /**
+     * Headers for the frame
+     *
+     * @var array
+     */
+    protected $_headers = array();
+
+    /**
+     * The command for the frame
+     *
+     * @var string
+     */
+    protected $_command = null;
+
+    /**
+     * The body of the frame
+     *
+     * @var string
+     */
+    protected $_body = null;
+
+    /**
+     * Do the content-length automatically?
+     */
+    protected $_autoContentLength = null;
+
+    /**
+     * Constructor
+     */
+    public function __construct()
+    {
+        $this->setHeaders(array());
+        $this->setBody(null);
+        $this->setCommand(null);
+        $this->setAutoContentLength(true);
+    }
+
+    /**
+     * get the status of the auto content length
+     *
+     * If AutoContentLength is true this code will automatically put the
+     * content-length header in, even if it is already set by the user.
+     *
+     * This is done to make the message sending more reliable.
+     *
+     * @return boolean
+     */
+    public function getAutoContentLength()
+    {
+        return $this->_autoContentLength;
+    }
+
+    /**
+     * setAutoContentLength()
+     *
+     * Set the value on or off.
+     *
+     * @param boolean $auto
+     * @return $this;
+     * @throws Zend_Queue_Exception
+     */
+    public function setAutoContentLength($auto)
+    {
+        if (!is_bool($auto)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$auto is not a boolean');
+        }
+
+        $this->_autoContentLength = $auto;
+        return $this;
+    }
+
+    /**
+     * Get the headers
+     *
+     * @return array
+     */
+    public function getHeaders()
+    {
+        return $this->_headers;
+    }
+
+    /**
+     * Set the headers
+     *
+     * Throws an exception if the array values are not strings.
+     *
+     * @param array $headers
+     * @return $this
+     * @throws Zend_Queue_Exception
+     */
+    public function setHeaders(array $headers)
+    {
+        foreach ($headers as $header => $value) {
+            $this->setHeader($header, $value);
+        }
+
+        return $this;
+    }
+
+    /**
+     * Sets a value for a header
+     *
+     * @param  string $header
+     * @param  string $value
+     * @return Zend_Queue_Stomp_Frame
+     * @throws Zend_Queue_Exception
+     */
+    public function setHeader($header, $value) {
+        if (!is_string($header)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$header is not a string: ' . print_r($header, true));
+        }
+
+        if (!is_scalar($value)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$value is not a string: ' . print_r($value, true));
+        }
+
+        $this->_headers[$header] = $value;
+        return $this;
+    }
+
+
+    /**
+     * Returns a value for a header
+     *
+     * Returns false if the header does not exist.
+     *
+     * @param  string $header
+     * @return string|false
+     * @throws Zend_Queue_Exception
+     */
+    public function getHeader($header)
+    {
+        if (!is_string($header)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$header is not a string');
+        }
+
+        return isset($this->_headers[$header])
+            ? $this->_headers[$header]
+            : false;
+    }
+
+    /**
+     * Return the body for this frame
+     *
+     * Returns false if the body does not exist
+     *
+     * @return false|string
+     */
+    public function getBody()
+    {
+        return is_null($this->_body)
+            ? false
+            : $this->_body;
+    }
+
+    /**
+     * Set the body for this frame
+     *
+     * Set to null for no body.
+     *
+     * @param  string|null $body
+     * @return Zend_Queue_Stomp_Frame
+     * @throws Zend_Queue_Exception
+     */
+    public function setBody($body)
+    {
+        if (!is_string($body) && !is_null($body)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$body is not a string or null');
+        }
+
+        $this->_body = $body;
+        return $this;
+    }
+
+    /**
+     * Return the command for this frame
+     *
+     * Return false if the command does not exist
+     *
+     * @return string|false
+     */
+    public function getCommand()
+    {
+        return is_null($this->_command)
+            ? false
+            : $this->_command;
+    }
+
+    /**
+     * Set the body for this frame
+     *
+     * @param  string|null
+     * @return Zend_Queue_Stomp_Frame
+     * @throws Zend_Queue_Exception
+     */
+    public function setCommand($command)
+    {
+        if (!is_string($command) && !is_null($command)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$command is not a string or null');
+        }
+
+        $this->_command = $command;
+        return $this;
+    }
+
+    /**
+     * Takes the current parameters and returns a Stomp Frame
+     *
+     * @return string
+     * @throws Zend_Queue_Exception
+     */
+    public function toFrame()
+    {
+        if ($this->getCommand() === false) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('You must set the command');
+        }
+
+        $command = $this->getCommand();
+        $headers = $this->getHeaders();
+        $body    = $this->getBody();
+        $frame   = '';
+
+        // add a content-length to the SEND command.
+        // @see http://stomp.codehaus.org/Protocol
+        if ($this->getAutoContentLength()) {
+            $headers[self::CONTENT_LENGTH] = strlen($this->getBody());
+        }
+
+        // Command
+        $frame = $command . self::EOL;
+
+        // Headers
+        foreach ($headers as $key=>$value) {
+            $frame .= $key . ': ' . $value . self::EOL;
+        }
+
+        // Seperator
+        $frame .= self::EOL; // blank line required by protocol
+
+        // add the body if any
+        if ($body !== false) {
+            $frame .= $body;
+        }
+        $frame .= self::END_OF_FRAME;
+
+        return $frame;
+    }
+
+    /**
+     * @see toFrame()
+     * @return string
+     */
+    public function __toString()
+    {
+        try {
+            $return = $this->toFrame();
+        } catch (Zend_Queue_Exception $e) {
+            $return = '';
+        }
+        return $return;
+    }
+
+    /**
+     * Accepts a frame and deconstructs the frame into its component parts
+     *
+     * @param  string $frame - a stomp frame
+     * @return $this
+     */
+    public function fromFrame($frame)
+    {
+        if (!is_string($frame)) {
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$frame is not a string');
+        }
+
+        $headers = array();
+        $body    = null;
+        $command = false;
+        $header  = '';
+
+        // separate the headers and the body
+        $match = self::EOL . self::EOL;
+        if (preg_match('/' . $match . '/', $frame)) {
+            list ($header, $body) = explode($match, $frame, 2);
+        } else {
+            $header = $frame;
+        }
+
+        // blow up headers
+        $headers = explode(self::EOL, $header);
+        unset($header);
+
+        // get the command (first line)
+        $this->setCommand(array_shift($headers));
+
+        // set each of the headers.
+        foreach ($headers as $header) {
+            if (strpos($header, ':') > 0) {
+                list($name, $value) = explode(':', $header, 2);
+                $this->setHeader($name, $value);
+            }
+        }
+
+        // crop the body if content-length is present
+        if ($this->getHeader(self::CONTENT_LENGTH) !== false ) {
+            $length = (int) $this->getHeader(self::CONTENT_LENGTH);
+            $body   = substr($body, 0, $length);
+        }
+
+        $this->setBody($body);
+        return $this;
+    }
+}

+ 154 - 0
library/Zend/Queue/Stomp/FrameInterface.php

@@ -0,0 +1,154 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Stomp.php 14504 2009-03-27 05:32:18Z danlo $
+ */
+
+/**
+ * This class represents a Stomp Frame Interface
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Adapter
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+interface Zend_Queue_Stomp_FrameInterface
+{
+    /**
+     * Get the status of the auto content length
+     *
+     * If AutoContentLength is true this code will automatically put the
+     * content-length header in, even if it is already set by the user.
+     *
+     * This is done to make the message sending more reliable.
+     *
+     * @return boolean
+     */
+    public function getAutoContentLength();
+
+    /**
+     * setAutoContentLength()
+     *
+     * Set the value on or off.
+     *
+     * @param boolean $auto
+     * @return $this;
+     * @throws Zend_Queue_Exception
+     */
+    public function setAutoContentLength($auto);
+
+    /**
+     * Get the headers
+     *
+     * @return array
+     */
+    public function getHeaders();
+
+    /**
+     * Set the headers
+     *
+     * Throws an exception if the array values are not strings.
+     *
+     * @param array $headers
+     * @return $this
+     * @throws Zend_Queue_Exception
+     */
+    public function setHeaders(array $headers);
+
+    /**
+     * Returns a value for a header
+     * returns false if the header does not exist
+     *
+     * @param string $header
+     * @return $string
+     * @throws Zend_Queue_Exception
+     */
+    public function getHeader($header);
+
+    /**
+     * Returns a value for a header
+     * returns false if the header does not exist
+     *
+     * @param string $header
+     * @param string $value
+     * @return $this
+     * @throws Zend_Queue_Exception
+     */
+    public function setHeader($header, $value);
+
+    /**
+     * Return the body for this frame
+     * returns false if the body does not exist
+     *
+     * @return $this
+     */
+    public function getBody();
+
+    /**
+     * Set the body for this frame
+     * returns false if the body does not exist
+     *
+     * Set to null for no body.
+     *
+     * @param string|null $body
+     * @return $this
+     * @throws Zend_Queue_Exception
+     */
+    public function setBody($body);
+
+    /**
+     * Return the command for this frame
+     * return false if the command does not exist
+     *
+     * @return $this
+     */
+    public function getCommand();
+
+    /**
+     * Set the body for this frame
+     * returns false if the body does not exist
+     *
+     * @return $this
+     * @throws Zend_Queue_Exception
+     */
+    public function setCommand($command);
+
+
+    /**
+     * Takes the current parameters and returns a Stomp Frame
+     *
+     * @throws Zend_Queue_Exception
+     * @return string
+     */
+    public function toFrame();
+
+    /**
+     * @see toFrame()
+     */
+    public function __toString();
+
+    /**
+     * Accepts a frame and deconstructs the frame into its' component parts
+     *
+     * @param string $frame - a stomp frame
+     * @return $this
+     */
+    public function fromFrame($frame);
+}

+ 436 - 0
library/Zend/Service/Amazon/Sqs.php

@@ -0,0 +1,436 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Service
+ * @subpackage Amazon_Sqs
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+/**
+ * @see Zend_Service_Amazon_Abstract
+ */
+require_once 'Zend/Service/Amazon/Abstract.php';
+
+/**
+ * @see Zend_Crypt_Hmac
+ */
+require_once 'Zend/Crypt/Hmac.php';
+
+/**
+ * Class for connecting to the Amazon Simple Queue Service (SQS)
+ *
+ * @category   Zend
+ * @package    Service
+ * @subpackage Amazon_Sqs
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @see        http://aws.amazon.com/sqs/ Amazon Simple Queue Service
+ */
+class Zend_Service_Amazon_Sqs extends Zend_Service_Amazon_Abstract
+{
+    /**
+     * Default timeout for createQueue() function
+     */
+    const CREATE_TIMEOUT_DEFAULT = 30;
+
+    /**
+     * HTTP end point for the Amazon SQS service
+     */
+    protected $_sqsEndpoint = 'queue.amazonaws.com';
+
+    /**
+     * The API version to use
+     */
+    protected $_sqsApiVersion = '2009-02-01';
+
+    /**
+     * Signature Version
+     */
+    protected $_sqsSignatureVersion = '2';
+
+    /**
+     * Signature Encoding Method
+     */
+    protected $_sqsSignatureMethod = 'HmacSHA256';
+
+    /**
+     * Constructor
+     *
+     * @param string $accessKey
+     * @param string $secretKey
+     * @param string $region
+     */
+    public function __construct($accessKey = null, $secretKey = null, $region = null)
+    {
+        parent::__construct($accessKey, $secretKey, $region);
+    }
+
+    /**
+     * Create a new queue
+     *
+     * Visibility timeout is how long a message is left in the queue "invisible"
+     * to other readers.  If the message is acknowleged (deleted) before the
+     * timeout, then the message is deleted.  However, if the timeout expires
+     * then the message will be made available to other queue readers.
+     *
+     * @param  string  $queue_name queue name
+     * @param  integer $timeout    default visibility timeout
+     * @return string|boolean
+     * @throws Zend_Service_Amazon_Sqs_Exception
+     */
+    public function create($queue_name, $timeout = null)
+    {
+        $params = array();
+        $params['QueueName'] = $queue_name;
+        $timeout = ($timeout === null) ? self::CREATE_TIMEOUT_DEFAULT : (int)$timeout;
+        $params['DefaultVisibilityTimeout'] = $timeout;
+
+        $retry_count = 0;
+
+        do {
+            $retry  = false;
+            $result = $this->_makeRequest(null, 'CreateQueue', $params);
+
+            if ($result->CreateQueueResult->QueueUrl === null) {
+                if ($result->Error->Code == 'AWS.SimpleQueueService.QueueNameExists') {
+                    return false;
+                } elseif ($result->Error->Code == 'AWS.SimpleQueueService.QueueDeletedRecently') {
+                    // Must sleep for 60 seconds, then try re-creating the queue
+                    sleep(60);
+                    $retry = true;
+                    $retry_count++;
+                } else {
+                    require_once 'Zend/Service/Amazon/Sqs/Exception.php';
+                    throw new Zend_Service_Amazon_Sqs_Exception($result->Error->Code);
+                }
+            } else {
+                return (string) $result->CreateQueueResult->QueueUrl;
+            }
+
+        } while ($retry);
+
+        return false;
+    }
+
+    /**
+     * Delete a queue and all of it's messages
+     *
+     * Returns false if the queue is not found, true if the queue exists
+     *
+     * @param  string  $queue_url queue URL
+     * @return boolean
+     * @throws Zend_Service_Amazon_Sqs_Exception
+     */
+    public function delete($queue_url)
+    {
+        $result = $this->_makeRequest($queue_url, 'DeleteQueue');
+
+        if ($result->Error->Code !== null) {
+            require_once 'Zend/Service/Amazon/Sqs/Exception.php';
+            throw new Zend_Service_Amazon_Sqs_Exception($result->Error->Code);
+        }
+
+        return true;
+    }
+
+    /**
+     * Get an array of all available queues
+     *
+     * @return array
+     * @throws Zend_Service_Amazon_Sqs_Exception
+     */
+    public function getQueues()
+    {
+        $result = $this->_makeRequest(null, 'ListQueues');
+
+        if ($result->ListQueuesResult->QueueUrl === null) {
+            require_once 'Zend/Service/Amazon/Sqs/Exception.php';
+            throw new Zend_Service_Amazon_Sqs_Exception($result->Error->Code);
+        }
+
+        $queues = array();
+        foreach ($result->ListQueuesResult->QueueUrl as $queue_url) {
+            $queues[] = (string)$queue_url;
+        }
+
+        return $queues;
+    }
+
+    /**
+     * Return the approximate number of messages in the queue
+     *
+     * @param  string  $queue_url Queue URL
+     * @return integer
+     * @throws Zend_Service_Amazon_Sqs_Exception
+     */
+    public function count($queue_url)
+    {
+        return (int)$this->getAttribute($queue_url, 'ApproximateNumberOfMessages');
+    }
+
+    /**
+     * Send a message to the queue
+     *
+     * @param  string $queue_url Queue URL
+     * @param  string $message   Message to send to the queue
+     * @return string            Message ID
+     * @throws Zend_Service_Amazon_Sqs_Exception
+     */
+    public function send($queue_url, $message)
+    {
+        $params = array();
+        $params['MessageBody'] = urlencode($message);
+
+        $checksum = md5($params['MessageBody']);
+
+        $result = $this->_makeRequest($queue_url, 'SendMessage', $params);
+
+        if ($result->SendMessageResult->MessageId === null) {
+            require_once 'Zend/Service/Amazon/Sqs/Exception.php';
+            throw new Zend_Service_Amazon_Sqs_Exception($result->Error->Code);
+        } else if ((string) $result->SendMessageResult->MD5OfMessageBody != $checksum) {
+            require_once 'Zend/Service/Amazon/Sqs/Exception.php';
+            throw new Zend_Service_Amazon_Sqs_Exception('MD5 of body does not match message sent');
+        }
+
+        return (string) $result->SendMessageResult->MessageId;
+    }
+
+    /**
+     * Get messages in the queue
+     *
+     * @param  string  $queue_url    Queue name
+     * @param  integer $max_messages Maximum number of messages to return
+     * @param  integer $timeout      Visibility timeout for these messages
+     * @return array
+     * @throws Zend_Service_Amazon_Sqs_Exception
+     */
+    public function receive($queue_url, $max_messages = null, $timeout = null)
+    {
+        $params = array();
+
+        // If not set, the visibility timeout on the queue is used
+        if ($timeout !== null) {
+            $params['VisibilityTimeout'] = (int)$timeout;
+        }
+
+        // SQS will default to only returning one message
+        if ($max_messages !== null) {
+            $params['MaxNumberOfMessages'] = (int)$max_messages;
+        }
+
+        $result = $this->_makeRequest($queue_url, 'ReceiveMessage', $params);
+
+        if ($result->ReceiveMessageResult->Message === null) {
+            require_once 'Zend/Service/Amazon/Sqs/Exception.php';
+            throw new Zend_Service_Amazon_Sqs_Exception($result->Error->Code);
+        }
+
+        $data = array();
+        foreach ($result->ReceiveMessageResult->Message as $message) {
+            $data[] = array(
+                'message_id' => (string)$message->MessageId,
+                'handle'     => (string)$message->ReceiptHandle,
+                'md5'        => (string)$message->MD5OfBody,
+                'body'       => urldecode((string)$message->Body),
+            );
+        }
+
+        return $data;
+    }
+
+    /**
+     * Delete a message from the queue
+     *
+     * Returns true if the message is deleted, false if the deletion is
+     * unsuccessful.
+     *
+     * @param  string $queue_url  Queue URL
+     * @param  string $handle     Message handle as returned by SQS
+     * @return boolean
+     * @throws Zend_Service_Amazon_Sqs_Exception
+     */
+    public function deleteMessage($queue_url, $handle)
+    {
+        $params = array();
+        $params['ReceiptHandle'] = (string)$handle;
+
+        $result = $this->_makeRequest($queue_url, 'DeleteMessage', $params);
+
+        if ($result->Error->Code !== null) {
+            return false;
+        }
+
+        // Will always return true unless ReceiptHandle is malformed
+        return true;
+    }
+
+    /**
+     * Get the attributes for the queue
+     *
+     * @param  string $queue_url  Queue URL
+     * @param  string $attribute
+     * @return string
+     * @throws Zend_Service_Amazon_Sqs_Exception
+     */
+    public function getAttribute($queue_url, $attribute = 'All')
+    {
+        $params = array();
+        $params['AttributeName'] = $attribute;
+
+        $result = $this->_makeRequest($queue_url, 'GetQueueAttributes', $params);
+
+        if ($result->GetQueueAttributesResult->Attribute === null) {
+            require_once 'Zend/Service/Amazon/Sqs/Exception.php';
+            throw new Zend_Service_Amazon_Sqs_Exception($result->Error->Code);
+        }
+
+        return (string) $result->GetQueueAttributesResult->Attribute->Value;
+    }
+
+    /**
+     * Make a request to Amazon SQS
+     *
+     * @param  string           $queue  Queue Name
+     * @param  string           $action SQS action
+     * @param  array            $params
+     * @return SimpleXMLElement
+     */
+    private function _makeRequest($queue_url, $action, $params = array())
+    {
+        $params['Action'] = $action;
+        $params = $this->addRequiredParameters($queue_url, $params);
+
+        if ($queue_url === null) {
+            $queue_url = '/';
+        }
+
+        $client = self::getHttpClient();
+
+        switch ($action) {
+            case 'ListQueues':
+            case 'CreateQueue':
+                $client->setUri('http://'.$this->_sqsEndpoint);
+                break;
+            default:
+                $client->setUri($queue_url);
+                break;
+        }
+
+        $retry_count = 0;
+
+        do {
+            $retry = false;
+
+            $client->resetParameters();
+            $client->setParameterGet($params);
+
+            $response = $client->request('GET');
+
+            $response_code = $response->getStatus();
+
+            // Some 5xx errors are expected, so retry automatically
+            if ($response_code >= 500 && $response_code < 600 && $retry_count <= 5) {
+                $retry = true;
+                $retry_count++;
+                sleep($retry_count / 4 * $retry_count);
+            }
+        } while ($retry);
+
+        unset($client);
+
+        return new SimpleXMLElement($response->getBody());
+    }
+
+    /**
+     * Adds required authentication and version parameters to an array of
+     * parameters
+     *
+     * The required parameters are:
+     * - AWSAccessKey
+     * - SignatureVersion
+     * - Timestamp
+     * - Version and
+     * - Signature
+     *
+     * If a required parameter is already set in the <tt>$parameters</tt> array,
+     * it is overwritten.
+     *
+     * @param  string $queue_url  Queue URL
+     * @param  array  $parameters the array to which to add the required
+     *                            parameters.
+     * @return array
+     */
+    protected function addRequiredParameters($queue_url, array $parameters)
+    {
+        $parameters['AWSAccessKeyId']   = $this->_getAccessKey();
+        $parameters['SignatureVersion'] = $this->_sqsSignatureVersion;
+        $parameters['Timestamp']        = gmdate('Y-m-d\TH:i:s\Z', time()+10);
+        $parameters['Version']          = $this->_sqsApiVersion;
+        $parameters['SignatureMethod']  = $this->_sqsSignatureMethod;
+        $parameters['Signature']        = $this->_signParameters($queue_url, $parameters);
+
+        return $parameters;
+    }
+
+    /**
+     * Computes the RFC 2104-compliant HMAC signature for request parameters
+     *
+     * This implements the Amazon Web Services signature, as per the following
+     * specification:
+     *
+     * 1. Sort all request parameters (including <tt>SignatureVersion</tt> and
+     *    excluding <tt>Signature</tt>, the value of which is being created),
+     *    ignoring case.
+     *
+     * 2. Iterate over the sorted list and append the parameter name (in its
+     *    original case) and then its value. Do not URL-encode the parameter
+     *    values before constructing this string. Do not use any separator
+     *    characters when appending strings.
+     *
+     * @param  string $queue_url  Queue URL
+     * @param  array  $parameters the parameters for which to get the signature.
+     *
+     * @return string the signed data.
+     */
+    protected function _signParameters($queue_url, array $paramaters)
+    {
+        $data = "GET\n";
+        $data .= $this->_sqsEndpoint . "\n";
+        if ($queue_url !== null) {
+            $data .= parse_url($queue_url, PHP_URL_PATH);
+        }
+        else {
+            $data .= '/';
+        }
+        $data .= "\n";
+
+        uksort($paramaters, 'strcmp');
+        unset($paramaters['Signature']);
+
+        $arrData = array();
+        foreach($paramaters as $key => $value) {
+            $arrData[] = $key . '=' . str_replace('%7E', '~', urlencode($value));
+        }
+
+        $data .= implode('&', $arrData);
+
+        $hmac = Zend_Crypt_Hmac::compute($this->_getSecretKey(), 'SHA256', $data, Zend_Crypt_Hmac::BINARY);
+
+        return base64_encode($hmac);
+    }
+}

+ 38 - 0
library/Zend/Service/Amazon/Sqs/Exception.php

@@ -0,0 +1,38 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service
+ * @subpackage Amazon_Sqs
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id$
+ */
+
+
+/**
+ * Zend_Service_Amazon/Exception
+ */
+require_once 'Zend/Service/Amazon/Exception.php';
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Service
+ * @subpackage Amazon_Sqs
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_Amazon_Sqs_Exception extends Zend_Service_Amazon_Exception
+{}

+ 23 - 0
tests/TestConfiguration.php.dist

@@ -446,6 +446,29 @@ define('TESTS_ZEND_MAIL_SMTP_AUTH', false);
 // AUTH can be set to false or a string of AUTH method (e.g. LOGIN, PLAIN, CRAMMD5 or DIGESTMD5)
 
 /**
+ * Zend_Queue Test Configuration constants
+ *
+ * The Zend_Queue_Adapter_Db constant should be a JSON-encoded string
+ * representing a configuration object for Zend_Db::factory(). For example:
+ * {
+ *     type: "pdo_mysql",
+ *     host: "127.0.0.1",
+ *     port: 3306,
+ *     username: "queue",
+ *     password: "queue",
+ *     dbname: "queue"
+ * }
+ *
+ * Selectively define the below in order to run tests for them.
+ */
+define('TESTS_ZEND_QUEUE_APACHEMQ_HOST', false);
+define('TESTS_ZEND_QUEUE_APACHEMQ_PORT', false);
+define('TESTS_ZEND_QUEUE_DB', false)
+define('TESTS_ZEND_QUEUE_MEMCACHEQ_SCHEME', false);
+define('TESTS_ZEND_QUEUE_MEMCACHEQ_HOST', false);
+define('TESTS_ZEND_QUEUE_MEMCACHEQ_PORT', false);
+
+/**
  * Zend_Service_Amazon online tests
  */
 define('TESTS_ZEND_SERVICE_AMAZON_ONLINE_ENABLED', false);

+ 2 - 0
tests/Zend/AllTests.php

@@ -76,6 +76,7 @@ require_once 'Zend/Paginator/AllTests.php';
 require_once 'Zend/Pdf/AllTests.php';
 require_once 'Zend/RegistryTest.php';
 require_once 'Zend/Rest/AllTests.php';
+require_once 'Zend/Queue/AllTests.php';
 require_once 'Zend/Search/Lucene/AllTests.php';
 require_once 'Zend/Server/AllTests.php';
 require_once 'Zend/Service/AllTests.php';
@@ -161,6 +162,7 @@ class Zend_AllTests
         $suite->addTest(Zend_Pdf_AllTests::suite());
         $suite->addTestSuite('Zend_RegistryTest');
         $suite->addTest(Zend_Rest_AllTests::suite());
+        $suite->addTest(Zend_Queue_AllTests::suite());
         $suite->addTest(Zend_Search_Lucene_AllTests::suite());
         $suite->addTest(Zend_Server_AllTests::suite());
         $suite->addTest(Zend_Service_AllTests::suite());

+ 887 - 0
tests/Zend/Queue/Adapter/AdapterTest.php

@@ -0,0 +1,887 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * The adapter test class provides a universal test class for all of the
+ * abstract methods.
+ *
+ * All methods marked not supported are explictly checked for for throwing
+ * an exception.
+ */
+
+/** PHPUnit Test Case */
+require_once 'PHPUnit/Framework/TestCase.php';
+
+/** TestHelp.php */
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue/Message.php';
+
+/** Zend_Queue_Message_Test */
+require_once 'MessageTestClass.php';
+
+/** Zend_Queue_Message_Iterator2 */
+require_once 'Iterator2.php';
+
+/**
+ * @see Zend_Config
+ */
+require_once 'Zend/Config.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+abstract class Zend_Queue_Adapter_AdapterTest extends PHPUnit_Framework_TestCase
+{
+    public function tearDown()
+    {
+        $this->error = false;
+    }
+
+    /**
+     * getAdapterName() is an method to help make AdapterTest work with any
+     * new adapters
+     *
+     * You must overload this method
+     *
+     * @return string
+     */
+    public function getAdapterName()
+    {
+        die('You must overload this function: getAdapterName()');
+        // example for Zend_Queue_Adatper_Array
+        return 'Array';
+    }
+
+    /**
+     * getAdapterName() is an method to help make AdapterTest work with any
+     * new adapters
+     *
+     * You may overload this method.  The default return is
+     * 'Zend_Queue_Adapter_' . $this->getAdapterName()
+     *
+     * @return string
+     */
+    public function getAdapterFullName()
+    {
+        return 'Zend_Queue_Adapter_' . $this->getAdapterName();
+    }
+
+    public function getTestConfig()
+    {
+        return array('driverOptions' => array());
+    }
+
+    /**
+     * for ActiveMQ it uses /queue/ /temp-queue/ /topic/ /temp-topic/
+     */
+    public function createQueueName($name)
+    {
+        return $name;
+    }
+
+    /**
+     * This is a generic function that creates a queue
+     *
+     * @param array $config, $config['name'] must be set.
+     *
+     * or
+     *
+     * @param string $name - name of the queue to create
+     * @param array $config - a special config?
+     * @return Zend_Queue
+     */
+    protected function createQueue($name, $config = null)
+    {
+        if (is_array($name)) {
+            $config = $name;
+            if (! is_string($config['name'])) {
+                throw new Exception("You must set a name in the config");
+            }
+        }
+
+        if ($config === null) {
+            $config = $this->getTestConfig();
+            $config['name'] = $name;
+        }
+
+        if (is_string($name)) {
+            $config['name'] = $name;
+        }
+
+        $config['name'] = $this->createQueueName($config['name']);
+
+        $class = $this->getAdapterFullName();
+
+        // create queue
+        if (!class_exists($class)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($class);
+        }
+
+        set_error_handler(array($this, 'handleErrors'));
+        try {
+            $queue = new Zend_Queue($this->getAdapterName(), $config);
+        } catch (Zend_Queue_Exception $e) {
+            $this->markTestSkipped();
+            restore_error_handler();
+            return false;
+        }
+        restore_error_handler();
+
+        return $queue;
+    }
+
+    public function handleErrors($errno, $errstr)
+    {
+        $this->error = true;
+    }
+
+    // test the constants
+    public function testConst()
+    {
+        $this->markTestSkipped('must be tested in each individual adapter');
+    }
+
+    public function testGetOptions()
+    {
+        $config = $this->getTestConfig();
+        $config['setting'] = true;
+
+        if (!$queue = $this->createQueue(__FUNCTION__, $config)) {
+            return;
+        }
+        $adapter = $queue->getAdapter();
+
+        $new = $adapter->getOptions();
+
+        $this->assertTrue(is_array($new));
+        $this->assertEquals($new['setting'], $config['setting']);
+
+        // delete the queue we created
+        $queue->deleteQueue();
+    }
+
+    // test the constructor
+    public function testZendQueueAdapterConstructor()
+    {
+        $class = $this->getAdapterFullName();
+        /**
+         * @see Zend_Loader
+         */
+        require_once 'Zend/Loader.php';
+        Zend_Loader::loadClass($class);
+
+        try {
+            $obj = new $class(true);
+            $this->fail('__construct() $config must be an array');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $obj = new $class( array());
+            $this->fail('__construct() cannot accept an empty array for a configuration');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $obj = new $class(array('name' => 'queue1', 'driverOptions'=>true));
+            $this->fail('__construct() $config[\'options\'] must be an array');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $obj = new $class(array('name' => 'queue1', 'driverOptions'=>array('opt'=>'val')));
+            $this->fail('__construct() humm I think this test is supposed to work @TODO');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+        try {
+            $config = new Zend_Config(array('driverOptions' => array() ));
+            $obj = new $class($config);
+            $this->fail('__construct() \'name\' is a required configuration value');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $config = new Zend_Config(array('name' => 'queue1', 'driverOptions' => array(), 'options' => array('opt1' => 'val1')));
+            $obj = new $class($config);
+            $this->fail('__construct() is not supposed to accept a true value for a configuraiton');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        // try passing the queue to the $adapter
+        if (!$queue = $this->createQueue(__FUNCTION__)) {
+            return;
+        }
+        $obj = new $class($queue->getOptions(), $queue);
+        $this->assertTrue($obj instanceof Zend_Queue_Adapter_AdapterInterface);
+    }
+
+    // this tests the configuration option $config['messageClass']
+    public function testZendQueueMessageTest()
+    {
+        $config = $this->getTestConfig();
+        $config['messageClass'] = 'Zend_Queue_Message_Test';
+
+        if (!$queue = $this->createQueue(__FUNCTION__, $config)) {
+            return;
+        }
+        $adapter = $queue->getAdapter();
+
+        // check to see if this function is supported
+        if (! ($adapter->isSupported('send')
+               && $adapter->isSupported('receive'))) {
+
+            // delete the queue we created
+            $queue->deleteQueue();
+
+            $this->markTestSkipped('send() receive() are not supported');
+        }
+
+        $body = 'this is a test message';
+        $message = $queue->send($body);
+
+        $this->assertTrue($message instanceof Zend_Queue_Message);
+
+        $list = $queue->receive();
+        $this->assertTrue($list instanceof Zend_Queue_Message_Iterator);
+        foreach ( $list as $i => $message ) {
+            $this->assertTrue($message instanceof Zend_Queue_Message_Test);
+            $queue->deleteMessage($message);
+        }
+
+        // delete the queue we created
+        $queue->deleteQueue();
+    }
+
+    public function testFactory()
+    {
+        if (!$queue = $this->createQueue(__FUNCTION__)) {
+            return;
+        }
+        $this->assertTrue($queue->getAdapter() instanceof Zend_Queue_Adapter_AdapterInterface);
+    }
+
+    public function testCreate()
+    {
+        if (!$queue = $this->createQueue(__FUNCTION__)) {
+            return;
+        }
+        $adapter = $queue->getAdapter();
+
+        // check to see if this function is supported
+        $func = 'create';
+        if (! $adapter->isSupported($func)) {
+            $this->markTestSkipped($func . '() is not supported');
+            return;
+        }
+
+        if ($adapter->isSupported('getQueues')) {
+            $this->assertTrue(in_array($queue->getName(), $adapter->getQueues()));
+        }
+
+        // cannot recreate a queue.
+        $this->assertFalse($adapter->create($queue->getName()));
+
+        // delete the queue we created
+        $queue->deleteQueue();
+    }
+
+    public function testDelete()
+    {
+        if (!$queue = $this->createQueue(__FUNCTION__)) {
+            return;
+        }
+        $adapter = $queue->getAdapter();
+
+        // check to see if this function is supported
+        $func = 'delete';
+        if (! $adapter->isSupported($func)) {
+            $this->markTestSkipped($func . '() is not supported');
+            return;
+        }
+
+        $new = $this->createQueueName(__FUNCTION__ . '_2');
+        $this->assertTrue($adapter->create($new));
+        $this->assertTrue($adapter->delete($new));
+
+        if ($adapter->isSupported('getQueues')) {
+            if (in_array($new, $adapter->getQueues())) {
+                $this->fail('delete() failed to delete it\'s queue, but returned true: '. $new);
+            }
+        }
+
+        // delete the queue we created
+        $queue->deleteQueue();
+    }
+
+    public function testIsExists()
+    {
+        if (!$queue = $this->createQueue(__FUNCTION__)) {
+            return;
+        }
+        $adapter = $queue->getAdapter();
+
+        // check to see if this function is supported
+        $func = 'isExists';
+        if (! $adapter->isSupported($func)) {
+            $this->markTestSkipped($func . '() is not supported');
+            return;
+        }
+
+        $this->assertFalse($adapter->isExists('perl'));
+
+        $new = $this->createQueueName(__FUNCTION__ . '_2');
+        $this->assertTrue($adapter->create($new));
+        $this->assertTrue($adapter->isExists($new));
+        $this->assertTrue($adapter->delete($new));
+
+        if ($adapter->isSupported('getQueues')) {
+            if (in_array($new, $adapter->getQueues())) {
+                $this->fail('delete() failed to delete it\'s queue, but returned true: '. $new);
+            }
+        }
+
+        // delete the queue we created
+        $queue->deleteQueue();
+    }
+
+    public function testSend()
+    {
+        if (!$queue = $this->createQueue(__FUNCTION__)) {
+            return;
+        }
+        $adapter = $queue->getAdapter();
+
+        // check to see if this function is supported
+        $func = 'send';
+        if (! $adapter->isSupported($func)) {
+            $this->markTestSkipped($func . '() is not supported');
+            return;
+        }
+
+        $body = 'this is a test message';
+        $message = $adapter->send($body);
+        $this->assertTrue($message instanceof Zend_Queue_Message);
+
+        // receive the record we created.
+        if (! $adapter->isSupported('receive')) {
+            $messages = $adapter->receive();
+            foreach ( $list as $i => $message ) {
+                $this->assertTrue($message instanceof Zend_Queue_Message_Test);
+                $queue->deleteMessage($message);
+            }
+        }
+
+        // delete the queue we created
+        $queue->deleteQueue();
+    }
+
+    public function testReceive()
+    {
+        if (!$queue = $this->createQueue(__FUNCTION__)) {
+            return;
+        }
+        $adapter = $queue->getAdapter();
+
+        // check to see if this function is supported
+        $func = 'receive';
+        if (! $adapter->isSupported($func)) {
+            $this->markTestSkipped($func . '() is not supported');
+            return;
+        }
+
+        // send the message
+        $body = 'this is a test message 2';
+        $message = $adapter->send($body);
+        $this->assertTrue($message instanceof Zend_Queue_Message);
+
+        // get it back
+        $list = $adapter->receive(1);
+        $this->assertEquals(1, count($list));
+        $this->assertTrue($list instanceof Zend_Queue_Message_Iterator);
+        $this->assertTrue($list->valid());
+
+        $message = $list->current();
+        if ($adapter->isSupported('deleteMessage')) {
+            $adapter->deleteMessage($list->current());
+        }
+
+        $this->assertTrue($message instanceof Zend_Queue_Message);
+        $this->assertEquals($message->body, $body);
+
+        // delete the queue we created
+        $queue->deleteQueue();
+    }
+
+    public function testDeleteMessage()
+    {
+        if (!$queue = $this->createQueue(__FUNCTION__)) {
+            return;
+        }
+        $adapter = $queue->getAdapter();
+
+        // check to see if this function is supported
+        $func = 'deleteMessage';
+        if (! $adapter->isSupported($func)) {
+            $this->markTestSkipped($func . '() is not supported');
+            return;
+        }
+
+        // in order to test this we need to send and receive so that the
+        // test code can send a sample message.
+        if (! ($adapter->isSupported('send') && $adapter->isSupported('receive'))) {
+            $this->markTestSkipped('send() and receive() are not supported');
+        }
+
+        $body = 'this is a test message';
+        $message = $adapter->send($body);
+        $this->assertTrue($message instanceof Zend_Queue_Message);
+
+        $list = $adapter->receive();
+        $this->assertTrue($list instanceof Zend_Queue_Message_Iterator);
+        $this->assertTrue($list->valid());
+
+        $message = $list->current();
+        $this->assertTrue($message instanceof Zend_Queue_Message);
+
+        $this->assertTrue($adapter->deleteMessage($message));
+
+        // no more messages, should return false
+        // stomp and amazon always return true.
+        $falsePositive = array('Apachemq', 'Amazon');
+        if (! in_array($this->getAdapterName(), $falsePositive)) {
+            $this->assertFalse($adapter->deleteMessage($message));
+        }
+
+        // delete the queue we created
+        $queue->deleteQueue();
+    }
+
+    public function testGetQueues()
+    {
+        if (!$queue = $this->createQueue(__FUNCTION__)) {
+            return;
+        }
+        $adapter = $queue->getAdapter();
+
+        // check to see if this function is supported
+        $func = 'getQueues';
+        if (! $adapter->isSupported($func)) {
+            $this->markTestSkipped($func . '() is not supported');
+            return;
+        }
+
+        // get a listing of queues
+        $queues = $adapter->getQueues();
+
+        // this is an array right?
+        $this->assertTrue(is_array($queues));
+
+        // make sure our current queue is in this list.
+        $this->assertTrue(in_array($queue->getName(), $queues));
+
+        // delete the queue we created
+        $queue->deleteQueue();
+    }
+
+    public function testCount()
+    {
+        if (!$queue = $this->createQueue(__FUNCTION__)) {
+            return;
+        }
+        $adapter = $queue->getAdapter();
+
+        // check to see if this function is supported
+        $func = 'count';
+        if (! $adapter->isSupported($func)) {
+            $this->markTestSkipped($func . '() is not supported');
+            return;
+        }
+
+        // for a test case, the count should be zero at first.
+        $this->assertEquals($adapter->count(), 0);
+        if (! $adapter->isSupported('send') && $adapter->isSupported('receive') ) {
+            $this->markTestSkipped('send() and receive() are not supported');
+        }
+
+        $body = 'this is a test message';
+
+        // send a message
+        $message = $adapter->send($body);
+
+        // test queue count for being 1
+        $this->assertEquals($adapter->count(), 1);
+
+        // receive the message
+        $message = $adapter->receive();
+
+        /* we need to delete the messages we put in the queue before
+         * counting.
+         *
+         * not all adapters support deleteMessage, but we should remove
+         * the messages that we created if we can.
+         */
+        if ( $adapter->isSupported('deleteMessage') ) {
+            foreach ( $message as $msg ) {
+                $adapter->deleteMessage($msg);
+            }
+        }
+
+        // test the count for being 0
+        $this->assertEquals($adapter->count(), 0);
+
+        // delete the queue we created
+        $queue->deleteQueue();
+    }
+
+    public function testCapabilities()
+    {
+        if (!$queue = $this->createQueue(__FUNCTION__)) {
+            return;
+        }
+        $adapter = $queue->getAdapter();
+
+        $list = $adapter->getCapabilities();
+        $this->assertTrue(is_array($list));
+
+        // these functions must have an boolean answer
+        $func = array(
+            'create', 'delete', 'send', 'receive',
+            'deleteMessage', 'getQueues', 'count',
+            'isExists'
+        );
+
+        foreach ( array_values($func) as $f ) {
+            $this->assertTrue(isset($list[$f]));
+            $this->assertTrue(is_bool($list[$f]));
+        }
+
+        // delete the queue we created
+        $queue->deleteQueue();
+    }
+
+    public function testIsSupported()
+    {
+        if (!$queue = $this->createQueue(__FUNCTION__)) {
+            return;
+        }
+        $adapter = $queue->getAdapter();
+
+        $list = $adapter->getCapabilities();
+        foreach ( $list as $function => $result ) {
+            $this->assertTrue(is_bool($result));
+            if ( $result ) {
+                $this->assertTrue($adapter->isSupported($function));
+            } else {
+                $this->assertFalse($adapter->isSupported($function));
+            }
+        }
+
+        // delete the queue we created
+        $queue->deleteQueue();
+    }
+
+    public function testGetQueue()
+    {
+        if (!$queue = $this->createQueue(__FUNCTION__)) {
+            return;
+        }
+        $adapter = $queue->getAdapter();
+
+        $this->assertTrue($queue === $queue->getAdapter()->getQueue());
+
+        // delete the queue we created
+        $queue->deleteQueue();
+    }
+
+    /*
+     * Send about 10 messages, read 5 back, then read 5 back 1 at a time.
+     * delete all messages and created queue
+     */
+    public function testSampleBehavior()
+    {
+        if (!$queue = $this->createQueue(__FUNCTION__)) {
+            return;
+        }
+        $this->assertTrue($queue instanceof Zend_Queue);
+
+        if ($queue->isSupported('send')) {
+            $msg = 1;
+
+            for($i = 0; $i < 10; $i++) {
+                $queue->send("$msg");
+                $msg ++;
+            }
+        }
+
+        if ($queue->isSupported('receive')) {
+            $msg = 1;
+            $messages = $queue->receive(5);
+
+            foreach($messages as $i => $message) {
+                $this->assertEquals($msg, $message->body);
+                $queue->deleteMessage($message);
+                $msg++;
+            }
+
+            for($i = 0; $i < 5; $i++) {
+                $messages = $queue->receive();
+                $message = $messages->current();
+                $this->assertEquals($msg, $message->body);
+                $queue->deleteMessage($message);
+                $msg++;
+            }
+        }
+
+        $this->assertEquals(0, count($queue));
+        $this->assertTrue($queue->deleteQueue());
+
+        // delete the queue we created
+        $queue->deleteQueue();
+    }
+
+    /**
+     * This tests to see if a message is in-visibile for the proper amount of time
+     *
+     * adapters that support deleteMessage() by nature will support visibility
+     */
+    public function testVisibility()
+    {
+        $debug = false;
+        $default_timeout = 3; // how long we tell the queue to keep the message invisible
+        $extra_delay = 2; // how long we are willing to wait for the test to finish before failing
+        // keep in mind that some queue services are on forigen machines and need network time.
+
+        if (false) { // easy comment/uncomment, set to true or false
+            $this->markTestSkipped('Visibility testing takes ' . $default_timeout+$extra_delay . ' seconds per adapter, if you wish to test this, uncomment the test case in ' . __FILE__ . ' line ' . __LINE__);
+            return;
+        }
+
+        $config = $this->getTestConfig();
+        $config['timeout'] = 2;
+
+        if (!$queue = $this->createQueue(__FUNCTION__, $config)) {
+            return;
+        }
+        $adapter = $queue->getAdapter();
+
+        $not_supported = array('Apachemq');
+        if ((! $queue->isSupported('deleteMessage')) || in_array($this->getAdapterName(), $not_supported)) {
+            $queue->deleteQueue();
+            $this->markTestSkipped($this->getAdapterName() . ' does not support visibility of messages');
+            return;
+        }
+
+        $body = 'hello world';
+
+        $queue->send($body);
+        $messages = $queue->receive(1); // messages are deleted at the bottom.
+
+        if ($queue->isSupported('count')) {
+            $this->assertEquals(1, count($queue));
+        }
+
+        $start = microtime(true);
+        $end = 0;
+
+        $this->assertTrue($messages instanceof Zend_Queue_Message_Iterator);
+
+        $timeout = $config['timeout'] + $start + $extra_delay;
+        $found = false;
+        $check = microtime(true);
+
+        $end = false;
+        do {
+            $search = $queue->receive(1);
+            if ((microtime(true) - $check) > 0.1) {
+                $check = microtime(true);
+                if ($debug) echo "Checking - found ", count($search), " messages at : ", $check, "\n";
+            }
+            if ( count($search) > 0 ) {
+                if ($search->current()->body == $body) {
+                    $found = true;
+                    $end = microtime(true);
+                } else {
+                    $this->fail('sent message is not the message received');
+                }
+            }
+        } while ($found === false && microtime(true) < $timeout);
+
+        // record end time
+        if ($end === false) {
+            $end = microtime(true);
+        }
+
+        $duration = sprintf("%5.2f seconds", $end-$start);
+        /*
+        There has to be some fuzzyness regarding comparisons because while
+        the timeout may be honored, the actual code time, database querying
+        and so on, may take more than the timeout time.
+        */
+        if ($found) {
+            if (abs(($end-$start) - $config['timeout']) < $extra_delay) { // stupid Db Adapter responds in a fraction less than a second.
+                $this->assertTrue(true, 'message was invisible for the required amount of time');
+            } else {
+                if ($debug) echo 'required duration of invisibility: ', $config['timeout'], ' seconds; actual duration: ', $duration, "\n";
+                $this->fail('message was NOT invisible for the required amount of time');
+            }
+        } else {
+            $this->fail('message never became visibile duration:' . $duration);
+        }
+        if ($debug) echo "duration $duration\n";
+
+        // now we delete the messages
+        if ( $adapter->isSupported('deleteMessage') ) {
+            foreach ( $messages as $msg ) {
+                $adapter->deleteMessage($msg);
+            }
+        }
+
+
+        // delete the queue we created
+        $queue->deleteQueue();
+    }
+
+    /**
+     * tests a function for an exception
+     *
+     * @param string $func function name
+     * @param array $args function arguments
+     * @return boolean - true if exception, false if not
+     */
+    protected function try_exception($func, $args)
+    {
+        $return = false;
+
+    }
+
+    public function testIsSupportException()
+    {
+        if (!$queue = $this->createQueue(__FUNCTION__)) {
+            return;
+        }
+        $adapter = $queue->getAdapter();
+
+        $functions = $adapter->getCapabilities();
+
+        if (! $functions['create']) {
+            try {
+                $adapter->create(__FUNCTION__ . '_2');
+                $this->fail('unsupported create() failed to throw an exception');
+            } catch (Exception $e) {
+                $this->assertTrue(true, 'exception thrown');
+            }
+        }
+
+        if (! $functions['delete']) {
+            try {
+                $adapter->delete(__FUNCTION__ . '_2');
+                $this->fail('unsupported delete() failed to throw an exception');
+            } catch (Exception $e) {
+                $this->assertTrue(true, 'exception thrown');
+            }
+        }
+
+        if (! $functions['send']) {
+            try {
+                $adapter->send(__FUNCTION__);
+                $this->fail('unsupported send() failed to throw an exception');
+            } catch (Exception $e) {
+                $this->assertTrue(true, 'exception thrown');
+            }
+        }
+
+        if (! $functions['receive']) {
+            try {
+                $adapter->send(__FUNCTION__);
+                $this->fail('unsupported receive() failed to throw an exception');
+            } catch (Exception $e) {
+                $this->assertTrue(true, 'exception thrown');
+            }
+        }
+
+        if (! $functions['receive']) {
+            try {
+                $adapter->receive();
+                $this->fail('unsupported receive() failed to throw an exception');
+            } catch (Exception $e) {
+                $this->assertTrue(true, 'exception thrown');
+            }
+        }
+
+        if (! $functions['deleteMessage']) {
+            try {
+                $message = new Zend_Queue_Message();
+                $adapter->deleteMessage($message);
+                $this->fail('unsupported deleteMessage() failed to throw an exception');
+            } catch (Exception $e) {
+                $this->assertTrue(true, 'exception thrown');
+            }
+        }
+
+        if (! $functions['getQueues']) {
+            try {
+                $adapter->getQueues();
+                $this->fail('unsupported getQueues() failed to throw an exception');
+            } catch (Exception $e) {
+                $this->assertTrue(true, 'exception thrown');
+            }
+        }
+
+        if (! $functions['count']) {
+            try {
+                $a = $adapter->count();
+                $this->fail('unsupported count() failed to throw an exception');
+            } catch (Exception $e) {
+                $this->assertTrue(true, 'exception thrown');
+            }
+        }
+
+        if (! $functions['isExists']) {
+            try {
+                $a = $adapter->isExists(__FUNCTION__ . '_3');
+                $this->fail('unsupported isExists() failed to throw an exception');
+            } catch (Exception $e) {
+                $this->assertTrue(true, 'exception thrown');
+            }
+        }
+
+        // delete the queue we created
+        $queue->deleteQueue();
+    }
+}

+ 82 - 0
tests/Zend/Queue/Adapter/ApachemqTest.php

@@ -0,0 +1,82 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * The adapter test class provides a universal test class for all of the
+ * abstract methods.
+ *
+ * All methods marked not supported are explictly checked for for throwing
+ * an exception.
+ */
+
+/** PHPUnit Test Case */
+require_once 'PHPUnit/Framework/TestCase.php';
+
+/** TestHelp.php */
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+
+class Zend_Queue_Adapter_ApachemqTest extends Zend_Queue_Adapter_AdapterTest
+{
+    /**
+     * getAdapterName() is an method to help make AdapterTest work with any
+     * new adapters
+     *
+     * You must overload this method
+     *
+     * @return string
+     */
+    public function getAdapterName()
+    {
+        return 'Apachemq';
+    }
+
+    public function getTestConfig()
+    {
+        $driverOptions = array();
+        if (defined('TESTS_ZEND_QUEUE_APACHEMQ_HOST')) {
+            $driverOptions['host'] = TESTS_ZEND_QUEUE_APACHEMQ_HOST;
+        }
+        if (defined('TESTS_ZEND_QUEUE_APACHEMQ_PORT')) {
+            $driverOptions['port'] = TESTS_ZEND_QUEUE_APACHEMQ_PORT;
+        }
+        return array('driverOptions' => $driverOptions);
+    }
+
+    /**
+     * Stomped requires specific name types
+     */
+    public function createQueueName($name)
+    {
+        return '/temp-queue/' . $name;
+    }
+
+    public function testConst()
+    {
+        /**
+         * @see Zend_Queue_Adapter_Stomp
+         */
+        require_once 'Zend/Queue/Adapter/Apachemq.php';
+        $this->assertTrue(is_string(Zend_Queue_Adapter_Apachemq::DEFAULT_SCHEME));
+        $this->assertTrue(is_string(Zend_Queue_Adapter_Apachemq::DEFAULT_HOST));
+        $this->assertTrue(is_integer(Zend_Queue_Adapter_Apachemq::DEFAULT_PORT));
+    }
+}

+ 120 - 0
tests/Zend/Queue/Adapter/ArrayTest.php

@@ -0,0 +1,120 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * The adapter test class provides a universal test class for all of the
+ * abstract methods.
+ *
+ * All methods marked not supported are explictly checked for for throwing
+ * an exception.
+ */
+
+/** PHPUnit Test Case */
+require_once 'PHPUnit/Framework/TestCase.php';
+
+/** TestHelp.php */
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue/Message.php';
+
+/** Zend_Queue_Message_Test */
+require_once 'MessageTestClass.php';
+
+/** Base Adapter test class */
+require_once dirname(__FILE__) . '/AdapterTest.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+class Zend_Queue_Adapter_ArrayTest extends Zend_Queue_Adapter_AdapterTest
+{
+    /**
+     * getAdapterName() is an method to help make AdapterTest work with any
+     * new adapters
+     *
+     * You must overload this method
+     *
+     * @return string
+     */
+    public function getAdapterName()
+    {
+        return 'Array';
+    }
+
+    /**
+     * getAdapterName() is an method to help make AdapterTest work with any
+     * new adapters
+     *
+     * You may overload this method.  The default return is
+     * 'Zend_Queue_Adapter_' . $this->getAdapterName()
+     *
+     * @return string
+     */
+    public function getAdapterFullName()
+    {
+        return 'Zend_Queue_Adapter_' . $this->getAdapterName();
+    }
+
+    public function getTestConfig()
+    {
+        return array('driverOptions' => array());
+    }
+
+    // test the constants
+    public function testConst()
+    {
+        $this->markTestSkipped('no constants to test');
+    }
+
+    // extra non standard tests
+    public function test_magic()
+    {
+        $queue = $this->createQueue(__FUNCTION__);
+        $adapter = $queue->getAdapter();
+
+        $this->assertTrue(is_array($adapter->__sleep()));
+        $data = serialize($adapter);
+        $new = unserialize($data);
+        $this->assertEquals($new->getData(), $adapter->getData());
+    }
+
+    public function test_get_setData()
+    {
+        $queue = $this->createQueue(__FUNCTION__);
+        $adapter = $queue->getAdapter();
+
+        $data = array('test' => 1);
+        $adapter->setData($data);
+        $got = $adapter->getData();
+        $this->assertEquals($data['test'], $got['test']);
+    }
+}

+ 143 - 0
tests/Zend/Queue/Adapter/DbTest.php

@@ -0,0 +1,143 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * The adapter test class provides a universal test class for all of the
+ * abstract methods.
+ *
+ * All methods marked not supported are explictly checked for for throwing
+ * an exception.
+ */
+
+/** TestHelp.php */
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue/Message.php';
+
+/** Zend_Queue_Message_Test */
+require_once 'MessageTestClass.php';
+
+/** Base Adapter test class */
+require_once dirname(__FILE__) . '/AdapterTest.php';
+
+/**
+ * @see Zend_Db_Select
+ */
+require_once 'Zend/Db/Select.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+class Zend_Queue_Adapter_DbTest extends Zend_Queue_Adapter_AdapterTest
+{
+    protected function setUp()
+    {
+        date_default_timezone_set('GMT');
+    }
+
+    /**
+     * getAdapterName() is an method to help make AdapterTest work with any
+     * new adapters
+     *
+     * You must overload this method
+     *
+     * @return string
+     */
+    public function getAdapterName()
+    {
+        return 'Db';
+    }
+
+    /**
+     * getAdapterName() is an method to help make AdapterTest work with any
+     * new adapters
+     *
+     * You may overload this method.  The default return is
+     * 'Zend_Queue_Adapter_' . $this->getAdapterName()
+     *
+     * @return string
+     */
+    public function getAdapterFullName()
+    {
+        return 'Zend_Queue_Adapter_' . $this->getAdapterName();
+    }
+
+    public function getTestConfig()
+    {
+        $driverOptions = array();
+        if (defined('TESTS_ZEND_QUEUE_DB')) {
+            require_once 'Zend/Json.php';
+            $driverOptions = Zend_Json::decode(TESTS_ZEND_QUEUE_DB);
+        }
+
+        return array(
+            'options'       => array(Zend_Db_Select::FOR_UPDATE => true),
+            'driverOptions' => $driverOptions,
+        );
+    }
+
+    // test the constants
+    public function testConst()
+    {
+        $this->markTestSkipped('no constants to test');
+    }
+
+    // additional non-standard tests
+
+    public function test_constructor2()
+    {
+        try {
+            $config = $this->getTestConfig();
+            /**
+             * @see Zend_Db_Select
+             */
+            require_once 'Zend/Db/Select.php';
+            $config['options'][Zend_Db_Select::FOR_UPDATE] = array();
+            $queue = $this->createQueue(__FUNCTION__, $config);
+            $this->fail('FOR_UPDATE accepted an array');
+        } catch (Exception $e) {
+            $this->assertTrue(true, 'FOR_UPDATE cannot be an array');
+        }
+
+        foreach (array('host', 'username', 'password', 'dbname') as $i => $arg) {
+            try {
+                $config = $this->getTestConfig();
+                unset($config['driverOptions'][$arg]);
+                $queue = $this->createQueue(__FUNCTION__, $config);
+                $this->fail("$arg is required but was missing.");
+            } catch (Exception $e) {
+                $this->assertTrue(true, $arg . ' is required.');
+            }
+        }
+    }
+}
+

+ 41 - 0
tests/Zend/Queue/Adapter/Iterator2.php

@@ -0,0 +1,41 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Message
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Message.php 14646 2009-04-04 21:17:27Z jplock $
+ */
+
+/**
+ * Class for managing queue messages
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Message
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/**
+ * @see Zend_Queue_Message_Iterator
+ */
+require_once 'Zend/Queue/Message/Iterator.php';
+
+class Zend_Queue_Message_Iterator2 extends Zend_Queue_Message_Iterator
+{
+    // This is a really lazy way to test a new iterator.
+}

+ 113 - 0
tests/Zend/Queue/Adapter/MemcacheqTest.php

@@ -0,0 +1,113 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * The adapter test class provides a universal test class for all of the
+ * abstract methods.
+ *
+ * All methods marked not supported are explictly checked for for throwing
+ * an exception.
+ */
+
+/** PHPUnit Test Case */
+require_once 'PHPUnit/Framework/TestCase.php';
+
+/** TestHelp.php */
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue/Message.php';
+
+/** Zend_Queue_Message_Test */
+require_once 'MessageTestClass.php';
+
+/** Base Adapter test class */
+require_once dirname(__FILE__) . '/AdapterTest.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+class Zend_Queue_Adapter_MemcacheqTest extends Zend_Queue_Adapter_AdapterTest
+{
+    /**
+     * getAdapterName() is an method to help make AdapterTest work with any
+     * new adapters
+     *
+     * You must overload this method
+     *
+     * @return string
+     */
+    public function getAdapterName()
+    {
+        return 'Memcacheq';
+    }
+
+    /**
+     * getAdapterName() is an method to help make AdapterTest work with any
+     * new adapters
+     *
+     * You may overload this method.  The default return is
+     * 'Zend_Queue_Adapter_' . $this->getAdapterName()
+     *
+     * @return string
+     */
+    public function getAdapterFullName()
+    {
+        return 'Zend_Queue_Adapter_' . $this->getAdapterName();
+    }
+
+    public function getTestConfig()
+    {
+        $driverOptions = array();
+        if (defined('TESTS_ZEND_QUEUE_MEMCACHEQ_SCHEME')) {
+            $driverOptions['scheme'] = TESTS_ZEND_QUEUE_MEMCACHEQ_SCHEME;
+        }
+        if (defined('TESTS_ZEND_QUEUE_MEMCACHEQ_HOST')) {
+            $driverOptions['host'] = TESTS_ZEND_QUEUE_MEMCACHEQ_HOST;
+        }
+        if (defined('TESTS_ZEND_QUEUE_MEMCACHEQ_PORT')) {
+            $driverOptions['port'] = TESTS_ZEND_QUEUE_MEMCACHEQ_PORT;
+        }
+        return array('driverOptions' => $driverOptions);
+    }
+
+    // test the constants
+    public function testConst()
+    {
+        /**
+         * @see Zend_Queue_Adapter_Memcacheq
+         */
+        require_once 'Zend/Queue/Adapter/Memcacheq.php';
+        $this->assertTrue(is_string(Zend_Queue_Adapter_Memcacheq::DEFAULT_HOST));
+        $this->assertTrue(is_integer(Zend_Queue_Adapter_Memcacheq::DEFAULT_PORT));
+        $this->assertTrue(is_string(Zend_Queue_Adapter_Memcacheq::EOL));
+    }
+}

+ 25 - 0
tests/Zend/Queue/Adapter/MessageTestClass.php

@@ -0,0 +1,25 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+class Zend_Queue_Message_Test extends Zend_Queue_Message
+{
+}

+ 98 - 0
tests/Zend/Queue/Adapter/NullTest.php

@@ -0,0 +1,98 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * The adapter test class provides a universal test class for all of the
+ * abstract methods.
+ *
+ * All methods marked not supported are explictly checked for for throwing
+ * an exception.
+ */
+
+/** PHPUnit Test Case */
+require_once 'PHPUnit/Framework/TestCase.php';
+
+/** TestHelp.php */
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue/Message.php';
+
+/** Zend_Queue_Message_Test */
+require_once 'MessageTestClass.php';
+
+/** Base Adapter test class */
+require_once dirname(__FILE__) . '/AdapterTest.php';
+
+
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+class Zend_Queue_Adapter_NullTest extends Zend_Queue_Adapter_AdapterTest
+{
+    /**
+     * getAdapterName() is an method to help make AdapterTest work with any
+     * new adapters
+     *
+     * You must overload this method
+     *
+     * @return string
+     */
+    public function getAdapterName()
+    {
+        return 'Null';
+    }
+
+    /**
+     * getAdapterName() is an method to help make AdapterTest work with any
+     * new adapters
+     *
+     * You may overload this method.  The default return is
+     * 'Zend_Queue_Adapter_' . $this->getAdapterName()
+     *
+     * @return string
+     */
+    public function getAdapterFullName()
+    {
+        return 'Zend_Queue_Adapter_' . $this->getAdapterName();
+    }
+
+    public function getTestConfig()
+    {
+        return array('driverOptions' => array());
+    }
+
+    // test the constants
+    public function testConst()
+    {
+    }
+}

+ 194 - 0
tests/Zend/Queue/Adapter/StompIOTest.php

@@ -0,0 +1,194 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * The adapter test class provides a universal test class for all of the
+ * abstract methods.
+ *
+ * All methods marked not supported are explictly checked for for throwing
+ * an exception.
+ */
+
+/** PHPUnit Test Case */
+require_once 'PHPUnit/Framework/TestCase.php';
+
+/** TestHelp.php */
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+
+/** Zend/Queue/Adapter/Stomp/IO.php */
+require_once 'Zend/Queue/Adapter/Stomp/IO.php';
+
+class Zend_Queue_Adapter_StompIOTest extends PHPUnit_Framework_TestCase
+{
+    protected $config = array(
+        'scheme' => 'tcp',
+        'host'   => '127.0.0.1',
+        'port'   => 61613,
+    );
+
+    protected $io = false;
+
+    protected $body = 'hello world'; // 11 characters
+
+    public function setUp()
+    {
+        if ( $this->io === false ) {
+            $this->io = new Zend_Queue_Adapter_Stomp_IO($this->config);
+        }
+    }
+
+    public function test_constructFrame()
+    {
+        $frame = $this->io->constructFrame('SEND', array(), $this->body);
+
+        $correct = 'SEND' . Zend_Queue_Adapter_Stomp_IO::EOL;
+        $correct .= 'content-length: 11' . Zend_Queue_Adapter_Stomp_IO::EOL;
+        $correct .= Zend_Queue_Adapter_Stomp_IO::EOL;
+        $correct .= $this->body;
+        $correct .= Zend_Queue_Adapter_Stomp_IO::END_OF_FRAME;
+
+        $this->assertEquals($frame, $correct);
+
+        // validate parameters
+        try {
+            $frame = $this->io->constructFrame(array());
+            $this->fail('constructFrame() should have failed $action as an array');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try { // this won't test, I think because phpunit suppresses the error
+            $frame = $this->io->constructFrame('SEND', 'string');
+            $this->fail('constructFrame() should have failed $headers as a string');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try { // this won't test, I think because phpunit suppresses the error
+            $frame = $this->io->constructFrame('SEND', array(), array());
+            $this->fail('constructFrame() should have failed $body as a array');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+    }
+
+    public function test_deconstructFrame()
+    {
+        $correct = array(
+            'headers' => array(),
+            'body' => $this->body,
+            'command' => 'SEND'
+        );
+
+        $frame = $this->io->constructFrame($correct['command'], array(), $correct['body']);
+        $frame = $this->io->deconstructFrame($frame);
+        $this->assertEquals($correct['command'], $frame['command']);
+        $this->assertEquals($correct['body'], $frame['body']);
+
+        // validate parameters
+        try {
+            $frame = $this->io->deconstructFrame(array());
+            $this->fail('deconstructFrame() should have failed with an array');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+    }
+
+    public function test_write_read()
+    {
+        $frame = $this->io->constructFrame('CONNECT');
+        $frame = $this->io->writeAndRead($frame);
+
+        $headers = array(
+            'destination' => '/queue/testing',
+            'ack' => 'auto'
+        );
+
+        $frame = $this->io->constructFrame('SEND', $headers, $this->body);
+        $this->io->write($frame);
+
+        $frame = $this->io->constructFrame('SUBSCRIBE', $headers);
+        $this->io->write($frame);
+
+        $frame = $this->io->read();
+        $frame = $this->io->deconstructFrame($frame);
+
+        $this->assertEquals($this->body, $frame['body']);
+
+        // validate parameters
+        try {
+            $frame = $this->io->write(array());
+            $this->fail('write() should have failed with an array');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+    }
+
+    public function test_open_close()
+    {
+        try {
+            $obj = new Zend_Queue_Adapter_Stomp_IO($this->config);
+        } catch (Exception $e) {
+            $this->fail('failed to create Zend_Queue_Adapter_Stomp_IO object:' . $e->getMessage());
+        }
+
+        try {
+            $obj->close();
+        } catch (Exception $e) {
+            $this->fail('failed to close Zend_Queue_Adapter_Stomp_IO object:' . $e->getMessage());
+        }
+
+        // validate parameters
+        $config = array(
+            'scheme' => 'tcp',
+            'host' => 'blahblahb asfd',
+            'port' => '0'
+        );
+
+        try {
+            $frame = $this->io->open($config);
+            $this->fail('open() should have failed with an invalid configuration');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+    }
+
+    public function test_constant()
+    {
+        $this->assertTrue(is_string(Zend_Queue_Adapter_Stomp_IO::END_OF_FRAME));
+        $this->assertTrue(is_string(Zend_Queue_Adapter_Stomp_IO::CONTENT_LENGTH));
+        $this->assertTrue(is_string(Zend_Queue_Adapter_Stomp_IO::EOL));
+    }
+
+    public function test_checkSocket()
+    {
+        $this->assertTrue($this->io->checkSocket());
+        $this->io->close();
+
+        try {
+            $this->io->checkSocket();
+            $this->fail('checkSocket() should have failed on a fclose($socket)');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+    }
+}

+ 102 - 0
tests/Zend/Queue/Adapter/StompTest.php

@@ -0,0 +1,102 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * The adapter test class provides a universal test class for all of the
+ * abstract methods.
+ *
+ * All methods marked not supported are explictly checked for for throwing
+ * an exception.
+ */
+
+/** PHPUnit Test Case */
+require_once 'PHPUnit/Framework/TestCase.php';
+
+/** TestHelp.php */
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue/Message.php';
+
+/** Zend_Queue_Message_Test */
+require_once 'MessageTestClass.php';
+
+/** Base Adapter test class */
+require_once dirname(__FILE__) . '/AdapterTest.php';
+
+class Zend_Queue_Adapter_StompTest extends Zend_Queue_Adapter_AdapterTest
+{
+    /**
+     * getAdapterName() is an method to help make AdapterTest work with any
+     * new adapters
+     *
+     * You must overload this method
+     *
+     * @return string
+     */
+    public function getAdapterName()
+    {
+        return 'Stomp';
+    }
+
+    /**
+     * getAdapterName() is an method to help make AdapterTest work with any
+     * new adapters
+     *
+     * You may overload this method.  The default return is
+     * 'Zend_Queue_Adapter_' . $this->getAdapterName()
+     *
+     * @return string
+     */
+    public function getAdapterFullName()
+    {
+        return 'Zend_Queue_Adapter_' . $this->getAdapterName();
+    }
+
+    public function getTestConfig()
+    {
+        return array('driverOptions' => array('host' => '127.0.0.1',
+                                               'port' => '61613'));
+    }
+
+    /**
+     * Stomped requires specific name types
+     */
+    public function createQueueName($name)
+    {
+        return '/temp-queue/' . $name;
+    }
+
+    public function testConst()
+    {
+        /**
+         * @see Zend_Queue_Adapter_Stomp
+         */
+        require_once 'Zend/Queue/Adapter/Stomp.php';
+        $this->assertTrue(is_string(Zend_Queue_Adapter_Stomp::DEFAULT_SCHEME));
+        $this->assertTrue(is_string(Zend_Queue_Adapter_Stomp::DEFAULT_HOST));
+        $this->assertTrue(is_integer(Zend_Queue_Adapter_Stomp::DEFAULT_PORT));
+    }
+}

+ 5 - 0
tests/Zend/Queue/Adapter/WARNING.txt

@@ -0,0 +1,5 @@
+A note to those who are writing test cases.
+
+Besure to receive() for every send() otherwise previous failed tests will interfere with future tests.
+
+If necessary you may have to delete the queue before creating it.

+ 103 - 0
tests/Zend/Queue/AllTests.php

@@ -0,0 +1,103 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Zend_Queue_AllTests::main');
+}
+
+require_once dirname(__FILE__) . '/../../TestHelper.php';
+
+require_once 'Zend/Queue/FactoryTest.php';
+
+// Queue testing
+require_once 'Zend/Queue/Queue1Test.php'; // Zend_Queue_Adapter_Array
+require_once 'Zend/Queue/Queue2Test.php'; // Zend_Queue_Adapter_Null
+
+// Message testing
+require_once 'Zend/Queue/MessageTest.php';
+require_once 'Zend/Queue/Message/IteratorTest.php';
+
+// Adapter testing
+require_once 'Zend/Queue/Adapter/ArrayTest.php';
+require_once 'Zend/Queue/Adapter/MemcacheqTest.php';
+require_once 'Zend/Queue/Adapter/NullTest.php';
+require_once 'Zend/Queue/Adapter/DbTest.php';
+
+// Stomp protocol testing
+require_once 'Zend/Queue/Stomp/FrameTest.php';
+require_once 'Zend/Queue/Stomp/ClientTest.php';
+
+// Message Queues dependent on Stomp
+require_once 'Zend/Queue/Adapter/ApachemqTest.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+class Zend_Queue_AllTests
+{
+    public static function main()
+    {
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
+
+    public static function suite()
+    {
+        $suite = new PHPUnit_Framework_TestSuite('Zend Framework - Zend_Queue');
+
+        $suite->addTestSuite('Zend_Queue_FactoryTest');
+
+        // Queue testing
+        $suite->addTestSuite('Zend_Queue_Queue1Test');   // Zend_Queue_Adapter_Array
+        $suite->addTestSuite('Zend_Queue_Queue2Test');  // Zend_Queue_Adapter_Null
+
+        // Message testing
+        $suite->addTestSuite('Zend_Queue_MessageTest');
+        $suite->addTestSuite('Zend_Queue_Message_IteratorTest');
+
+        // Adapter testing
+        $suite->addTestSuite('Zend_Queue_Adapter_ArrayTest');
+        if (extension_loaded('memcache')) {
+            $suite->addTestSuite('Zend_Queue_Adapter_MemcacheqTest');
+        }
+        $suite->addTestSuite('Zend_Queue_Adapter_DbTest');
+        $suite->addTestSuite('Zend_Queue_Adapter_NullTest');
+
+        // Stomp protocol testing
+        $suite->addTestSuite('Zend_Queue_Stomp_FrameTest');
+        $suite->addTestSuite('Zend_Queue_Stomp_ClientTest');
+
+        // Message Queues dependent on Stomp
+        $suite->addTestSuite('Zend_Queue_Adapter_ApachemqTest');
+
+
+        return $suite;
+    }
+}
+
+if (PHPUnit_MAIN_METHOD == 'Zend_Queue_AllTests::main') {
+    Zend_Queue_AllTests::main();
+}

+ 128 - 0
tests/Zend/Queue/Custom/DbForUpdate.php

@@ -0,0 +1,128 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Custom
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Db.php 14846 2009-04-11 15:56:47Z danlo $
+ */
+
+/**
+ * @see Zend_Queue_Adapter_Db
+ */
+require_once 'Zend/Queue/Adapter/Db.php';
+
+/**
+ * Class for using connecting to a Zend_Db-based queuing system
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Custom
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/*
+$config['options'][Zend_Db_Select::FOR_UPDATE] is a new feature that was
+written after this code was written.  However, this will still serve as a
+good example adapter
+*/
+
+class Custom_DbForUpdate extends Zend_Queue_Adapter_Db
+{
+    /**
+     * Return the first element in the queue
+     *
+     * @param  integer    $maxMessages
+     * @param  integer    $timeout
+     * @param  Zend_Queue $queue
+     * @return Zend_Queue_Message_Iterator
+     */
+    public function receive($maxMessages=null, $timeout=null, Zend_Queue $queue=null)
+    {
+        if ($maxMessages === null) {
+            $maxMessages = 1;
+        }
+        if ($timeout === null) {
+            $timeout = self::RECEIVE_TIMEOUT_DEFAULT;
+        }
+        if ($queue === null) {
+            $queue = $this->_queue;
+        }
+
+        $msgs = array();
+
+        $info = $this->_msg_table->info();
+
+        $microtime = microtime(true); // cache microtime
+
+        $db = $this->_msg_table->getAdapter();
+
+        try {
+            // transaction must start before the select query.
+            $db->beginTransaction();
+
+            // changes: added forUpdate
+            $query = $db->select()->forUpdate();
+            $query->from($info['name'], array('*'));
+            $query->where('queue_id=?', $this->getQueueId($queue->getName()));
+            $query->where('handle IS NULL OR timeout+' . (int)$timeout . ' < ' . (int)$microtime);
+            $query->limit($maxMessages);
+
+            foreach ($db->fetchAll($query) as $data) {
+                // setup our changes to the message
+                $data['handle'] = md5(uniqid(rand(), true));
+
+                $update = array(
+                    'handle'  => $data['handle'],
+                    'timeout' => $microtime
+                );
+
+                // update the database
+                $where = array();
+                $where[] = $db->quoteInto('message_id=?', $data['message_id']);
+
+                $count = $db->update($info['name'], $update, $where);
+
+                // we check count to make sure no other thread has gotten
+                // the rows after our select, but before our update.
+                if ($count > 0) {
+                    $msgs[] = $data;
+                    $this->getLogger()->debug('Received message:' . $data['message_id'] . ' byte size=' . strlen($data['body']));
+                }
+            }
+            $db->commit();
+        } catch (Exception $e) {
+            $db->rollBack();
+            $this->getLogger()->err($e->getMessage() . ' code ' . $e->getCode());
+            /**
+             * @see Zend_Queue_Exception
+             */
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception($e->getMessage(), $e->getCode());
+        }
+
+        $config = array(
+            'queue'    => $queue,
+            'data'     => $msgs,
+            'messageClass' => $queue->getMessageClass()
+        );
+
+        $classname = $queue->getMessageSetClass();
+        Zend_Loader::loadClass($classname);
+        return new $classname($config);
+    }
+}

+ 121 - 0
tests/Zend/Queue/Custom/Message.php

@@ -0,0 +1,121 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Custom
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Message.php 14777 2009-04-09 04:40:39Z danlo $
+ */
+
+/**
+ * Class for custom messages
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Custom
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/**
+ * We want be able to delete messages and we to serialize objects
+ * via a getBody() and setBody()
+ *
+ * This is different that doing the serialization directly next to the object
+ * because you may want to update getBody() and setBody() to do a json
+ * conversion instead of a php serialize
+ *
+ * You could also just overload the Zend_Queue::send() and Zend_Queue::receive()
+ * functions to do the serialization/json encoding, but I wanted to give an
+ * good example that overloaded near everything except for the adapter.
+ */
+class Custom_Message extends Zend_Queue_Message
+{
+    /**
+     * We adjusted the constructor to accept both an array and an object.
+     */
+    public function __construct($mixed) {
+        // we still have to support the code in Zend_Queue::receive that
+        // passes in an array
+        if (is_array($mixed)) {
+            parent::__construct($mixed);
+        } elseif (is_object($mixed)) {
+            $this->setBody($mixed);
+            $this->_connected = false;
+        }
+    }
+
+    /**
+     * We need to get the underlying body as a string
+     *
+     * @return string
+     */
+    public function __toString() {
+        return $this->_data['body'];
+    }
+
+    /**
+     * Sets the message body
+     *
+     * @param serializable $mixed
+     */
+    public function setBody($mixed)
+    {
+        $this->_data['body'] = serialize($mixed);
+    }
+
+    /**
+     * Gets the message body
+     *
+     * @return $mixed
+     */
+    public function getBody()
+    {
+        return unserialize($this->_data['body']);
+    }
+
+    /**
+     * Deletes the message.
+     *
+     * Note you cannot be disconnected from queue.
+     *
+     * $throw is set to to true, because most of the time you want to know if
+     * there is an error.  However, in Custom_Messages::__destruct() exceptions
+     * cannot be thrown.
+     *
+     * These does not create a circular reference loop. Because deleteMessage
+     * asks the queue service to delete the message, the message located here
+     * is NOT deleted.
+     *
+     * @param boolean $throw defaults to true.  Throw a message if there is an error
+     *
+     * @throws Zend_Queue_Exception if not connected
+     */
+    public function delete($throw = true)
+    {
+        if ($this->_connected) {
+            if ($this->getQueue()->getAdapter()->isSupported('deleteMessage')) {
+                $this->getQueue()->deleteMessage($this);
+            }
+        } elseif ($throw) {
+            /**
+             * @see Zend_Queue_Exception
+             */
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('Disconnected from queue.  Cannot delete message from queue.');
+        }
+    }
+}

+ 181 - 0
tests/Zend/Queue/Custom/Messages.php

@@ -0,0 +1,181 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Custom
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: Iterator.php 14781 2009-04-09 07:07:24Z danlo $
+ */
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Custom
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+
+/**
+ * This class uses the SLP_ArrayIterator
+ * We are interested in overriding unset() to auto delete the message
+ */
+
+/** Zend_Queue_Message_Iterator */
+require_once('Zend/Queue/Message/Iterator.php');
+
+class Custom_Messages
+extends Zend_Queue_Message_Iterator
+implements ArrayAccess
+{
+    /**
+     * Constructor
+     *
+     * @param array $config ('queue', 'messageClass', 'data'=>array());
+     */
+    public function __construct(array $config=array())
+    {
+        if (isset($config['queue'])) {
+            $this->_queue = $config['queue'];
+            $this->_queueClass = get_class($this->_queue);
+            $this->_connected = true;
+        } else {
+            $this->_connected = false;
+        }
+
+        if (isset($config['messageClass'])) {
+            $this->_messageClass = $config['messageClass'];
+        }
+
+        if (isset($config['data']) && ! is_array($config['data'])) {
+            /**
+             * @see Zend_Queue_Exception
+             */
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('array configuration must have $config[\'data\'] = array');
+        }
+
+        // load the message class
+        $class = $this->_messageClass;
+        Zend_Loader::loadClass($class);
+
+        if (isset($config['data'])) {
+            // for each of the messages
+            foreach($config['data'] as $i => $data) {
+                // construct the message parameters
+                $message = array('data' => $data);
+
+                // If queue has not been set, then use the default.
+                if (empty($message['queue'])) {
+                    $message['queue'] = $this->_queue;
+                }
+
+                // construct the message and add it to _data[];
+                $this->_data[] = new $class($message);
+            }
+        }
+    }
+
+    /**
+     * Our destruct will delete all the messages in the queue
+     *
+     * Notice: if anything throws a message we are doomed.
+     * You cannot throw an error in an destructor
+     */
+    public function __destruct()
+    {
+        if ($this->_connected) {
+            foreach ($this->_data as $i => $value) {
+                $value->delete(false);
+            }
+        } else {
+            unset($this->_data);
+        }
+    }
+
+    /*
+     * ArrayIterator
+     */
+
+    /**
+     * @see SPL ArrayIterator::append
+     */
+    public function append($value) {
+        $this->_data[] = $value;
+    }
+
+    /*
+     * ArrayAccess
+     */
+
+    /**
+     * @see SPL ArrayAccess::offsetSet
+     */
+    public function offsetSet($offset, $value) {
+        if (! $value instanceof Custom_Message) {
+            $msg = '$value must be a child or an instance of Custom_Messag';
+            /**
+             * @see Zend_Queue_Exception
+             */
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception($msg);
+        }
+
+        $this->_data[$offset] = $value;
+        return $value;
+    }
+
+    /**
+     * @see SPL ArrayAccess::offsetGet
+     */
+    public function offsetGet($offset) {
+        return $this->_data[$offset];
+    }
+
+    /**
+     * @see SPL ArrayAccess::offsetUnset
+     */
+    public function offsetUnset($offset) {
+        if (! $this->_connected) {
+            $msg = 'Cannot delete message after serialization';
+            /**
+             * @see Zend_Queue_Exception
+             */
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception($msg);
+        }
+
+        $this->_data[$offset]->delete(); // Custom_Message added this function
+        unset($this->_data[$offset]);
+    }
+
+    /**
+     * @see SPL ArrayAccess::offsetExists
+     */
+    public function offsetExists($offset) {
+        return isSet($this->_data[$offset]);
+    }
+
+    /*
+     * SeekableIterator implementation
+     */
+
+    /**
+     * @see SPL SeekableIterator::seek
+     */
+    public function seek($index) {
+        $this->_pointer = $index;
+    }
+}

+ 98 - 0
tests/Zend/Queue/Custom/Queue.php

@@ -0,0 +1,98 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Custom
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * The adapter test class provides a universal test class for all of the
+ * abstract methods.
+ *
+ * All methods marked not supported are explictly checked for for throwing
+ * an exception.
+ */
+
+/** Zend_Queue */
+require_once 'Zend/Queue.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue/Message.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage Custom
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+class Custom_Queue extends Zend_Queue
+{
+    /**
+     * Constructor
+     *
+     * Can be called as
+     * $queue = new Zend_Queue($config);
+     * - or -
+     * $queue = new Zend_Queue('array', $config);
+     * - or -
+     * $queue = new Zend_Queue(null, $config); // Zend_Queue->createQueue();
+     *
+     * @param Zend_Queue_Adapter_Abstract|string $adapter adapter object or class name
+     * @param Zend_Config|array  $config Zend_Config or an configuration array
+     */
+    public function __construct()
+    {
+        $args = func_get_args();
+        call_user_func_array(array($this, 'parent::__construct'), $args);
+
+        $this->setMessageClass('Custom_Message');
+        $this->setMessageSetClass('Custom_Messages');
+
+        $this->getLogger()->debug('Succcessfully created class: ' . get_class($this));
+    }
+
+    /**
+     * Send a message to the queue
+     *
+     * @param  Custom_Message|Custom_Messages $message message
+     * @return $this
+     * @throws Zend_Queue_Exception
+     */
+    public function send($message)
+    {
+        if (! ($message instanceof Custom_Message || $message instanceof Custom_Messages) ) {
+            /**
+             * @see Zend_Queue_Exception
+             */
+            require_once 'Zend/Queue/Exception.php';
+            throw new Zend_Queue_Exception('$message must be an instance of Custom_Message or Custom_Messages');
+        }
+        if ($message instanceof Custom_Message) {
+            $response = parent::send($message->__toString());
+        } else {
+            foreach($message as $i => $one) {
+                $response = parent::send($one->__toString());
+            }
+        }
+
+        return $this;
+    }
+}

+ 161 - 0
tests/Zend/Queue/CustomTest.php

@@ -0,0 +1,161 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * This test code tests the customization functions provided in the example
+ * documentation code.
+ */
+
+/** PHPUnit Test Case */
+require_once 'PHPUnit/Framework/TestCase.php';
+
+/** TestHelp.php */
+require_once dirname(__FILE__) . '/../../TestHelper.php';
+
+/** Custom_Queue */
+require_once 'Custom/Queue.php';
+
+/** Custom_Message */
+require_once 'Custom/Message.php';
+
+/** Custom_Messages */
+require_once 'Custom/Messages.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+class Custom_Object {
+    public $a;
+
+    public function __construct()
+    {
+        $a = rand(1,200);
+    }
+
+    public function getA()
+    {
+        return $this->a;
+    }
+
+    public function setA($a)
+    {
+        $this->a = $a;
+    }
+
+    public function __sleep()
+    {
+        return array('a'); // serialize only this variable
+    }
+}
+
+class Zend_Queue_CustomTest extends PHPUnit_Framework_TestCase
+{
+    public function test_behavior()
+    {
+        $object_count = 10;
+        $objects = array();
+
+        $queue = new Custom_Queue('Array', array('name'=>'ObjectA'));
+        $this->assertTrue($queue instanceof Custom_Queue);
+
+        // ------------------------------------------------ send
+
+        // add items $objects[0-4]
+        $objects = array();
+        for ($i = 0; $i < $object_count-5; $i++) {
+            $object = new Custom_Object();
+            $queue->send(new Custom_Message($object));
+            $objects[] = $object;
+        }
+
+        // add items $objects[5-9]
+        $messages = new Custom_Messages();
+        for ($i = 0; $i < 5; $i++) {
+            $object = new Custom_Object();
+            $messages->append( new Custom_Message($object));
+            $objects[] = $object;
+        }
+        $queue->send($messages);
+
+        $this->assertEquals($object_count, count($queue));
+        unset($messages);
+
+        // ------------------------------------------------ receive
+
+        // get the first 5 doing 0-4
+        $receive = $queue->receive(5);
+        $this->assertTrue($receive instanceof Custom_Messages);
+        $this->assertEquals(5, count($receive));
+
+        // test them
+        for ($index = 0; $index < 5; $index++) {
+            $this->assertEquals($objects[$index]->getA(), $receive[$index]->getBody()->getA());
+            try {
+                unset($receive[$index]);
+                $this->assertTrue(true, '$receive[$index] successfully deleted');
+            } catch(Zend_Queue_Exception $e) {
+                $this->fail('$receive[$index] should have been deleted' . $e->getMessage());
+            }
+        }
+        // there should only be 5 objects left
+        $this->assertEquals($object_count - $index, count($queue));
+
+        // get 1 doing $objects[5]
+        $receive = $queue->receive();
+        $index++;
+        $this->assertTrue($receive instanceof Custom_Messages);
+        $this->assertEquals(1, count($receive));
+
+        // testing Custom_Messages::__deconstruct()
+        unset($receive);
+        $this->assertEquals($object_count - $index, count($queue));
+
+
+        // get all the rest doing 6-20
+        $receive = $queue->receive($object_count - $index);
+        $this->assertTrue($receive instanceof Custom_Messages);
+        $this->assertEquals($object_count - $index, count($receive));
+
+        // test them
+        $r_index = -1;
+        for (; $index < $object_count; $index++) {
+            $r_index++;
+            $this->assertEquals($objects[$index]->getA(), $receive[$r_index]->getBody()->getA());
+
+            try {
+                unset($receive[$r_index]);
+                $this->assertTrue(true, '$receive[$index] successfully deleted');
+            } catch(Zend_Queue_Exception $e) {
+                $this->fail('$receive[$index] should have been deleted' . $e->getMessage());
+            }
+        }
+
+        // auto-delete should have been called on $receive
+        $this->assertEquals(0, count($queue));
+    }
+}

+ 107 - 0
tests/Zend/Queue/FactoryTest.php

@@ -0,0 +1,107 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/** PHPUnit Test Case */
+require_once 'PHPUnit/Framework/TestCase.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue.php';
+
+/** Zend_Queue_Exception */
+require_once 'Zend/Queue/Exception.php';
+
+/** Zend_Queue_Adapter_* */
+require_once 'Zend/Queue/Adapter/Array.php';
+require_once 'Zend/Queue/Adapter/Db.php';
+require_once 'Zend/Queue/Adapter/Memcacheq.php';
+require_once 'Zend/Queue/Adapter/Apachemq.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+class Zend_Queue_FactoryTest extends PHPUnit_Framework_TestCase
+{
+    protected function setUp()
+    {
+        date_default_timezone_set('GMT');
+    }
+
+    public function testDb()
+    {
+        $this->markTestSkipped('Db setup required');
+
+        $config = array('name'           => 'queue1',
+                        'driverOptions' => array('host'     => 'db1.domain.tld',
+                                                 'username' => 'my_username',
+                                                 'password' => 'my_password',
+                                                 'dbname'   => 'messaging',
+                                                 'type'     => 'pdo_mysql',
+                                                 'port'     => 3306)); // optional parameter
+
+        $adapter = new Zend_Queue('Db', $config);
+
+        $this->assertTrue($adapter instanceof Zend_Queue);
+    }
+
+    public function testMemcacheq()
+    {
+        $this->markTestSkipped('MemcacheQ setup required');
+
+        $config = array('name'           => 'queue1',
+                        'driverOptions' => array('host' => 'memcacheq.domain.tld',
+                                                 'port' => 22201));
+
+        $adapter = new Zend_Queue('Memcacheq', $config);
+
+        $this->assertTrue($adapter instanceof Zend_Queue);
+    }
+
+    public function testApachemq()
+    {
+        $this->markTestSkipped('Stomp setup required');
+
+        $config = array('name'           => 'queue1',
+                        'driverOptions' => array('host'     => 'msg.domain.tld',
+                                                 'port'     => 61613,
+                                                 'username' => 'username',
+                                                 'password' => 'password'));
+
+        $adapter = new Zend_Queue('Stomp', $config);
+
+        $this->assertTrue($adapter instanceof Zend_Queue);
+    }
+
+    public function testArray()
+    {
+        $config = array('name' => 'queue1',
+                        'driverOptions' => array());
+
+        $adapter = new Zend_Queue('Array', $config);
+
+        $this->assertTrue($adapter instanceof Zend_Queue);
+    }
+}

+ 168 - 0
tests/Zend/Queue/Message/IteratorTest.php

@@ -0,0 +1,168 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * The adapter test class provides a universal test class for all of the
+ * abstract methods.
+ *
+ * All methods marked not supported are explictly checked for for throwing
+ * an exception.
+ */
+
+/** TestHelp.php */
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue/Message.php';
+
+/** Zend_Queue_Adapter_Array */
+require_once 'Zend/Queue/Adapter/Array.php';
+/** Zend_Queue_Adapter_Null */
+require_once 'Zend/Queue/Adapter/Null.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+class Zend_Queue_Message_IteratorTest extends PHPUnit_Framework_TestCase
+{
+    protected function setUp()
+    {
+        // Test Zend_Config
+        $this->options = array(
+            'name'      => 'queue1',
+            'params'    => array(),
+        );
+
+        $this->queue = new Zend_Queue('array', $this->options);
+
+        // construct messages
+        $this->message_count = 5;
+        $data  = array();
+        $datum = array();
+        for ($i = 0; $i < $this->message_count; $i++) {
+            $data[] = array(
+                'id' => $i+1,
+                'handle' => null,
+                'body' => 'Hello world' // This is my 2524'th time writing that.
+            );
+        }
+
+        $options = array(
+            'queue'    => $this->queue,
+            'data'     => $data,
+            'messageClass' => $this->queue->getMessageClass()
+        );
+
+        $classname = $this->queue->getMessageSetClass();
+        if (!class_exists($classname)) {
+            require_once 'Zend/Loader.php';
+            Zend_Loader::loadClass($classname);
+        }
+        $this->messages = new $classname($options);
+    }
+
+
+    public function test_setup()
+    {
+        $this->assertTrue($this->queue instanceof Zend_Queue);
+        $this->assertTrue(is_array($this->options));
+
+        foreach ($this->messages as $i => $message) {
+            $this->assertTrue($message instanceof Zend_Queue_Message);
+            $this->assertEquals('Hello world', $message->body);
+        }
+    }
+
+    protected function tearDown()
+    {
+    }
+
+    public function testConstruct()
+    {
+        $this->assertTrue($this->messages instanceof Zend_Queue_Message_Iterator);
+
+        // parameter validation
+        try {
+            $config = $this->options;
+            $config['data']='ops';
+
+            $classname = $this->queue->getMessageSetClass();
+            Zend_Loader::loadClass($classname);
+            $this->messages = new $classname($config);
+            $this->fail('config[data] must be an array.  a message should have been thrown');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+    }
+
+    public function test_count()
+    {
+        $this->assertEquals($this->message_count, count($this->messages));
+    }
+
+    public function test_magic()
+    {
+        $this->assertTrue(is_array($this->messages->__sleep()));
+
+        $messages = serialize($this->messages);
+        $woken = unserialize($messages);
+        $this->assertEquals($this->messages->current()->body, $woken->current()->body);
+    }
+
+    public function test_get_setQueue()
+    {
+        $queue = $this->messages->getQueue();
+        $this->assertTrue($queue instanceof Zend_Queue);
+
+        $this->assertTrue($this->messages->setQueue($queue));
+    }
+
+    public function test_getQueueClass()
+    {
+        $this->assertEquals(get_class($this->queue), $this->messages->getQueueClass());
+    }
+
+    public function test_iterator()
+    {
+        foreach ($this->messages as $i => $message) {
+            $this->assertEquals('Hello world', $message->body);
+        }
+    }
+
+    public function test_toArray()
+    {
+        $array = $this->messages->toArray();
+        $this->assertTrue(is_array($array));
+        $this->assertEquals($this->message_count, count($array));
+        $this->assertEquals('Hello world', $array[0]['body']);
+    }
+
+}

+ 206 - 0
tests/Zend/Queue/MessageTest.php

@@ -0,0 +1,206 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * The adapter test class provides a universal test class for all of the
+ * abstract methods.
+ *
+ * All methods marked not supported are explictly checked for for throwing
+ * an exception.
+ */
+
+/** PHPUnit Test Case */
+require_once 'PHPUnit/Framework/TestCase.php';
+
+/** TestHelp.php */
+require_once dirname(__FILE__) . '/../../TestHelper.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue/Message.php';
+
+/** Zend_Queue_Adapter_Array */
+require_once 'Zend/Queue/Adapter/Array.php';
+/** Zend_Queue_Adapter_Null */
+require_once 'Zend/Queue/Adapter/Null.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+class Zend_Queue_MessageTest extends PHPUnit_Framework_TestCase
+{
+    protected function setUp()
+    {
+        // Test Zend_Config
+        $this->options = array(
+            'name'      => 'queue1',
+            'params'    => array(),
+        );
+
+        $this->queue = new Zend_Queue('array', $this->options);
+
+        $this->data = array(
+            'id'     => 123,
+            'handle' => 567,
+            'body'   => 'Hello world' // This is my 2524'th time writing that.
+        );
+
+        $this->options = array(
+            'queue'     => $this->queue,
+            'data'      => $this->data,
+        );
+
+        $this->message = new Zend_Queue_Message($this->options);
+    }
+
+    protected function tearDown()
+    {
+    }
+
+    public function testConstruct()
+    {
+        try {
+            $message = new Zend_Queue_Message($this->options);
+            $this->assertTrue(true);
+        } catch (Exception $e) {
+            $this->fail('should have gotten a valid object');
+        }
+
+        // parameter verification
+        try {
+            $config2 = $this->options;
+            $config2['queue'] = 'weee';
+            $message = new Zend_Queue_Message($config2);
+            $this->fail('should have thrown an exception bad queue var');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $config2 = $this->options;
+            $config2['data'] = 'weee';
+            $message = new Zend_Queue_Message($config2);
+            $this->fail('should have thrown an exception bad queue var');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+    }
+
+    public function testMagic()
+    {
+        $this->assertEquals(123, $this->message->__get('id'));
+        $this->assertEquals(123, $this->message->id);
+        $this->assertEquals('Hello world', $this->message->body);
+        $this->message->__set('id', 'abc');
+        $this->assertEquals('abc', $this->message->__get('id'));
+        $this->assertTrue($this->message->__isset('id'));
+
+        try {
+            $this->message->__get('hello world');
+            $this->fail('key is NOT in variable, should have thrown an exception');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $this->message->__set('hello world', 'good bye');
+            $this->fail('key is NOT in variable, should have thrown an exception');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $message = new Zend_Queue_Message($this->options);
+            $this->assertTrue(true);
+        } catch (Exception $e) {
+            $this->fail('should have gotten a valid object');
+        }
+
+        // parameter verification
+        try {
+            $config2 = $this->options;
+            $config2['queue'] = 'weee';
+            $message = new Zend_Queue_Message($config2);
+            $this->fail('should have thrown an exception bad queue var');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $config2 = $this->options;
+            $config2['data'] = 'weee';
+            $message = new Zend_Queue_Message($config2);
+            $this->fail('should have thrown an exception bad queue var');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+    }
+
+    public function test_set_getQueue()
+    {
+        $this->assertTrue($this->message->getQueue() instanceof Zend_Queue);
+
+        $class = $this->message->getQueueClass();
+        $this->assertEquals('Zend_Queue', $class);
+
+        $this->assertTrue($this->message->setQueue($this->message->getQueue()));
+
+        // parameter verification
+
+        try {
+            $null = new Zend_Queue('Null', array());
+            $this->message->setQueue($null);
+            $this->fail('invalid class passed to setQueue()');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+    }
+
+    public function test_array()
+    {
+        $array = $this->message->toArray();
+        $this->assertTrue(is_array($array));
+
+        $array['id'] = 'hello';
+        $this->message->setFromArray($array);
+
+        $this->assertEquals('hello', $this->message->id);
+    }
+
+    public function test_magic()
+    {
+        $this->assertTrue(is_array($this->message->__sleep()));
+
+        $message = serialize($this->message);
+        $woken = unserialize($message);
+        $this->assertEquals($this->message->body, $woken->body);
+    }
+
+}

+ 62 - 0
tests/Zend/Queue/Queue1Test.php

@@ -0,0 +1,62 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * The adapter test class provides a universal test class for all of the
+ * abstract methods.
+ *
+ * All methods marked not supported are explictly checked for for throwing
+ * an exception.
+ */
+
+/** PHPUnit Test Case */
+require_once 'PHPUnit/Framework/TestCase.php';
+
+/** TestHelp.php */
+require_once dirname(__FILE__) . '/../../TestHelper.php';
+
+/** Zend_Queue_Queue2Test */
+require_once 'Zend/Queue/QueueBaseTest.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+class Zend_Queue_Queue1Test extends Zend_Queue_QueueBaseTest
+{
+    protected function setUp()
+    {
+        date_default_timezone_set('GMT');
+
+        // Test Zend_Config
+        $this->config = array(
+            'name'      => 'queue1'
+        );
+
+        $this->queue = new Zend_Queue('Array', $this->config);
+    }
+}

+ 60 - 0
tests/Zend/Queue/Queue2Test.php

@@ -0,0 +1,60 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * The adapter test class provides a universal test class for all of the
+ * abstract methods.
+ *
+ * All methods marked not supported are explictly checked for for throwing
+ * an exception.
+ */
+
+/** PHPUnit Test Case */
+require_once 'PHPUnit/Framework/TestCase.php';
+
+/** TestHelp.php */
+require_once dirname(__FILE__) . '/../../TestHelper.php';
+
+/** Zend_Queue_Queue2Test */
+require_once 'Zend/Queue/QueueBaseTest.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+class Zend_Queue_Queue2Test extends Zend_Queue_QueueBaseTest
+{
+    protected function setUp()
+    {
+        // Test Zend_Config
+        $this->config = array(
+            'name'      => 'queue1'
+        );
+
+        $this->queue = new Zend_Queue('Null', $this->config);
+    }
+}

+ 274 - 0
tests/Zend/Queue/QueueBaseTest.php

@@ -0,0 +1,274 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * The adapter test class provides a universal test class for all of the
+ * abstract methods.
+ *
+ * All methods marked not supported are explictly checked for for throwing
+ * an exception.
+ */
+
+/** TestHelper.php */
+require_once dirname(__FILE__) . '/../../TestHelper.php';
+
+/** Zend_Config */
+require_once 'Zend/Config.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue/Message.php';
+
+/** Zend_Queue_Adapter_Array */
+require_once 'Zend/Queue/Adapter/Array.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+abstract class Zend_Queue_QueueBaseTest extends PHPUnit_Framework_TestCase
+{
+    protected function setUp()
+    {
+        // Test Zend_Config
+        $this->config = array(
+            'name'      => 'queue1',
+        );
+
+        $this->queue = new Zend_Queue('Null', $this->config);
+    }
+
+    protected function tearDown()
+    {
+    }
+
+    public function testConst()
+    {
+        $this->assertTrue(is_string(Zend_Queue::TIMEOUT));
+        $this->assertTrue(is_integer(Zend_Queue::VISIBILITY_TIMEOUT));
+        $this->assertTrue(is_string(Zend_Queue::NAME));
+    }
+
+    /**
+     * Constructor
+     *
+     * @param string|Zend_Queue_Adapter_Abstract $adapter
+     * @param array  $config
+     */
+    public function testConstruct()
+    {
+        // Test Zend_Config
+        $config = array(
+            'name'      => 'queue1',
+            'params'    => array(),
+            'adapter'   => 'array'
+        );
+
+        $zend_config = new Zend_Config($config);
+
+        $obj = new Zend_Queue($config);
+        $this->assertTrue($obj instanceof Zend_Queue);
+
+        $obj = new Zend_Queue($zend_config);
+        $this->assertTrue($obj instanceof Zend_Queue);
+
+        try {
+            $obj = new Zend_Queue('ops');
+            $this->fail('Zend_Queue cannot accept a string');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+    }
+
+    public function testDebugInfo()
+    {
+        $this->assertTrue(is_array($this->queue->debugInfo()));
+        // var_dump($this->queue->debugInfo());
+    }
+
+    public function testGetOptions()
+    {
+        $options = $this->queue->getOptions();
+        $this->assertTrue(is_array($options));
+        $this->assertEquals($this->config['name'], $options['name']);
+    }
+
+    public function testSetAndGetAdapter()
+    {
+        $adapter = new Zend_Queue_Adapter_Array($this->config);
+        $this->assertTrue($this->queue->setAdapter($adapter) instanceof Zend_Queue);
+        $this->assertTrue($this->queue->getAdapter($adapter) instanceof Zend_Queue_Adapter_Array);
+    }
+
+    public function testSetAndGetMessageClass()
+    {
+        $class = 'test';
+        $this->assertTrue($this->queue->setMessageClass($class) instanceof Zend_Queue);
+        $this->assertEquals($class, $this->queue->getMessageClass());
+    }
+
+    public function testSetAndGetMessageSetClass()
+    {
+        $class = 'test';
+        $this->assertTrue($this->queue->setMessageSetClass($class) instanceof Zend_Queue);
+        $this->assertEquals($class, $this->queue->getMessageSetClass());
+    }
+
+    public function testSetAndGetName()
+    {
+        $this->assertEquals($this->config['name'], $this->queue->getName());
+    }
+
+    public function testCreateAndDeleteQueue()
+    {
+        // parameter testing
+        try {
+            $this->queue->createQueue(array());
+            $this->fail('createQueue() $name must be a string');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $this->queue->createQueue('test', 'test');
+            $this->fail('createQueue() $timeout must be an integer');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        // isExists
+        $queue = 'test';
+        $new = $this->queue->createQueue($queue);
+        $this->assertTrue($new instanceof Zend_Queue);
+
+        // createQueue() will return true if the adapter cannot
+        // do isExist($queue);
+        // $this->assertFalse($this->queue->createQueue($queue));
+
+        if ($new->isSupported('deleteQueue')) {
+            $this->assertTrue($new->deleteQueue());
+        }
+    }
+
+    public function testSendAndCountAndReceiveAndDeleteMessage()
+    {
+        if (! $this->queue->isSupported('send')
+            && ! $this->queue->isSupported('receive')
+            && ! $this->queue->isSupported('count')) {
+            $this->markTestSkipped('send/count/receive are not supported');
+            return;
+        }
+
+        // ------------------------------------ send()
+        // parameter verification
+        try {
+            $this->queue->send(array());
+            $this->fail('send() $mesage must be a string');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        $message = 'Hello world'; // never gets boring!
+        $this->assertTrue($this->queue->send($message) instanceof Zend_Queue_Message);
+
+        // ------------------------------------ count()
+        $this->assertEquals($this->queue->count(), 1);
+
+        // ------------------------------------ receive()
+        // parameter verification
+        try {
+            $this->queue->receive(array());
+            $this->fail('receive() $maxMessages must be a integer or null');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $this->queue->receive(1, array());
+            $this->fail('receive() $timeout must be a integer or null');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        $messages = $this->queue->receive();
+        $this->assertTrue($messages instanceof Zend_Queue_Message_Iterator);
+
+        // ------------------------------------ deleteMessage()
+        foreach ($messages as $i => $message) {
+            $this->assertTrue($this->queue->deleteMessage($message));
+        }
+    }
+
+    public function testCapabilities()
+    {
+        $list = $this->queue->getCapabilities();
+        $this->assertTrue(is_array($list));
+
+        // these functions must have an boolean answer
+        $func = array(
+            'create', 'delete', 'send', 'receive',
+            'deleteMessage', 'getQueues', 'count',
+            'isExists'
+        );
+
+        foreach ( array_values($func) as $f ) {
+            $this->assertTrue(isset($list[$f]));
+            $this->assertTrue(is_bool($list[$f]));
+        }
+    }
+
+    public function testIsSupported()
+    {
+        $list = $this->queue->getCapabilities();
+        foreach ( $list as $function => $result ) {
+            $this->assertTrue(is_bool($result));
+            if ( $result ) {
+                $this->assertTrue($this->queue->isSupported($function));
+            } else {
+                $this->assertFalse($this->queue->isSupported($function));
+            }
+        }
+    }
+
+    public function testGetQueues()
+    {
+        if ($this->queue->isSupported('getQueues')) {
+            $queues = $this->queue->getQueues();
+            $this->assertTrue(is_array($queues));
+            $this->assertTrue(in_array($this->config['name'], $queues));
+        } else {
+            try {
+                $queues = $this->queue->getQueues();
+                $this->fail('getQueues() should have thrown an error');
+            } catch (Exception $e) {
+                $this->assertTrue(true);
+            }
+        }
+    }
+}

+ 290 - 0
tests/Zend/Queue/QueueTest.php

@@ -0,0 +1,290 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * The adapter test class provides a universal test class for all of the
+ * abstract methods.
+ *
+ * All methods marked not supported are explictly checked for for throwing
+ * an exception.
+ */
+
+/** PHPUnit Test Case */
+require_once 'PHPUnit/Framework/TestCase.php';
+
+/** TestHelp.php */
+require_once dirname(__FILE__) . '/../../TestHelper.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue.php';
+
+/** Zend_Queue */
+require_once 'Zend/Queue/Message.php';
+
+/** Zend_Queue_Adapter_Array */
+require_once 'Zend/Queue/Adapter/Array.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+class Zend_Queue_QueueTest extends PHPUnit_Framework_TestCase
+{
+    protected function setUp()
+    {
+        // Test Zend_Config
+        $this->config = array(
+            'name'      => 'queue1',
+            'params'    => array(),
+        );
+
+        $this->queue = new Zend_Queue('array', $this->config);
+
+        /**
+         * @see Zend_Log
+         */
+        require_once 'Zend/Log.php';
+        require_once 'Zend/Log/Writer/Stream.php';
+        require_once 'Zend/Log/Writer/Null.php';
+        if (! isset($this->logger)) {
+            if (1) { // vebose?
+                $this->_logger = new Zend_Log(new Zend_Log_Writer_Stream('php://output'));
+            } else {
+                $this->_logger = new Zend_Log(new Zend_Log_Writer_Null());
+            }
+        }
+
+        $this->queue->setLogger($this->_logger);
+    }
+
+    protected function tearDown()
+    {
+    }
+
+    public function testConst()
+    {
+        $this->assertTrue(is_string(Zend_Queue::TIMEOUT));
+        $this->assertTrue(is_integer(Zend_Queue::VISABILITY_TIMEOUT));
+        $this->assertTrue(is_string(Zend_Queue::NAME));
+    }
+
+    /**
+     * Constructor
+     *
+     * @param string|Zend_Queue_Adapter_Abstract $adapter
+     * @param array  $config
+     */
+    public function testConstruct()
+    {
+        // Test Zend_Config
+        $config = array(
+            'name'      => 'queue1',
+            'params'    => array(),
+            'adapter'   => 'array'
+        );
+
+        $zend_config = new Zend_Config($config);
+
+        $obj = new Zend_Queue($config);
+        $this->assertTrue($obj instanceof Zend_Queue);
+
+        // test logger
+        $this->assertTrue($obj->getLogger() instanceof Zend_Log);
+
+        $obj = new Zend_Queue($zend_config);
+        $this->assertTrue($obj instanceof Zend_Queue);
+
+        try {
+            $obj = new Zend_Queue('ops');
+            $this->fail('Zend_Queue cannot accept a string');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+    }
+
+    public function test_getConfig()
+    {
+        $config = $this->queue->getConfig();
+        $this->assertTrue(is_array($config));
+        $this->assertEquals($this->config['name'], $config['name']);
+    }
+
+    public function test_set_getAdapter()
+    {
+        $adapter = new Zend_Queue_Adapter_Array($this->config);
+        $this->assertTrue($this->queue->setAdapter($adapter) instanceof Zend_Queue);
+        $this->assertTrue($this->queue->getAdapter($adapter) instanceof Zend_Queue_Adapter_Array);
+    }
+
+    public function test_set_getMessageClass()
+    {
+        $class = 'test';
+        $this->assertTrue($this->queue->setMessageClass($class) instanceof Zend_Queue);
+        $this->assertEquals($class, $this->queue->getMessageClass());
+    }
+
+    public function test_set_getMessageSetClass()
+    {
+        $class = 'test';
+        $this->assertTrue($this->queue->setMessageSetClass($class) instanceof Zend_Queue);
+        $this->assertEquals($class, $this->queue->getMessageSetClass());
+    }
+
+    public function test_set_getName()
+    {
+        // $this->assertTrue($this->queue->setName($new) instanceof Zend_Queue);
+        $this->assertEquals($this->config['name'], $this->queue->getName());
+    }
+
+    public function test_create_deleteQueue()
+    {
+        // parameter testing
+        try {
+            $this->queue->createQueue(array());
+            $this->fail('createQueue() $name must be a string');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $this->queue->createQueue('test', 'test');
+            $this->fail('createQueue() $timeout must be an integer');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        // isExists
+        $queue = 'test';
+        $new = $this->queue->createQueue($queue);
+        $this->assertTrue($new instanceof Zend_Queue);
+        $this->assertFalse($this->queue->createQueue($queue));
+
+        $this->assertTrue($new->deleteQueue());
+    }
+
+    public function test_send_count_receive_deleteMessage()
+    {
+        // ------------------------------------ send()
+        // parameter verification
+        try {
+            $this->queue->send(array());
+            $this->fail('send() $mesage must be a string');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        $message = 'Hello world'; // never gets boring!
+        $this->assertTrue($this->queue->send($message) instanceof Zend_Queue_Message);
+
+        // ------------------------------------ count()
+        $this->assertEquals($this->queue->count(), 1);
+
+        // ------------------------------------ receive()
+        // parameter verification
+        try {
+            $this->queue->receive(array());
+            $this->fail('receive() $maxMessages must be a integer or null');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $this->queue->receive(1, array());
+            $this->fail('receive() $timeout must be a integer or null');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        $messages = $this->queue->receive();
+        $this->assertTrue($messages instanceof Zend_Queue_Message_Iterator);
+
+        // ------------------------------------ deleteMessage()
+        foreach ($messages as $i => $message) {
+            $this->assertTrue($this->queue->deleteMessage($message));
+        }
+    }
+
+    public function test_set_getLogger()
+    {
+        /**
+         * @see Zend_Log
+         */
+        require_once 'Zend/Log.php';
+        require_once 'Zend/Log/Writer/Null.php';
+
+        $logger = new Zend_Log(new Zend_Log_Writer_Null);
+
+        $this->assertTrue($this->queue->setLogger($logger) instanceof Zend_Queue);
+        $this->assertTrue($this->queue->getLogger() instanceof Zend_Log);
+
+        // parameter verification
+        try {
+            $this->queue->setLogger(array());
+            $this->fail('setlogger() passed an array and succeeded (bad)');
+        } catch (Exception $e) {
+            $this->assertTrue(true);
+        }
+    }
+
+    public function test_capabilities()
+    {
+        $list = $this->queue->getCapabilities();
+        $this->assertTrue(is_array($list));
+
+        // these functions must have an boolean answer
+        $func = array(
+            'create', 'delete', 'send', 'receive',
+            'deleteMessage', 'getQueues', 'count',
+            'isExists'
+        );
+
+        foreach ( array_values($func) as $f ) {
+            $this->assertTrue(isset($list[$f]));
+            $this->assertTrue(is_bool($list[$f]));
+        }
+    }
+
+    public function test_isSupported()
+    {
+        $list = $this->queue->getCapabilities();
+        foreach ( $list as $function => $result ) {
+            $this->assertTrue(is_bool($result));
+            if ( $result ) {
+                $this->assertTrue($this->queue->isSupported($function));
+            } else {
+                $this->assertFalse($this->queue->isSupported($function));
+            }
+        }
+    }
+
+    public function test_getQueues()
+    {
+        $queues = $this->queue->getQueues();
+        $this->assertTrue(is_array($queues));
+        $this->assertTrue(in_array($this->config['name'], $queues));
+    }
+}

+ 154 - 0
tests/Zend/Queue/Stomp/ClientTest.php

@@ -0,0 +1,154 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * The adapter test class provides a universal test class for all of the
+ * abstract methods.
+ *
+ * All methods marked not supported are explictly checked for for throwing
+ * an exception.
+ */
+
+/** TestHelp.php */
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+
+/** Zend_Queue_Stomp_Frame */
+require_once 'Zend/Queue/Stomp/Frame.php';
+
+/** Zend_Queue_Stomp_Client */
+require_once 'Zend/Queue/Stomp/Client.php';
+
+/** Zend_Queue_Stomp_Client_Interface */
+require_once 'Zend/Queue/Stomp/Client/Connection.php';
+
+class Zend_Queue_Stomp_Connection_Mock
+    extends Zend_Queue_Stomp_Client_Connection
+{
+    /**
+     * open() opens a socket to the Stomp server
+     *
+     * @param array $config ('scheme', 'host', 'port')
+     * @return true;
+     */
+    public function open($scheme, $host, $port)
+    {
+        if ( $port == 0 )  return false;
+        return true;
+    }
+
+    public function close($destructor = false)
+    {
+    }
+
+    /**
+     * Check whether we are connected to the server
+     *
+     * @return true
+     * @throws Zend_Queue_Exception
+     */
+    public function ping()
+    {
+        return true;
+    }
+
+    /**
+     * write a frame to the stomp server
+     *
+     * @example $response = $client->write($frame)->read();
+     *
+     * @param Zend_Queue_Stom_Frame $frame
+     * @return $this
+     */
+    public function write(Zend_Queue_Stomp_FrameInterface $frame)
+    {
+        $this->_buffer[] = $frame;
+    }
+
+    /**
+     * tests the socket to see if there is data for us
+     */
+    public function canRead()
+    {
+        return count($this->_buffer) > 0;
+    }
+
+    /**
+     * reads in a frame from the socket or returns false.
+     *
+     * @return Zend_Queue_Stomp_Frame|false
+     * @throws Zend_Queue_Exception
+     */
+    public function read()
+    {
+        if (! $this->canRead()) return false;
+        return array_shift($this->_buffer);
+    }
+}
+
+class Zend_Queue_Stomp_ClientTest extends PHPUnit_Framework_TestCase
+{
+    public function testConstruct()
+    {
+        $client = new Zend_Queue_Stomp_Client('tcp', 'localhost', '11232', 'Zend_Queue_Stomp_Connection_Mock');
+        $this->assertTrue($client->getConnection() instanceof Zend_Queue_Stomp_Client_ConnectionInterface);
+    }
+
+    public function testAddConnection()
+    {
+        $client = new Zend_Queue_Stomp_Client();
+        $client->addConnection('tcp', 'localhost', '11232', 'Zend_Queue_Stomp_Connection_Mock');
+        $this->assertTrue($client->getConnection() instanceof Zend_Queue_Stomp_Client_ConnectionInterface);
+
+        $client = new Zend_Queue_Stomp_Client();
+        $this->assertFalse($client->addConnection('tcp', 'localhost', 0, 'Zend_Queue_Stomp_Connection_Mock'));
+    }
+
+    public function testGetAndSetConnection()
+    {
+        $connection = new Zend_Queue_Stomp_Connection_Mock('tcp', 'localhost', '11232');
+
+        $client = new Zend_Queue_Stomp_Client();
+        $this->assertTrue($client->setConnection($connection) instanceof Zend_Queue_Stomp_Client);
+
+        $try = $client->getConnection();
+        $this->assertEquals($connection, $try);
+    }
+
+    public function testSendAndReceive()
+    {
+        $frame = new Zend_Queue_Stomp_Frame();
+        $frame->setCommand('testing');
+        $frame->setHeader('testing',1);
+        $frame->setBody('hello world');
+
+        $client = new Zend_Queue_Stomp_Client();
+        $client->addConnection('tcp', 'localhost', '11232', 'Zend_Queue_Stomp_Connection_Mock');
+
+        $client->send($frame);
+        $this->assertTrue($client->canRead());
+        $test = $client->receive();
+
+        $this->assertEquals('testing', $test->getCommand());
+        $this->assertEquals(1, $test->getHeader('testing'));
+        $this->assertEquals('hello world', $test->getBody());
+    }
+}

+ 149 - 0
tests/Zend/Queue/Stomp/FrameTest.php

@@ -0,0 +1,149 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Queue
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2008 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 13626 2009-01-14 18:24:57Z matthew $
+ */
+
+/*
+ * The adapter test class provides a universal test class for all of the
+ * abstract methods.
+ *
+ * All methods marked not supported are explictly checked for for throwing
+ * an exception.
+ */
+
+/** PHPUnit Test Case */
+require_once 'PHPUnit/Framework/TestCase.php';
+
+/** TestHelp.php */
+require_once dirname(__FILE__) . '/../../../TestHelper.php';
+
+/** Zend/Queue/Stomp/Frame.php */
+require_once 'Zend/Queue/Stomp/Frame.php';
+
+class Zend_Queue_Stomp_FrameTest extends PHPUnit_Framework_TestCase
+{
+
+    protected $body = 'hello world'; // 11 characters
+
+    public function test_to_fromFrame()
+    {
+        $correct = 'SEND' . Zend_Queue_Stomp_Frame::EOL;
+        $correct .= 'content-length: 11' . Zend_Queue_Stomp_Frame::EOL;
+        $correct .= Zend_Queue_Stomp_Frame::EOL;
+        $correct .= $this->body;
+        $correct .= Zend_Queue_Stomp_Frame::END_OF_FRAME;
+
+        $frame = new Zend_Queue_Stomp_Frame();
+        $frame->setCommand('SEND');
+        $frame->setBody($this->body);
+        $this->assertEquals($frame->toFrame(), $correct);
+
+        $frame = new Zend_Queue_Stomp_Frame();
+        $frame->fromFrame($correct);
+        $this->assertEquals($frame->getCommand(), 'SEND');
+        $this->assertEquals($frame->getBody(), $this->body);
+
+        $this->assertEquals($frame->toFrame(), "$frame");
+
+        // fromFrame, but no body
+        $correct = 'SEND' . Zend_Queue_Stomp_Frame::EOL;
+        $correct .= 'testing: 11' . Zend_Queue_Stomp_Frame::EOL;
+        $correct .= Zend_Queue_Stomp_Frame::EOL;
+        $correct .= Zend_Queue_Stomp_Frame::END_OF_FRAME;
+        $frame->fromFrame($correct);
+        $this->assertEquals($frame->getHeader('testing'), 11);
+    }
+
+    public function test_setHeaders()
+    {
+        $frame = new Zend_Queue_Stomp_Frame();
+        $frame->setHeaders(array('testing' => 1));
+        $this->assertEquals(1, $frame->getHeader('testing'));
+    }
+
+    public function test_parameters()
+    {
+        $frame = new Zend_Queue_Stomp_Frame();
+
+        try {
+            $frame->setAutoContentLength(array());
+            $this->fail('Exception should have been thrown');
+        } catch(Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $frame->setHeader(array(), 1);
+            $this->fail('Exception should have been thrown');
+        } catch(Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $frame->setHeader('testing', array());
+            $this->fail('Exception should have been thrown');
+        } catch(Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $frame->getHeader(array());
+            $this->fail('Exception should have been thrown');
+        } catch(Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $frame->setBody(array());
+            $this->fail('Exception should have been thrown');
+        } catch(Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $frame->setCommand(array());
+            $this->fail('Exception should have been thrown');
+        } catch(Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $frame->toFrame();
+            $this->fail('Exception should have been thrown');
+        } catch(Exception $e) {
+            $this->assertTrue(true);
+        }
+
+        try {
+            $frame->fromFrame(array());
+            $this->fail('Exception should have been thrown');
+        } catch(Exception $e) {
+            $this->assertTrue(true);
+        }
+    }
+
+    public function test_constant()
+    {
+        $this->assertTrue(is_string(Zend_Queue_Stomp_Frame::END_OF_FRAME));
+        $this->assertTrue(is_string(Zend_Queue_Stomp_Frame::CONTENT_LENGTH));
+        $this->assertTrue(is_string(Zend_Queue_Stomp_Frame::EOL));
+    }
+
+}

+ 5 - 0
tests/Zend/Service/Amazon/AllTests.php

@@ -56,6 +56,10 @@ require_once 'Zend/Service/Amazon/Ec2/AllTests.php';
  */
 require_once 'Zend/Service/Amazon/S3/AllTests.php';
 
+/**
+ * @see Zend_Service_Amazon_Sqs_AllTests
+ */
+require_once 'Zend/Service/Amazon/Sqs/AllTests.php';
 
 /**
  * @category   Zend
@@ -96,6 +100,7 @@ class Zend_Service_Amazon_AllTests
 
         $suite->addTest(Zend_Service_Amazon_Ec2_AllTests::suite());
         $suite->addTest(Zend_Service_Amazon_S3_AllTests::suite());
+        $suite->addTest(Zend_Service_Amazon_Sqs_AllTests::suite());
 
         return $suite;
     }

+ 93 - 0
tests/Zend/Service/Amazon/Sqs/AllTests.php

@@ -0,0 +1,93 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Amazon_Sqs
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: AllTests.php 11973 2008-10-15 16:00:56Z matthew $
+ */
+
+if (!defined('PHPUnit_MAIN_METHOD')) {
+    define('PHPUnit_MAIN_METHOD', 'Zend_Service_Amazon_Sqs_AllTests::main');
+}
+
+/**
+ * Test helper
+ */
+require_once dirname(__FILE__) . '/../../../../TestHelper.php';
+
+/**
+ * Exclude from code coverage report
+ */
+PHPUnit_Util_Filter::addFileToFilter(__FILE__);
+
+/**
+ * @see Zend_Service_Amazon_Sqs_OfflineTest
+ */
+require_once 'Zend/Service/Amazon/Sqs/OfflineTest.php';
+
+/**
+ * @see Zend_Service_Amazon_Sqs_OnlineTest
+ */
+require_once 'Zend/Service/Amazon/Sqs/OnlineTest.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_Amazon_Sqs
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_Amazon_Sqs_AllTests
+{
+    /**
+     * Runs this test suite
+     *
+     * @return void
+     */
+    public static function main()
+    {
+        PHPUnit_TextUI_TestRunner::run(self::suite());
+    }
+
+    /**
+     * Creates and returns this test suite
+     *
+     * @return PHPUnit_Framework_TestSuite
+     */
+    public static function suite()
+    {
+        $suite = new PHPUnit_Framework_TestSuite('Zend Framework - Zend_Service - Amazon - SQS');
+
+        $suite->addTestSuite('Zend_Service_Amazon_Sqs_OfflineTest');
+
+        if (defined('TESTS_ZEND_SERVICE_AMAZON_ONLINE_ENABLED') 
+            && constant('TESTS_ZEND_SERVICE_AMAZON_ONLINE_ENABLED') 
+            && defined('TESTS_ZEND_SERVICE_AMAZON_ONLINE_ACCESSKEYID') 
+            && defined('TESTS_ZEND_SERVICE_AMAZON_ONLINE_SECRETKEY')
+        ) {
+            $suite->addTestSuite('Zend_Service_Amazon_Sqs_OnlineTest');
+        } else {
+            $suite->addTestSuite('Zend_Service_Amazon_Sqs_OnlineTest_Skip');
+        }
+
+        return $suite;
+    }
+}
+
+if (PHPUnit_MAIN_METHOD == 'Zend_Service_Amazon_Sqs_AllTests::main') {
+    Zend_Service_Amazon_Sqs_AllTests::main();
+}

+ 45 - 0
tests/Zend/Service/Amazon/Sqs/OfflineTest.php

@@ -0,0 +1,45 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Amazon_Sqs
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: OfflineTest.php 8064 2008-02-16 10:58:39Z thomas $
+ */
+
+/**
+ * Test helper
+ */
+require_once dirname(__FILE__) . '/../../../../TestHelper.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_Amazon_Sqs
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_Amazon_Sqs_OfflineTest extends PHPUnit_Framework_TestCase
+{
+    public function setUp()
+    {
+        $this->markTestSkipped('No offline tests for Zend_Service_Amazon_Sqs');
+    }
+
+    public function testNothing()
+    {
+    }
+}

+ 141 - 0
tests/Zend/Service/Amazon/Sqs/OnlineTest.php

@@ -0,0 +1,141 @@
+<?php
+/**
+ * Zend Framework
+ *
+ * LICENSE
+ *
+ * This source file is subject to the new BSD license that is bundled
+ * with this package in the file LICENSE.txt.
+ * It is also available through the world-wide-web at this URL:
+ * http://framework.zend.com/license/new-bsd
+ * If you did not receive a copy of the license and are unable to
+ * obtain it through the world-wide-web, please send an email
+ * to license@zend.com so we can send you a copy immediately.
+ *
+ * @category   Zend
+ * @package    Zend_Service_Amazon_Sqs
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ * @version    $Id: OnlineTest.php 11973 2008-10-15 16:00:56Z matthew $
+ */
+
+/**
+ * Test helper
+ */
+require_once dirname(__FILE__) . '/../../../../TestHelper.php';
+
+/**
+ * @see Zend_Service_Amazon_Sqs
+ */
+require_once 'Zend/Service/Amazon/Sqs.php';
+
+/**
+ * @see Zend_Http_Client_Adapter_Socket
+ */
+require_once 'Zend/Http/Client/Adapter/Socket.php';
+
+/**
+ * @category   Zend
+ * @package    Zend_Service_Amazon_Sqs
+ * @subpackage UnitTests
+ * @copyright  Copyright (c) 2005-2009 Zend Technologies USA Inc. (http://www.zend.com)
+ * @license    http://framework.zend.com/license/new-bsd     New BSD License
+ */
+class Zend_Service_Amazon_Sqs_OnlineTest extends PHPUnit_Framework_TestCase
+{
+    /**
+     * Reference to Amazon service consumer object
+     *
+     * @var Zend_Service_Amazon_Sqs
+     */
+    protected $_amazon;
+
+    /**
+     * Socket based HTTP client adapter
+     *
+     * @var Zend_Http_Client_Adapter_Socket
+     */
+    protected $_httpClientAdapterSocket;
+
+    /**
+     * Sets up this test case
+     *
+     * @return void
+     */
+    public function setUp()
+    {
+        $this->_amazon = new Zend_Service_Amazon_Sqs(
+            constant('TESTS_ZEND_SERVICE_AMAZON_ONLINE_ACCESSKEYID'),
+            constant('TESTS_ZEND_SERVICE_AMAZON_ONLINE_SECRETKEY')
+        );
+
+        $this->_queue_name = constant('TESTS_ZEND_SERVICE_AMAZON_SQS_QUEUE');
+
+        $this->_httpClientAdapterSocket = new Zend_Http_Client_Adapter_Socket();
+
+        $this->_amazon->getHttpClient()
+                      ->setAdapter($this->_httpClientAdapterSocket);
+    }
+
+    /**
+     * Test SQS methods
+     *
+     * @return void
+     */
+    public function testSqs()
+    {
+        try {
+            $queue_url = $this->_amazon->create($this->_queue_name, 45);
+            $timeout = $this->_amazon->getAttribute($queue_url, 'VisibilityTimeout');
+            $this->assertEquals(45, $timeout, 'VisibilityTimeout attribute is not 45');
+
+            $test_msg = 'this is a test';
+            $this->_amazon->send($queue_url, $test_msg);
+
+            $messages = $this->_amazon->receive($queue_url);
+
+            foreach ($messages as $message) {
+                $this->assertEquals($test_msg, $message['body']);
+            }
+
+            foreach ($messages as $message) {
+                $result = $this->_amazon->deleteMessage($queue_url, $message['handle']);
+                $this->assertTrue($result, 'Message was not deleted');
+            }
+
+            $count = $this->_amazon->count($queue_url);
+            $this->assertEquals(0, $count);
+
+            $this->_amazon->delete($queue_url);
+        } catch (Exception $e) {
+            $this->fail($e->getMessage());
+        }
+    }
+
+    /**
+     * Tear down the test case
+     *
+     * @return void
+     */
+    public function tearDown()
+    {
+        unset($this->_amazon);
+    }
+}
+
+
+class Zend_Service_Amazon_Sqs_OnlineTest_Skip extends PHPUnit_Framework_TestCase
+{
+    public function setUp()
+    {
+        $this->markTestSkipped(
+            'Zend_Service_Amazon_Sqs online tests not enabled with an access key ID in '
+            . 'TestConfiguration.php'
+        );
+    }
+
+    public function testNothing()
+    {
+    }
+}