View Full Version : Ability to add object definition in XmlElement to registry?
apiwoni
11-01-2005, 12:17 AM
Given following XML,
<plugin>
<extension point="PointA">
<object
id="springObjectA"
name="springObjectA"
type="SpringApplication.SpringObjectA, SpringApplication"
singleton="true" />
</extension>
</plugin>
I would like to use my own parser to handle <plugin> section and invoke Spring framework to handle <object> section. I don't expect Spring to parse entire file but I would expect it to handle XmlElement for object. Having said that, once XmlApplicationContext is created with xml file, is it currently possible to add to registry, especially using XmlElement? If so, once added to the registry what else need to be done to configure object.
Good control over object registry can be very helpful in integrating Spring.NET in other frameworks.
Sincerely,
Andre
Rick Evans
11-02-2005, 10:04 PM
Hi Andre
Work is currently underway to allow the extension of the parser so that we, the Spring team, can provide built in custom elements, and so that users such as yourself can contribute / define your own elements.
This will (in time) lead to configuration such as this...
<object id="myServiceObject" class="Foo.Bar, Foo">
<tx:transactional/>
</object>
This would result in the creation of a transactional proxy (with default transaction semantics) for the 'myServiceObject' service object, skipping all of that noisy TransactionProxyFactoryObject configuration that is (currently) required.
Please bear in mind that the above syntax is config that I have conjured up out of my head based on some discussions I have been having with the Spring (for Java) team (they too are currently implementing this feature).
The exact mechanism for achieving this functionality is currently being prototyped... I believe it will address the issue you have raised, in that you as an end user application developer or framework provider will be able to define your own 'element handlers' and register them with the Spring configuratoin mechanism so that you can have, for example, a 'plugin' element in a Spring.NET config file.
Like I say, its all being prototyped at the moment... I'll ping back when something more concrete is in the offing and some code has been comitted to the sandbox. (I don't envision it being implemented in the 1.1 timeframe though).
Ciao
Rick
Aleks Seovic
11-03-2005, 01:03 AM
Actually, the example Rick described is probably a bad example and something I don't agree with right now. My standard example is related to simplified AOP definitions:
<object id="accountService" type="MyApp.MyAccountService"/>
<aop:aspect name="transactions">
<aop:pointcut name="transactionalMethods" classes="*" methods="*[@Transaction]"/>
<aop:advice type="xyz.TransactionAdvice" applies-to="transactionalMethods"/>
</aop:aspect>
Custom parser would process all elements from the 'aop' namespace and create and register standard object definitions for them. Keep in mind that <aop:pointcut> and <aop:advice> are really just a special cases of the standard <object> element -- they allow you to specify some of the properties directly as attributes, but you could also have <property>, <constructor-arg> and other standard elements within them.
There is functionality in the framework right now that allows you to define custom parsers based on the XML namespace of the element. However, I'm not sure if it will do right now what both you and I need (allow you to nest some standard elements within custom ones).
If you want to play with it you can simply add something like this to your application's main config file:
<configuration>
<configSections>
<sectionGroup name="spring">
<section name="configParsers" type="Spring.Context.Support.ConfigParsersSectionHandler , Spring.Core"/>
...
</sectionGroup>
</configSections>
<spring>
<configParsers>
<parser namespace="http://myNamespace/plugins" type="MyFramework.Config.PluginConfigParser, MyFramework"/>
</configParsers>
...
</spring>
...
</configuration>
You would then have to make sure that your custom elements are defined in the namespace you specified and your parser should be invoked for them. Oh yeah, your custom parser has to implement Spring.Objects.Factory.Xml.IXmlObjectDefinitionPar ser interface.
Let me know if you try this,
Aleks
P.S. If you would rather register parser programatically, you can call static XmlParserResolver.RegisterParser method, passing namespace and parser type as parameters.
apiwoni
11-17-2005, 09:49 PM
Hi Rick,
Having custom element handlers registered with the Spring configuration mechanism is one way to take care of some of my problems.
You can allow Spring framework to parse sample XML file and let handlers do any custom work. But you could also let an application specific parser to parse this file and then let Spring parser do its work. Last time I looked at Spring.NET source code I coudn't find a way to add new object definitions to XMLApplicationContext once spring objects file was parsed.
It would be good to have something like this:
XMLApplicationContext.add(XmlElement node).
Thank you for your response.
Cheers!
Andre
apiwoni
11-17-2005, 10:02 PM
Hi Aleks,
Allowing to register parser for a namespace is a very good idea, though, like you said, I don't know about nesting standard elements within custom ones.
Again, it would be good to add XmlElement to XmlApplicationContext which is a different issue.
When, and if, I get some time I'd like to test parser for my own namespace.
I'll let you know if I try this.
Thanks for you respose!
Andre
Mark Pollack
11-18-2005, 07:07 PM
Hi Andre,
I wrote a sample for registering a custom parser - damn embarrasing as we can't use "configParsers" as the section name since
System.Configuration.ConfigurationException: Tag names beginning with config are reserved
which is what is in the latest release :oops: I'll get a cvs tarball out there with this fix asap. I've changed the name to be "parsers" instead.
That said, here is a minimal example of using a custom schema for the "TestObject" we use in the unit tests.
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<configSections>
<sectionGroup name='spring'>
<section name="parsers" type="Spring.Context.Support.ConfigParsersSectionHandler , Spring.Core" />
<section name='context' type='Spring.Context.Support.ContextHandler, Spring.Core' />
<section name='objects' type='Spring.Context.Support.DefaultSectionHandler , Spring.Core' />
</sectionGroup>
</configSections>
<spring>
<parsers>
<parser namespace="http://schemas.springframework.net/testobject"
type="Spring.Context.Support.TestObjectConfigParser, Spring.Core.Tests" />
</parsers>
<context>
<resource uri='config://spring/objects' />
</context>
<objects xmlns="http://www.springframework.net">
<object id="Parent" type="Spring.Objects.TestObject,Spring.Core.Tests">
<property name="name" value="Parent" />
</object>
<testobject xmlns="http://schemas.springframework.net/testobject">
<age>12</age>
<name>John</name>
</testobject>
</objects>
</spring>
</configuration>
And a very simple parser is
public class TestObjectConfigParser : DefaultXmlObjectDefinitionParser
{
public TestObjectConfigParser()
{
}
public override int ParseRootElement(XmlElement root, XmlResourceReader reader)
{
return 0;
}
public override int ParseElement(XmlElement element, XmlResourceReader reader)
{
ObjectDefinitionHolder holder = ParseTestObjectDefinition(element, reader);
if (holder == null)
{
return 0;
}
ObjectDefinitionReaderUtils.RegisterObjectDefiniti on(holder, reader.ObjectReader.Registry);
//We created one object.
return 1;
}
private ObjectDefinitionHolder ParseTestObjectDefinition(XmlElement rootElement, XmlResourceReader reader)
{
MutablePropertyValues properties = new MutablePropertyValues();
XmlNodeList childNodes = rootElement.ChildNodes;
//Get the age text
string agePropValue = childNodes[0].InnerText;
properties.Add(new PropertyValue("Age", agePropValue));
string namePropValue = childNodes[1].InnerText;
properties.Add(new PropertyValue("Name", namePropValue));
IConfigurableObjectDefinition od = new RootObjectDefinition(typeof (TestObject), null, properties);
od.IsSingleton = false;
//HardCoded for now.
string id = "testObject";
//id = ObjectDefinitionReaderUtils.GenerateObjectName(od, reader.ObjectReader.Registry);
return new ObjectDefinitionHolder(od, id);
}
}
We will have to look into the ability to add object definitions to the context after it has been created. I gather the usecase you have in mind is dynamic plugins.
Allowing the Spring schema to be nested inside your schema.. To support that we would probably have to make the current Spring schema more modular so that bits of it could be imported into your schema. I never really thought of it because I thought the whole purpose of having custom schema was to get away from the generic reflection like usage and provide "domain" specific elements and attributes. Now that you mention it I can see how reusing bits and pieces maybe nice, for example lists and maps. The implementation of your parser would then probably have to call inherited methods from DefaultXmlObjectDefinitionParser, some of which are probably private now.
Cheers,
Mark
vBulletin® v3.7.3, Copyright ©2000-2008, Jelsoft Enterprises Ltd.