activemq-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "David Fahlander" <David.Fahlan...@portwise.com>
Subject RE: openwire C++ client
Date Mon, 27 Mar 2006 11:40:27 GMT
Nathan, in point 3, you certainly have a point.

Even though I've been conscious about the internal structure of C++
objects, the fact that making an up-cast to one of multiple base classes
needs ptr adjustment (as static_cast<> and dynamic_cast<> does), I have
been missing this part when implementing the p_cast<> function.

The reason why using void* is to be able to reuse classes internal
refcounting mechanism if such is present, but attach an own refcounter
where not. For example, the p<> template is compatible with both p<int>
and p<IUnknown>.

Thanks for seeing the problem. We will need to update the IFR code in
order for the client to work properly where p_cast<> is used. I'll look
into this and update the IFR. Mats and I will continue with testing and
fixing issues.

David

-----Original Message-----
From: Nathan Mittler [mailto:nathan.mittler@gmail.com] 
Sent: den 26 mars 2006 23:12
To: activemq-dev@geronimo.apache.org
Subject: 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

Mime
View raw message