cxf-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Dan Diephouse <...@envoisolutions.com>
Subject Re: Configuration APIs
Date Thu, 31 Aug 2006 01:58:01 GMT
Andrea Smyth wrote:

> Dan Diephouse wrote:
>
>> Andrea Smyth wrote:
>>
>>> Dan Diephouse wrote:
>>>
>>>> Andrea Smyth wrote:
>>>>
>>>>> So assuming all configurable properties of the http client and 
>>>>> server transport are data members of HTTPConduit.java and 
>>>>> JettyHTTPDestination with corresponding getters/setters (whether 
>>>>> manually coded or inherited from a generated POJO, also assume 
>>>>> standard getters for now) - how can we use Spring (for example) to 
>>>>> run the ClientServerTest in the systest module with a non-default 
>>>>> value for the contextMatchStrategy field (picking this one as it's 
>>>>> of type String) - without changing the test code? Any other 
>>>>> properties of the transport and other objects (e.g. bus) should be 
>>>>> left at their defaults.
>>>>>
>>>>> We'll have something like:
>>>>>
>>>>> <bean id="?" 
>>>>> class="org.apache.cxf.transport.http.JettyHTTPDestination">
>>>>>    <property name="contextMatchStrategy" value="stem"/>
>>>>> </bean>
>>>>>
>>>>> But do we need other beans that reference this one? How should the 
>>>>> id(s) be chosen?
>>>>> And what's the role of HTTPConduitFactory in this - is it not used 
>>>>> at all or is it used as a factory in the above bean definition? 
>>>>> Same question for the BusFactory.
>>>>>
>>>>> Dan D. - it would help if you could sketch out the steps involved 
>>>>> - or point to code for similar in XFire.
>>>>>
>>>>> Andrea.
>>>>
>>>>
>>>>
>>>>
>>>> Hi Andrea,
>>>>
>>>> Sorry if I was being too vague.
>>>>
>>>> Lets start off with our baseline spring definitions (these would be 
>>>> defined in an xml somewhere
>>>> <bean id="httpTransport">
>>>>  <property name="serverPolicy" ref="servicePolicy"/>
>>>> </bean>
>>>>
>>>> <bean id="serverPolicy" class="...HttpServerPolicy"/>
>>>>
>>>> <bean id="bus" class="org.apache.cxf.bus.CXFBus">
>>>>  <constructor-arg>
>>>>   <map>
>>>>    <entry key="org.apache.cxf.transport.DestinationFactoryManager" 
>>>> value-ref="destinationFactorymanager"/>
>>>> ...
>>>>   </map>
>>>>  </constructor-arg>
>>>> </bean>
>>>>
>>>> <bean id="destinationFactoryManager" 
>>>> class="org.apache.cxf.transport.DestinationFactoryManagerImpl">
>>>>  <property name="transports">
>>>>   <list>
>>>>     <entry ref="httpTransport">
>>>> ...
>>>>   </list>
>>>>  </property>
>>>> </bean>
>>>>
>>>> Now if we have a spring user all they need to override the policy is:
>>>>
>>>> <import resource="/org/apache/cxf/spring/beans.xml"/>
>>>>
>>>> <bean id="serverPolicy" class="...HttpServerPolicy">
>>>> .. override the defaults here.
>>>> </bean>
>>>>
>>>> Similarily they could define their own list of transports. Or we 
>>>> could even help them by creating an abstract destination factory 
>>>> manager which they can extend.
>>>>
>>>> The abstract one:
>>>> <bean id="abstractDestinationFactoryManager" 
>>>> class="org.apache.cxf.transport.DestinationFactoryManagerImpl" 
>>>> abstract="true">
>>>>  <property name="transports">
>>>>   <list>
>>>>     <entry ref="httpTransport">
>>>> ...
>>>>   </list>
>>>>  </property>
>>>> </bean>
>>>>
>>>> The user's:
>>>> <bean id="destinationFactoryManager" 
>>>> extends="abstractDestinationFactoryManager">
>>>>  <property name="transports">
>>>>    <list merge="true">
>>>>      <entry ref="myTransport">
>>>>   </list>
>>>>  </property>
>>>> </bean>
>>>>
>>>> So in summary, the user only modifies what they want and the 
>>>> policies, transports, bus, are all handled by Spring. Also, the 
>>>> bean names don't really matter. If a user wants to override a bean 
>>>> in our beans.xml, the will need to know that name, but it doesn't 
>>>> really matter what it is.
>>>>
>>>> - Dan
>>>>
>>> Hi Dan,
>>>
>>> OK, so this raises a couple of questions as to how our code is 
>>> supposed to digest this information:
>>>
>>> 1. The current bus factory (CXFBusFactory in rt-core) would have to 
>>> be replaced by a SpringBusFactory which does not actually create a 
>>> bus itself but obtains it from an XmlBeanFactory (and similar for 
>>> other frameworks), right? And with the bus being the to level object 
>>> this would be the only place where we are interacting with the 
>>> XmlBeanFactory I assume.
>>
>>
>> I suppose we could make a helper class like a SpringBusFactory which 
>> helps a user load in different ApplicationContexts. But there is no 
>> reason that we have to.
>>
>>> Where does that leave the bus extensions, i.e. the  recently 
>>> implemented component discovery mechanism? 
>>
>>
>> It wouldn't be used.
>>
>>> Could it ever be used in conjunction with an IOC style configuration 
>>> mechanism?
>>
>>
>> I don't see why you would. IoC is doing the wiring for you.
>>
>>>
>>> 2. DestinationFactoryManager does not manage actual Destinations but 
>>> DestinationFactories, so if anything  it'd have to be something like:
>>> <bean id="destinationFactoryManager" 
>>> class="org.apache.cxf.transport.DestinationFactoryManagerImpl">
>>> <property name="destinationFactories">
>>>   <map>
>>>     <entry key="http://schemas.xmlsoap.org/wsdl/http/" 
>>> value-ref="HTTPDestinationFactory"/>
>>>   <map>
>>> </property>
>>> </bean>
>>> (again - how does this relate to the component discovery mechanism?)
>>>
>> Oops! Yes, you're right, that would be what needs to happen. And 
>> again, there is no need for a component discover mechanism here 
>> because Spring is doing it all for you.
>>
>> We can also have the @PostConstruct & @Resource annotations help us 
>> in component discovery like they are now. For instance, take the JMS 
>> transport. To make it easier, we can do:
>>
>> public class JMSTransport implements DestinationFactory {
>>  @Resource DestinationFactoryManager dfm;
>>
>>  @PostConstruct
>>  public void registerDestination() {
>>    dfm.register(namespaces, this);
>>  }
>> }
>>
>> I think the HTTPTransport can already do this in fact. Then a user 
>> can import specific sections of the cxf spring files:
>>
>> The basic beans:
>> <import resource="/org/apache/cxf/spring/cxf.xml"/>
>> The JMS beans:
>> <import resource="/org/apache/cxf/jms/beans.xml"/>
>
>
> Assuming that the content of the transport specific xml files does not 
> include beans for concrete destinations or conduits I don't see the 
> value in that - the same can be achieved with the extension look up 
> without a single line of additional (cfg file) code.

 I think we need to figure out what we're debating about here. First, I 
am not saying we should or should not use Spring as the default 
configuration mechanism. I am saying that we need to allow for this case 
where people are wiring things together themselves. Second, what I am 
saying is that we don't need the Configuration stuff. We can have Spring 
or our own extension lookup thing inject all the stuff we need to.

> The main problem here is that for the transport specific xml files to 
> have any effect their beans (or at least one of them) need to be 
> referenced from within cxf.xml - meaning we'd need a new cxf.xml file 
> every time a new transport/binding is made available.
>
That isn't my understanding. My understanding is that my imports will 
put beans all in the same context. So I can import cxf.xml and jms.xml 
and the jms file can use beans in the cxf.xml.

>>
>> Etc.
>>
>>> Actual instances of  HTTP Destination could be stored in a  
>>> list-type property of the http destination factory:
>>>
>>> <bean id="HTTPDestinationFactory" 
>>> class="org.apache.cxf.transports.http.HTTPTransportFactory">
>>> <property name="destinations">
>>>   <list merge="true">
>>>     <entry ref="myDestination">
>>>     <entry ref="anotherDestination">
>>>  </list>
>>> </property>
>>> </bean>
>>>
>>> but that way they are not related to any specific endpoints. Suppose 
>>> the server had two endpoints, each using their own destination, and 
>>> we wanted to configure those two destinations with different 
>>> HTTPServerPolicies. That seems to suggest the destinations should be 
>>> ref'd by their corresponding endpoint beans (of which we can't have 
>>> any in the default cxf.xml), as in:
>>>
>>> a) <bean 
>>> id="{http://apache.org/hello_world_soap_http}/SOAPService/SOAPPort" 
>>> class="<endpoint bean class>">
>>>    <property name="destination" ref="myDestination"> </bean>
>>>
>>> or  the destinations instances are kept  in a map instead,  keyed 
>>> with the id of the endpoint for which they are used
>>>
>>> b) <bean id="HTTPDestinationFactory" 
>>> class="org.apache.cxf.transports.http.HTTPTransportFactory">
>>> <property name="destinations">
>>>   <map>
>>>     <entry 
>>> key="{http://apache.org/hello_world_soap_http}/SOAPService/SOAPPort" 
>>> value-ref="myDestination">
>>>  </map>
>>> </property>
>>> </bean>
>>>
>>> In case a) the question is what for do we need the 
>>> DestinationFactory and the DestinationFactoryManager at all. and in 
>>> case b) the implementation for the destination factory has to change 
>>> so that (given the id of the endpoint) it returns either a 
>>> pre-injected destination that can be used for the endpoint in 
>>> question or else instantiates a new one - right?
>>> Ditto for bindings.
>>>
>> So this depends a bit on how we want to build up our services. One 
>> way is to have the ServiceBean register activate all the endpoints, 
>> and then provide a reference to an EndpointBean which configures that 
>> specific Endpoint. The EndpointBean would participate in the service 
>> construction via the a ServiceConfiguration for a ServiceFactory.
>>
>> <bean id="helloWorldService" 
>> class="org.apache.cxf.jaxws.JaxWsServiceFactoryBean">
>> <property name="serviceClass" value="...HelloWorld"/>
>> <property name="bus" ref="bus"/>
>> <property name="endpoints">
>>   <map>
>>     <entry key="{endpoint}QName" ref="helloWorldEndpoint"/>
>>   <map>
>> </property>
>> </bean>
>>
>> <bean id="helloWorldEndpoint" 
>> class="org.apache.cxf.spring.EndpointBean">
>> <property name="properties">
>>   <map>
>>     <entry key="HTTPServerPolicy" ref="myServerPolicy"/>
>>   <map>
>> </property>
>> </bean>
>>
>> OR we could have an EndpointBean which actually activates/starts the 
>> endpoint:
>>
>> <bean id="helloWorldService" 
>> class="org.apache.cxf.jaxws.JaxWsServiceFactoryBean" 
>> factory-method="create">
>> <property name="serviceClass" value="...HelloWorld"/>
>> <property name="bus" ref="bus"/>
>> </bean>
>>
>> <bean id="helloWorldEndpoint" 
>> class="org.apache.cxf.spring.EndpointBean">
>> <property name="service" ref="helloWorldService"/>
>> <property name="properties">
>>   <map>
>>     <entry key="HTTPServerPolicy" ref="myServerPolicy"/>
>>   <map>
>> </property>
>> </bean>
>>
>> This all goes back to the contextual lookup. The Destination would be 
>> able to find the server policy via a search through the contexts. 
>> Eventually it would get to 
>> endpointInfo.getProperty("HTTPServerPolicy") and the myServerPolicy 
>> bean would be retrieved. The same concept could be applied to bindings.
>
>
> I strongly disagree. The HTTPServerPolicy is a property of the 
> HTTPDestination - and it should be injected into the HTTPDestination 
> instance and nonwhere else. The fact that the same property value is 
> used for all endpoints in all services, for all endpoints of  
> particular service or only in a particular endpoint is another issue 
> and should be solved by other means (abstract beans, scoping, naming 
> conventions, whatever).
> It's also not clear to me whether in the above you mean to inject it 
> into the endpoint or the endpoint info (as you are saying it would get 
> to endpointInfo.getProperty("HTTPServerPolicy")). But the service 
> model gets built from wsdl or an implementor and is never injected - 
> or is it?
>
I'm kind of confused now. In one case you're saying we need to support 
setting policies in the wsdl for the endpoint. In which case the 
EndpointInfo would've been a logical place to store it.

But you'r re right, a particular destination will have one policy and 
stick to it. In which case there would be no need for associating an 
server policy with an endpoint at all. There could be 5 endpoints which 
use the same destination so it doesn't make sense to associate a policy 
with one endpoint per se. We could just do:

<bean id="httpDestinationFactory" class="....HTTPDestinationFactory">
  <property name="destinations">
    <list>
      <entry ref="destination1"/>
    </list>
  </property>
</bean>

<bean id="destination1" class="...HTTPDestination">
  <property="serverPolicy" ref="customServerPolicy"/>
</bean>

>>
>> I think this has two advantages over a & b above. First, it doesn't 
>> require any special bean naming. Second, it doesn't require the 
>> transport to hold information about the service.
>>
>> We could definitely add a lot of syntax sugar to all this so JAXB 
>> objects and other extensor are directly usable within Spring.
>>
>>>
>>> It is  not clear to me how you want to bridge the application 
>>> specific (for which there are no defaults) with the common 
>>> infrastructure (all the stuff in the default cxf.xml).
>>
>>
>> I would see cxf.xml containing defaults for how things are wired 
>> together. The schema generated beans would be in the context too. So 
>> the HTTPDestinationFactory could reference a default server policy 
>> bean. And a specific HTTPDestination could reference another.
>>
>>> As endpoints and services are always associated with a bus, would 
>>> the bus bean not also have to be overwritten in the user.xml file to 
>>> ref those endpoint beans? 
>>
>>
>> No, because, the Endpoints & Services get built via the EndpointBean 
>> & JaxWsServiceFactoryBean.
>
>
> Yes, but thats the problem I have here: why should the fact that there 
> is a JaxWsServiceFactoryBean involved in creating and publishing the 
> endpoint be exposed to a JAX-WS programmer? The helloWorldService and 
> helloWorldEndpoint serve no purpose themselves other than identifying 
> the 'path' to the myServerPolicy bean (or say the HTTPDestination 
> bean). In so far the combination of these beans does not carry any 
> more information than the single bean
> <bean 
> id="{http://apache.org/hello_world_soap_http}/SOAPService.SOAPPort.http-destination"

> class="JettyHTTPDestination">
>    <property name="httpServer">
>       <value>
>         <http-conf:HTTPServerPolicy ReceiveTimeout="10000" 
> SuppressClientSendErrors="true" ..../>
>      </value>
>   </property>
> </bean>
>
But that bean above doesn't tell Spring to create a service or which bus 
the service is to use or provide places to override the service 
construction defaults. Whereas using the JaxWsServiceFactoryBean does. I 
agree with you that the destination properties probably belong in the 
DestinationFactory, so maybe that wasn't the right example to bring up.

Also, as I mentioned above - a destination isn't even necessarily 
associated with one particular endpoint, it could be associated with 5. 
So having the QName in the id and using that to look it up doesn't make 
sense really. I much prefer the injenction approach. Its much more IoC like.



>>
>> BTW, I'm not  saying that it'd be a bad idea to have a simple built 
>> in discovery mechanism.
>
>
> What do you mean by that? The capability that anywhere in the code we 
> could request a bean from the XmlBeanFactory/ApplicationContext (or a 
> abstraction of that to not depend on Spring exclusively)? I would very 
> much be in favor of that - and it would not take away the option that 
> developers can wire everything together in whatever way they want if 
> they wish to do so. They just would not be forced to do  any wiring 
> when it does not yield a benefit (as in the above example of the 
> EndpointBean, JaxWsServiceFactoryBean, and JettyHTTPDestination beans).
>
I meant I think it would be good to have the extension manager as a 
simple ioc container to manage things for people not using spring. I 
really don't like requesting beans from the ApplicationContext. I think 
containers should do the injection as I outlined in my first email.

I'd write more I'm afraid I have to go now... Will continue some tomorrow...

- Dan

-- 
Dan Diephouse
(616) 971-2053
Envoi Solutions LLC
http://netzooid.com


Mime
View raw message