You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@activemq.apache.org by Nathan Mittler <na...@gmail.com> on 2006/03/26 23:11:33 UTC

openwire C++ client

I've taken a closer look at the openwire C++ client this weekend and noticed
a few things ...

1) I think there are a few cases where we could reduce the usage of smart
pointers.

One instance where I think smart pointer usage is questionable is when
openwire is referencing an object that it doesn't control.  For example,
when my code declares a class that is an IMessageListener, it seems strange
that this should be passed in as a smart pointer to openwire functions.
Openwire doesn't control the lifetime of this object, so I don't believe it
should be referencing it in a "managed" way.

Another case where smart pointers could be avoided is strings.  If all
string member variables are std::strings, then the setXXX method could just
take a "const char*" and the const getXXX method could simply return a
"const char*" (which would be the value returned from the mystr.c_str()
method).  This makes for a much simpler and symmetric API.

2) ITextMessage should extend IMessage

It seems that the ITextMessage class was at one time derived from IMessage,
but it is commented out (probably to get through compilation :-) ).  If you
try to call send() on the MessagePublisher class with an ITextMessage, the
code won't compile.

I've gotten around this by making ITextMessage extend IMessage - the trick
is that when you do this, ActiveMQTextMessage gets IMessage from two
branches.  In one branch, it gets the methods from IMessage implemented for
it ( by ActiveMQMessage) and in the other branch (ITextMessage), it
doesn't.  So you have to have ActiveMQTextMessage implement all the methods
from the IMessage interface and delegate them to the ActiveMQMessage base
class.  This seems to do the trick.

3) It seems that the smart pointer code should be using dynamic_cast rather
than reinterpret cast.  I seem to remember times where a dynamic_cast
returned a slightly different address (in some cases).   If this is the
case, it could be very dangerous to use reinterpret_cast everywhere since it
just takes the same pointer and treats its address as the other type
(corrupting the references to the object).  This could lead to strange bugs
that are difficult to track down.

The other problem is in the fact that the internal pointer is a void* rather
than a T*.  This complicates debugging, because the debugger sees an
internal pointer, but doesn't look inside since it doesn't know what type it
"really" is.

4) I'm not seeing an ExceptionListener equivalent.  Am I missing something?

5) I got a small sample app compiling, but I'm getting a segfault when
creating a session (could certainly be user error - a code snippet is
below).  Here's the stack dump:

    Thread [1] (Suspended: Signal 'SIGSEGV' received. Description:
Segmentation fault.)
    12 apache::activemq::client::command::ConnectionInfo::marshal() at
src/command/ConnectionInfo.cpp:111 0x0804fd02
    11 apache::activemq::client::protocol::OpenWireFormat::marshal() at
src/protocol/OpenWireFormat.cpp:89 0x0808c0a3
    10 apache::activemq::client::transport::SocketTransport::send() at
src/transport/SocketTransport.cpp:144 0x08051650
    9 apache::activemq::client::transport::SocketTransport::asyncRequest()
at src/transport/SocketTransport.cpp:109 0x08052e11
    8 apache::activemq::client::transport::SocketTransport::request() at
src/transport/SocketTransport.cpp:123 0x08051362
    7 apache::activemq::client::Connection::syncRequest() at
src/Connection.cpp:188 0x0805e31e
    6 apache::activemq::client::Connection::checkConnected() at
src/Connection.cpp:298 0x0805e196
    5 apache::activemq::client::Connection::syncRequest() at
src/Connection.cpp:186 0x0805e2d1
    4 apache::activemq::client::Connection::createSession() at
src/Connection.cpp:173 0x0805fb56
    3 apache::activemq::client::Connection::createSession() at
src/Connection.cpp:162 0x0805db3b
    2 Tester::test() at ../main.cpp:47 0x0804bd8a
    1 main() at ../main.cpp:102 0x0804ab34

My code is a modified version of the cms sample ... the guts of the code is
shown below

            int numMessages = 1000;
            int sleepTime = 10;

            printf("Starting activemqcms test (sending %d messages and
sleeping %d seconds) ...\n", numMessages, sleepTime );

            // START SNIPPET: demo
            ConnectionFactory connectionFactory( p<Uri>(new
Uri("tcp://127.0.0.1:61616") ) );

            p<IConnection> connection = connectionFactory.createConnection
();

            p<ISession> session = connection->createSession();
            p<ITopic> topic = session->getTopic("mytopic");
            p<MessageConsumer> consumer =
p_cast<MessageConsumer>(session->createConsumer( topic ));
            consumer->setMessageListener( p<IMessageListener>(this) );
            p<IMessageProducer> producer = session->createProducer( topic );

            const char* text = "this is a test!";
            p<ITextMessage> msg = session->createTextMessage( text );

            for( int ix=0; ix<numMessages; ++ix ){
                producer->send( msg );
                doSleep();
            }
            // END SNIPPET: demo

            sleep( sleepTime );

I'm using AMQ 4.0 M4 and my broker was configured with the default
transports as follows:

    <transportConnectors>
       <transportConnector uri="tcp://localhost:61616"
discoveryUri="multicast://default"/>

       <transportConnector uri="stomp://localhost:61617"/>
    </transportConnectors>

Mats, let me know if there is anything you'd like me to tackle, or if you'd
like to continue this discussion (on/offline).

Regards,
Nate

Re: openwire C++ client

Posted by Hiram Chirino <hi...@hiramchirino.com>.
Hi Nathan,

On 3/26/06, Nathan Mittler <na...@gmail.com> wrote:
> I've taken a closer look at the openwire C++ client this weekend and noticed
> a few things ...
>
> 1) I think there are a few cases where we could reduce the usage of smart
> pointers.
>
> One instance where I think smart pointer usage is questionable is when
> openwire is referencing an object that it doesn't control.  For example,
> when my code declares a class that is an IMessageListener, it seems strange
> that this should be passed in as a smart pointer to openwire functions.
> Openwire doesn't control the lifetime of this object, so I don't believe it
> should be referencing it in a "managed" way.
>
> Another case where smart pointers could be avoided is strings.  If all
> string member variables are std::strings, then the setXXX method could just
> take a "const char*" and the const getXXX method could simply return a
> "const char*" (which would be the value returned from the mystr.c_str()
> method).  This makes for a much simpler and symmetric API.
>

I agreed.  I think it may be possible to be even more aggressive and
avoid having the interface classes use smart pointers at all.  I think
the if we define good ownership rules, then we do not need to have the
API user need to worry about smart pointers.

On a related note, It would be nice if the name spaces used were
changed so that they paralleled the .NET stuff a little closer.  It
might be nice to have a 'cms' name space the holds all the interface
classes and a 'activemq', 'activemq::transport', etc. name space that
holds all the activemq implementation of the interfaces.  Using
'org::apache::activemq' seems a little verbose to me.

Regards,
Hiram

> 2) ITextMessage should extend IMessage
>
> It seems that the ITextMessage class was at one time derived from IMessage,
> but it is commented out (probably to get through compilation :-) ).  If you
> try to call send() on the MessagePublisher class with an ITextMessage, the
> code won't compile.
>

agreed.

> I've gotten around this by making ITextMessage extend IMessage - the trick
> is that when you do this, ActiveMQTextMessage gets IMessage from two
> branches.  In one branch, it gets the methods from IMessage implemented for
> it ( by ActiveMQMessage) and in the other branch (ITextMessage), it
> doesn't.  So you have to have ActiveMQTextMessage implement all the methods
> from the IMessage interface and delegate them to the ActiveMQMessage base
> class.  This seems to do the trick.
>

The joys of multiple inheritance :)


--
Regards,
Hiram