Return-Path: Delivered-To: apmail-incubator-cxf-dev-archive@locus.apache.org Received: (qmail 65324 invoked from network); 24 Aug 2006 17:18:56 -0000 Received: from hermes.apache.org (HELO mail.apache.org) (209.237.227.199) by minotaur.apache.org with SMTP; 24 Aug 2006 17:18:56 -0000 Received: (qmail 6010 invoked by uid 500); 24 Aug 2006 17:18:56 -0000 Delivered-To: apmail-incubator-cxf-dev-archive@incubator.apache.org Received: (qmail 5958 invoked by uid 500); 24 Aug 2006 17:18:55 -0000 Mailing-List: contact cxf-dev-help@incubator.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: cxf-dev@incubator.apache.org Delivered-To: mailing list cxf-dev@incubator.apache.org Received: (qmail 5949 invoked by uid 99); 24 Aug 2006 17:18:55 -0000 Received: from asf.osuosl.org (HELO asf.osuosl.org) (140.211.166.49) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 24 Aug 2006 10:18:55 -0700 X-ASF-Spam-Status: No, hits=0.0 required=10.0 tests= X-Spam-Check-By: apache.org Received-SPF: neutral (asf.osuosl.org: local policy) Received: from [204.127.200.81] (HELO sccrmhc11.comcast.net) (204.127.200.81) by apache.org (qpsmtpd/0.29) with ESMTP; Thu, 24 Aug 2006 10:18:54 -0700 Received: from [192.168.3.100] (c-71-205-191-164.hsd1.mi.comcast.net[71.205.191.164]) by comcast.net (sccrmhc11) with ESMTP id <20060824171831011003cm7re>; Thu, 24 Aug 2006 17:18:31 +0000 Message-ID: <44EDDFAD.5010001@envoisolutions.com> Date: Thu, 24 Aug 2006 13:19:41 -0400 From: Dan Diephouse User-Agent: Thunderbird 1.5.0.5 (Windows/20060719) MIME-Version: 1.0 To: cxf-dev@incubator.apache.org Subject: Re: Configuration APIs References: <44DCAC2F.60805@envoisolutions.com> <44E0A066.8060709@iona.com> <44E0A2EA.1080804@envoisolutions.com> <44EC531E.1050907@iona.com> In-Reply-To: <44EC531E.1050907@iona.com> Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit X-Virus-Checked: Checked by ClamAV on apache.org X-Spam-Rating: minotaur.apache.org 1.6.2 0/1000/N Andrea Smyth wrote: > Dan Diephouse wrote: > >> Andrea Smyth wrote: >> >>> Dan Diephouse wrote: >>> >>>> I'd like to start discussing the Configuration apis for CXF. The >>>> main celtix configuration APIs which have integrated by default are >>>> here: >>>> >>>> http://svn.forge.objectweb.org/cgi-bin/viewcvs.cgi/celtix/trunk/celtix-common/src/main/java/org/objectweb/celtix/configuration/ >>>> >>>> >>>> For those who aren't familiar with Celtix, let me try to outline >>>> how this works. There is a tree of Configuration objects. >>>> Configurations allow to look up a value like so: >>>> >>>> Configuration config = >>>> getBus().getConfiguration().get.Child(HTTP_LISTENER_CONFIGURATION_URI); >>>> >>>> HTTPListenerPolicy policy = >>>> config.getObject(HTTPListenerPolicy.class, "httpListener"); >>>> >>>> Where the Bus is kind of the central object in Celtix. It has a >>>> configuration root node which is accessed via >>>> bus.getConfiguration(). When initializing the bus a >>>> ConfigurationBuilder is used to build Configurations. These >>>> Configurations are backed by ConfigurationProviders. >>>> ConfigurationProviders provide the actual objects. So there is a >>>> Spring ConfigurationProvider which looks up beans from the Spring >>>> context. There is also one which will pull configuration out of a >>>> WSDL. The objects (like HTTPListenerPolicy) are built from XML and >>>> are JAXB beans defined by a schema. >>>> >>>> Here's a more concrete example: >>>> >>>> http://svn.forge.objectweb.org/cgi-bin/viewcvs.cgi/celtix/trunk/celtix-distribution/src/main/samples/configuration/client.xml?view=auto&rev=947 >>>> >>>> >>>> Here the configuration is backed by spring. The beans are looked up >>>> by convention - to get the configuration for the web service port >>>> Celtix uses the id format of "BUS_ID.SERVICE_NAME.PORT_NAME". Which >>>> turns into the format you see there. >>>> >>>> Requirements that this meets: >>>> 1. Live replacement of a configuration in the system. Since an >>>> HTTPListenerPolicy is queried every time a listener is created, we >>>> just need to replace it in the configuration tree and the effects >>>> will be seen across the system. It is relatively easy to have a JMX >>>> component which does this. >>>> 2. Ability to have configuration come from multiple sources - wsdl, >>>> spring, etc. For instance, I could set up a policy for a specific >>>> endpoint in my WSDL and have a default policy in my spring config. >>>> 3. Allows configuration to be schema validated. (This is oppsed to >>>> say the spring approach where you type and >>>> hope that it is actually a property). >>>> 4. Creates a relatively straightforward way to supply >>>> configurations in the standard case. A user just writes their >>>> Spring definition with the standard name and its configured. >>>> >>>> --- >>>> >>>> Hopefully I've explained this somewhat well. Now, I want to talk >>>> about what I don't like about it. >>>> >>>> 1. Its not very IoC like. Control is not inverted. For instance, >>>> the Celtix spring integration looks up beans from the context >>>> instead of >>>> having the beans be injected in. This loses a lot of the power of >>>> Spring as I can't control how things are wired up. Instead Celtix >>>> is controlling it for me. >>>> >>>> 2. It is not very friendly to people just using the API and wiring >>>> things up themselves (like embedders and people doing unit tests) . >>>> Instead of doing something like this: >>>> >>>> HTTPListenerPolicy policy = new HTTPListenerPolicy() >>>> httptransport = new HTTPTransport(); >>>> httptransport.setPolicy(policy); >>>> >>>> I have to do: >>>> >>>> HTTPListenerPolicy policy = new HTTPListenerPolicy() >>>> ConfigurationImpl c = new ConfigurationImpl(); >>>> c.setObject("httpListenerPolicy", policy); >>>> getBus().getConfiguration().setChild(HTTP_LISTENER_CONFIGURATION_URI, >>>> c); >>>> new HTTPTransport(getBus()); >>>> >>>> IMO, the API should focus on making itself a great API and friendly >>>> to developers. This isn't very developer friendly, it is completely >>>> focused on people building things from XML. >>>> >>>> Furthermore this relies on me instantiating the Bus and loading all >>>> the configurations. What if I don't want to load the Bus? What if I >>>> want to mock the bus? This isn't very easy with the current setup. >>>> >>>> 3. It is not very friendly to other containers >>>> Not all containers provide an String/id based mechanism to look up >>>> objects. And not all provide easy ways to setup jaxb beans. Some, >>>> like Plexus/Pico, are more component based than bean based. It >>>> would be much easier if the configuration was part of the object >>>> (ala point #2 above), than if it had to be looked up from a >>>> Configuration. >>>> >>>> --- >>>> >>>> What I would like to propose is this: >>>> 1. Remove the Configuration APIs and use getter/setter/constructor >>>> injenction. >>> >>>> >>>> 2 Still use JAXB generated beans from schema. In addition to this >>>> though, take the default values which are in the schema and have >>>> the "default value plugin" from the JAXB project preinit the >>>> private fields with those values. (i.e. >>> default="10"/> would turn into "private int timeout = 10;") >>>> >>> Hi Dan, >>> >>> For 1. and 2 to work - do you envision the configurable components >>> to inherit from their generated beans (instead of delegate to them >>> as is the case now)? >> >> I'd probably prefer that the Transports took a configuration as a >> property instead. That way we can find the most appropriate >> configuration, and then apply. For instance: >> >> HTTPTransportPolicy transportPolicy = >> operation.get(HTTP_TRANSPORT_POLICY); >> if (transportPolicy == null) >> transportPolicy = endpoint.get(HTTP_TRANSPORT_POLICY): >> >> if (transportPolicy == null) >> transportPolicy = service.get(HTTP_TRANSPORT_POLICY): >> >> if (transportPolicy == null) >> transportPolicy = getDefaultPolicy(); >> >> Obviously we could encode this logic to be more compact (i.e. I want >> a method which will search a hierarchy of Maps for any property), but >> I think it gets the idea across that a transport policy could come >> from any location. So I don't think it makes sense to have transports >> extend their configuration. > > I am not sure I understand what you are getting at here: > If you say you want to use getter/setter/constructor injection, what > do you want to inject into? Say in the case of the http server > transport, the transport itself has properties httpServer, > authorization, sslServer, contextMatchStrategy (of type > HTTPServerPolicy, AuthorizationPolicy, SSLServerPolicy, String resp), > and these get injected. I don't see how there is injenction currently. It is all a lookup from the configuration: configuration = createConfiguration(bus, endpointInfo); policy = getServerPolicy(configuration); And the getServerPolicy method: private HTTPServerPolicy getServerPolicy(Configuration conf) { HTTPServerPolicy pol = conf.getObject(HTTPServerPolicy.class, "httpServer"); if (pol == null) { pol = new HTTPServerPolicy(); } return pol; } In my mind it should just be new HttpDestination(serverPolicy). > Now, for "nice xml" in Spring configuration, you'd have to associate > associate (via a NamespaceHandler, BeanDefinitionParser) a schema with > the http server transport (the bean). > While Spring 2,0 rc3 docs describe how to do this mapping manually and > does not mention tools for automation, I believe it should be > automated. There are two ways do do that: > a) Start with a schema and generate an (abstract base) bean - from > which the real bean inherits (that's what I was referring to), or > b) Start with the bean implementation and generate the schema, using > standard @Resource or some custom annotation. > I agree, and I am fine with either of these options. Option a sounds like we would be plugging in JAXB beans. Option b sounds like the XBean stuff. >>> We could even vamp up the generated beans from being pure Jaxws >>> generated beans to also meet the 'configuration from multiple >>> sources' requirement. And use the generic CXF management framework >>> (a layer above JMX) to remote manage those beans and so on. >> >> How exactly are you thinking of vamping up the beans? > > If the abstract base bean is generated, it could be generated with > getters that use additional configuration providers in case no value > was injected. Generated getters would first check if the data member > provides a value, and if that is not the case, ask the registered > configuration providers in turn to find a value (and in that sense > would actually behave very similar to the current Configuration object). > In your example above this could be done by a configuration provider > that introspects the service model, and as such would allow to pull in > wsdl extensions - added to the port, the service, the binding > elements, much like as WS-Policy. It's basically what you call a > method that "searches a hierarchy of maps for a property". I am > actually using such a provider already in the http transport - except > that in case it only checks the endpoint info's property map (because > we only expect HTTPServerPolicy as an extension element of the WSDL > port element). > A service model based configuration provider is only one example of > retrieving values if none were injected - there may be other sources > of information, and the service model should not hold information that > is not model related. > > Does that make sense? > Kind of... So you're saying that instead of just using POJOS, we'd extend the generated POJOs so they had the smarts to pull data from other places like the service model? I do see that you have the ability to search the service model for configuration values, like the HTTPServicePolicy, but I don't like the way it is done. It goes back to the things I said in the first email about why we shouldn't be doing Configuration/ConfigurationProvider stuff. It isn't friendly for testing, embedding, api users, etc and creates unnecessary indirection. I'd much prefer the following method of finding the apropriate HTTPServerPolicy: HTTPServerPolicy policy = endpoint.get(HTTPServicerPolicy.class); if (policy == null) getServicePolicy(); // the the server policy that was injected in the constructor (see above) Cheers, - Dan -- Dan Diephouse Envoi Solutions http://envoisolutions.com http://netzooid.com/blog