Hi Dan,

Thanks for the detail response, now i understand a little bit more.

Short answers on your questions:
> 1. Why are you creating a new DesintinationFactory?
You are right, existing DestinationFactory should be obtained as bus extension.
By the way it also fixes the problem 3 (reregistration is not necessary any 
more!).
Unfortunatelly it was not shown in code shippet in wiki page for Local 
transport http://cxf.apache.org/docs/local-transport.html .
(line how to obtain DestinationFactory is missing there)

> 2. Honestly, I'm surprised this works at all. 
Exactly, exception will be consequent in this scenario.

> 3. In both cases, I would not  register the soap ID's.   That would cause the 
> soap transport (not http) to be unregistered from those and that MAY cause 
> issues.

Basically I agree with you for case if just additional physical transport 
should be implemented (for example UDP). But in my scenario I would like 
deliberately to replace all possible transports transparently for the WSDL.
WSDL will still contain http://schemas.xmlsoap.org/soap/http transports and 
even real http endpoint will be used later by SOPERA/SBB to send a message. But 
my conduit and destination are activated for all transports and replace "real 
transport call" to "sbb call" that is transport independent (supports http, 
https, jms, etc). Messages originally intended to be send via http will be 
transparently tunneled via SOPERA/SBB.
In some aspects it is similar to local transport that also replaces default 
soap transportURI (http://cxf.apache.org/docs/local-transport.html).

> 4. Most likely, the ConduitInitiator needs to go into "search" mode
It can also explain effect by web deployment scenario. I register my factory 
via spring in web application:
 <bean class="org.sopera.cxf.transport.SBBTransportFactory" lazy-init="false">
      <property name="transportIds">
          <list>
              <value>http://cxf.apache.org/transports/sbb</value>
              <value>http://schemas.xmlsoap.org/soap/http</value>
              <value>http://schemas.xmlsoap.org/wsdl/soap/http</value>
              <value>http://cxf.apache.org/transports/http</value>
              <value>http://cxf.apache.org/transports/http/configuration</value>
          </list>
      </property>
  </bean>
That has the following effect: my factory is instantiated (constructor was 
called), but destination and conduit are not requested.
If I register factory additionally in factory constructor programmatically (via 
DestinationFactoryManager and ConduitInitator) - scenario works (my destination 
and conduit are requested).

Interesting is that in standalone scenario just spring registration is enough.
I will look in this a little bit deeper now.

Regards,
Andrei.

-----Original Message-----
From: Daniel Kulp [mailto:[email protected]] 
Sent: Montag, 17. Januar 2011 18:02
To: [email protected]
Cc: Andrei Shakirin
Subject: Re: Registration of custom transport factory is overwritten if service 
created with WSDL URL

On Monday 17 January 2011 7:30:39 am Andrei Shakirin wrote:
> Hi folks,
> 
> By developing of custom CXF transport factory I faced one strange 
> behavior looks like a bug.
> 
> Scenario:
> 1. I register my factory using
>             Bus bus = BusFactory.getDefaultBus();
>             DestinationFactoryManagerImpl dfm = new 
> DestinationFactoryManagerImpl(bus); SBBTransportFactory sbbTransport = 
> new SBBTransportFactory(); 
> dfm.registerDestinationFactory("http://cxf.apache.org/transports/sbb";,
> sbbTransport);
> dfm.registerDestinationFactory("http://schemas.xmlsoap.org/soap/http";,
> sbbTransport);
> dfm.registerDestinationFactory("http://schemas.xmlsoap.org/wsdl/soap/http";
> , sbbTransport);

Why are you creating a new DesintinationFactory?    That should just be:

DestinationFactoryManager dfm =
bus.getExtension(DestinationFactoryManager.class)

as well.   I think you are ending up wiping out any registrations that may 
have already occurred.   Not really sure though, but definitely use the the 
one that is there, don't create a new one.


>             ConduitInitiatorManager extension = 
> bus.getExtension(ConduitInitiatorManager.class);
> extension.registerConduitInitiator("http://cxf.apache.org/transports/s
> bb",
> sbbTransport);
> extension.registerConduitInitiator("http://schemas.xmlsoap.org/soap/ht
> tp",
> sbbTransport);
> extension.registerConduitInitiator("http://schemas.xmlsoap.org/wsdl/so
> ap/h
> ttp", sbbTransport);


In both cases, I would not  register the soap ID's.   That would cause the 
soap transport (not http) to be unregistered from those and that MAY cause 
issues.

 
> 2. If I call consumer via ClientProxyFactoryBean or via Service 
> without WSDL URL: Service service = Service.create(SERVICE_NAME);
>          HelloWorld hw = service.getPort(HelloWorld.class);
>           hw.write(TEST_REQUEST);
> my factory is activated as expected -ok.

Honestly, I'm surprised this works at all.   I need to check the spec, but I 
actually would have expected an exception as there isn't an addPort call first 
to associate a port with an address.

> 
> 3. If I try to call consumer via Service, but additionally pass WSDL URL:
>         URL wsdlURL = this.getClass().getResource("/HelloWorld.wsdl");
>         Service service = Service.create(wsdlURL, SERVICE_NAME);
>         HelloWorld hw = service.getPort(HelloWorld.class);
>         String result = hw.sayHi(TEST_REQUEST); my factory is not 
> activated.

In the wsdl, the first extensor in the port (that can map to a conduit) is the 
soap:address element.  It's namespace is http://schemas.xmlsoap.org/wsdl/soap/ 
and thus the soap transport is activated.   The soap transport maps the HTTP 
URL transport ID's to the CXF HTTP transport.   That's a soap level mapping.  
If you want your transport used, change the wsdl to say:

<soap:binding style="document"
                        transport="http://cxf.apache.org/transports/sbb"; />

OR

remove the soap:address and stick something like:
   <sbb:address> or something that would cause your transport to be activated 
automatically.

> But if I make the same registration again after getPort() call - it works.
> It seems that registration in this case is somehow overwritten and 
> should be actualized.

Most likely, the ConduitInitiator needs to go into "search" mode (by default, 
everything is lazy initialized and only loaded if it needs to search) to find 
the appropriate conduit and the search is causing the override.   You could 
probably "fix" it by doing:
ConduitInitiatorManager extension =
     bus.getExtension(ConduitInitiatorManager.class);
extension.getConduitInitiator("http://schemas.xmlsoap.org/soap/http";);
extension.register(....);

The "get" would force a search which would force the load and then you would 
override the load.   Normally, in spring config, this would be similar to a  
"depends-on" type scenario to force the other one first..

 
> I attach the small project illustrated this effect.
> consumerRequestResponseOK - use service without WSDL URL 
> consumerRequestResponseFailed - iluustrates the problem 
> consumerRequestResponseFixed - shows the fix.
> 
> Another workaround is just to read DestinationFactory and 
> ConduitInitor before registration (call printRegistration() in setup()).
> 
> Do you have any ideas regarding this effect?
> For me it looks like a bug.

Well, the "bugs" to me are:
1) In the first case, I need  to see if an exception should be thrown or not.  
If not, it still should be activating the soap transport, not yours.  I may 
need to look at that.

2) Case 2: not a bug.

3) I need to look at this more.   It should be the same as case 2 I think.

--
Daniel Kulp
[email protected]
http://dankulp.com/blog

Reply via email to