cxf-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Andrea Smyth <andrea.sm...@iona.com>
Subject Re: Configuration APIs
Date Thu, 31 Aug 2006 11:22:08 GMT
Dan Diephouse wrote:

> 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.

Yes, but beans in the jms file are only instantiated (and then use beans 
in the cxf file)  if a) they are referenced from beans in the cxf or the 
users file or b) the code explicitly requests a bean in the jms file.

>
>>>
>>> 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.

The policy belongs to the destination - and that is defaulted or 
replaced by something injected into the destination. What I mean to say 
is that we need multiple sources to participate in performing the 
injection: the container on the one hand and wsdl/the service model on 
the other.

>
> 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.

My understanding is that multiple destinations can share one listener 
but to allow different endpoints to have independent lifecycles (i.e to 
be shut down at different times) they'd each need their own destination.

> 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.

or rather: not using top down dependency injection performed by any 
container like Spring. These users would use the bus factory that we 
have now - using the extension manager.

> I really don't like requesting beans from the ApplicationContext. I 
> think containers should do the injection as I outlined in my first email.

If you used a bus factory that is based on Spring or another container 
then you would not have to (request beans from the ApplicationContext).
So why not support both approaches?

Andrea.

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


Mime
View raw message