cxf-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Andrei Shakirin <ashaki...@talend.com>
Subject RE: Adding features to a conduit for a custom transport
Date Sun, 10 Feb 2013 18:10:32 GMT
Hi Leon,

Yep, now I got your problem.

Cleint.getConduit() actually invokes Conduit.activate() because of following chain:
1) getConduit() creates empty exchange and calls setExchangeProperties(...) for this exchange
2) setExchangeProperties initialises message observer in this exchange: exchange.put(MessageObserver.class,
this)
3) AbstractConduitSelector calls setMessageObserver() for conduit
4) AbstarctObservable extended by Conduit calls activate() in setMessageObserver().

I see two ways to resolve your problem:


1.       Do not use activate() to establish connection with the server, but introduce custom
setupConnection() method.
               Then cast conduit to your type and invoke setupConnection() with necessary
parameters:

    public void initialize(Client client, Bus bus) {
        Conduit c = client.getConduit(); // activate() gets called here, which is too early
        if (c instanceof XMPPConduit) {
            XMPPConduit xmppConduit = (XMPPConduit)c;
            xmppConduit.setupConnection(this.username);
            ...
        } else {
            LOGGER.severe("This feature only supports XMPP clients");
        }
    }


2.       Pass callback as parameter to your TransportFactory, set it into conduit and invoke
this callback by activate() method to get necessary parameters:



interface ConduitCallback {

                ConduitParams getParams(EndpointInfo ei);

}

                Callback implementation will return necessary parameters for each client dependent
on endpoint information.

Regards,
Andrei.



From: Leon Doud [mailto:leon.doud@gmail.com]
Sent: Samstag, 2. Februar 2013 03:29
To: Andrei Shakirin
Cc: users@cxf.apache.org
Subject: Re: Adding features to a conduit for a custom transport

Andrei,
Thanks for the reply. I'll try to explain my use case completely.

I'm writing a custom CXF transport for XMPP. XMPP is different from HTTP, as the XMPP client
keeps a constant socket connection open to the server. For this use case, the CXF client should
open its connection to the XMPP server when the client is created. It should not wait until
the first message is sent.

To open the XMPP connection immediately,  my custom conduit extends "org.apache.cxf.transport.AbstractConduit"
and overrides the "activate()" method. The  implementation opens the connection to the XMPP
server. A username/password is required to connect to the server. This means that my custom
conduit needs a username/password and XMPP server address prior to the activate() method being
called on the AbstractConduit.

My first attempt at implementing this was to set the username/password on my custom transport
factory. Then when the getConduit method was called, the custom transport factory creates
a new conduit that has the same username/password set on it. It worked. The drawback is that
all my clients have to use the same username/password and the same XMPP server. I didn't find
this flexible enough.

Now, I'm trying to set the username/password and XMPP server address on the conduit via a
feature on the client. I feel this approach provides more flexibility.  The problem occurs
when calling "client.getConduit()". The problem is that client.getConduit() triggers the conduit's
activate() method to be called. This leaves me in a catch-22 situation. The activate() method
that I implemented needs the username/password and XMPP server address. The only way for a
feature to get conduit is to call client.getConduit().  Please see the code snipet below from
the feature I'm trying to use:

    public void initialize(Client client, Bus bus) {
        Conduit con = client.getConduit(); // activate() gets called here, which is too early


        if (con instanceof XMPPConduit) {
            XMPPConduit xmppConduit = (XMPPConduit)con;
            xmppConduit.setUsername(this.username);
            ...
        } else {
            LOGGER.severe("This feature only supports XMPP clients");
        }
    }


On Wed, Jan 30, 2013 at 12:22 PM, Andrei Shakirin <ashakirin@talend.com<mailto:ashakirin@talend.com>>
wrote:
Hi Leon,

> This design worked as planned for the destination. A problem occurred when
> using the same approach for the conduit. I would add features to the client,
> and the initialize(Client, Bus) of the feature is triggered. I then attempt to use
> Client.getConduit() so I can set properties on the conduit.
I did not get your use case completely. Conduit is not related with features your adding to
client.
Conduit and Destination are created using TransportFactory, as described in article. Do you
register your own transport factory?
Basically call Client.getConduit() invokes Conduit selector which retrieves correct transport
factory (based on endpoint url) and ask transport factory for conduit (getConduit() method).

> Unfortunately calling Client.getConduit() eventually calls activate() on my
> conduit, which results in a null pointer exception.
Conduit has prepare() and close() methods. What do you mean with activate()?

For more information just look how CXF transports are implemented: org.apache.cxf.transport.jms,
org.apache.cxf.transport.local.
You can find additional info in my blog: http://ashakirin.blogspot.de/2012/02/custom-cxf-transport.html
.

Regards,
Andrei.

> -----Original Message-----
> From: Leon Doud [mailto:leon.doud@gmail.com<mailto:leon.doud@gmail.com>]
> Sent: Dienstag, 29. Januar 2013 03:25
> To: users@cxf.apache.org<mailto:users@cxf.apache.org>
> Subject: Adding features to a conduit for a custom transport
>
> I'm implementing a custom transport. I planned to support the transport by
> using features to setup the destination and conduit prior to them being
> activated. This is based on what I read from http://cxf.apache.org/custom-
> cxf-transport.html
>
> This design worked as planned for the destination. A problem occurred when
> using the same approach for the conduit. I would add features to the client,
> and the initialize(Client, Bus) of the feature is triggered. I then attempt to use
> Client.getConduit() so I can set properties on the conduit.
> Unfortunately calling Client.getConduit() eventually calls activate() on my
> conduit, which results in a null pointer exception.
>
> Here is the stack trace, and the feature is XMPPService (I'm trying to set the
> username/password in this case)
>     at
> org.apache.cxf.transport.xmpp.messaging.XMPPConduit.activate(XMPPCon
> duit.java:57)
>     at
> org.apache.cxf.transport.AbstractObservable.setMessageObserver(Abstract
> Observable.java:48)
>     at
> org.apache.cxf.endpoint.AbstractConduitSelector.getSelectedConduit(Abstr
> actConduitSelector.java:115)
>     at
> org.apache.cxf.endpoint.UpfrontConduitSelector.selectConduit(UpfrontCon
> duitSelector.java:77)
>     at org.apache.cxf.endpoint.ClientImpl.getConduit(ClientImpl.java:846)
>     at
> org.apache.cxf.transport.xmpp.messaging.XMPPService.initialize(XMPPServi
> ce.java:153)
>
> It seems like I'm in a catch-22. I want to use features to setup the conduit
> before it is activated, but trying to use Client.getConduit() activates the
> conduit. Is there someway to use Client.getConduit() (from the
> implementation of the feature) without activating the conduit? I would
> prefer to use features to configure the client/conduit and not the transport
> factory.
>
> Thanks in advance,
> Leon


Mime
  • Unnamed multipart/alternative (inline, None, 0 bytes)
View raw message