You are viewing a plain text version of this content. The canonical link for it is here.
Posted to users@cxf.apache.org by Leon Doud <le...@gmail.com> on 2013/01/29 03:25:27 UTC
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(XMPPConduit.java:57)
at
org.apache.cxf.transport.AbstractObservable.setMessageObserver(AbstractObservable.java:48)
at
org.apache.cxf.endpoint.AbstractConduitSelector.getSelectedConduit(AbstractConduitSelector.java:115)
at
org.apache.cxf.endpoint.UpfrontConduitSelector.selectConduit(UpfrontConduitSelector.java:77)
at org.apache.cxf.endpoint.ClientImpl.getConduit(ClientImpl.java:846)
at
org.apache.cxf.transport.xmpp.messaging.XMPPService.initialize(XMPPService.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
RE: Adding features to a conduit for a custom transport
Posted by Andrei Shakirin <as...@talend.com>.
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 <as...@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<ma...@gmail.com>]
> Sent: Dienstag, 29. Januar 2013 03:25
> To: users@cxf.apache.org<ma...@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
Re: Adding features to a conduit for a custom transport
Posted by Leon Doud <le...@gmail.com>.
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 <as...@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]
> > Sent: Dienstag, 29. Januar 2013 03:25
> > To: 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
>
RE: Adding features to a conduit for a custom transport
Posted by Andrei Shakirin <as...@talend.com>.
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]
> Sent: Dienstag, 29. Januar 2013 03:25
> To: 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