Differences between revisions 4 and 5
Revision 4 as of 2006-06-30 11:52:00
Size: 3706
Editor: 213
Comment:
Revision 5 as of 2006-06-30 13:25:43
Size: 5056
Editor: 193
Comment:
Deletions are marked like this. Additions are marked like this.
Line 37: Line 37:
We implement this by making getProperty clever:
We also want to be efficient at converting these XMLs into config objects. For example, Spring configs need to be built into application contexts, XSLTs compiled, etc.

So we will maintain a list of "converters" which can convert from the XML to an object. If a given converter is registered, then we always run it on the XML before returning the property. So here is the pseudo-code for getProperty
Line 39: Line 43:
// pseudo code.... this ignores some issues! public class DynamicProperty {
   Mapper xmlMapper;
   Object cache;
   long timeCached;
   String key;
}
    
   
Line 42: Line 54:
    if (obj instanceof o.a.s.DynamicProperty) {
         XMLRegistry r = this.getRegistry;
    if (obj instanceof DynamicProperty) {
         XMLRegistry r = this.getRegistry;
         DynamicProperty dp = (DynamicProperty)obj;
         //have we ever cached this?
         if (dp.cache==null) {
             OMElement el = r.lookup(dp.key);
             Object fresh = null;
             if (dp.xmlMapper==null) fresh = el;
             else fresh = dp.xmlMapper.fromOM(el);
             dp.cache = fresh;
             return fresh;
         }
         // now check if it is up to date
         OMElement el = r.lookupIfModified(dp.key, timeCached);

         if (el == null) { // still good - return cached
             return dp.cache
         };

         if (dp.xmlMapper==null) fresh = el;
         else fresh = dp.xmlMapper.fromOM(el);
         
         
         dp.cache = fresh;
         return fresh;

         
         if (r.isModified,
         Object cached = cache.lookup(key);
         if (cached==null) { // first time reading this

First pass design: There are exactly two registries defined. If we need more later we will refactor.

The core "in-memory" Registry is basically defined by a hashtable. If something is not found there then Synapse automatically looks up the key in the other registry. The other registry is defined by an interface and you can configure the provider using the following XML syntax:

<syn:registry provider="o.a.s.r.HTTPRegistry">
  <property name="prop-for-HTTPRegistry" value="...">
</syn:registry>

At the moment the properties in our config

<property name="" value=""/>

are

  1. only strings
  2. only loaded from this XML (i.e. not pulling in an external resource)

This proposes changing this. Instead of having each mediator pull XML config or metadata in its own way, we can extend the properties to support XML, and then have the mediators grab the XML from the "in-memory" registry. This means that we could remove any "src" tags from mediators and have mediators use a common pattern to access external xml. However, we will still expect mediators to allow inline XML "right there" so as to make the structure easy and clear. So an XSLT can be loaded from a file, in which case its specified at the top using a property; or inlined, when it can be either in a property or in the actual <xslt/> element.

mediator <== property <== (value | inline | src | lookup)

So here is the enhanced property xml structure. It must have exactly one of value, src, key or inline:

 <property name="foo" [value="string"] [src="url to XML"] [key="string-key"]>
   <inline-xml/>
 </property>

Note that the particular approach of <property name="" key=""/> is really just an aliasing mechanism.

If you specify a key then it will lookup the entry *whenever* you use it. Of course we will optimize cache etc this. But the semantic is dynamic.

We also want to be efficient at converting these XMLs into config objects. For example, Spring configs need to be built into application contexts, XSLTs compiled, etc.

So we will maintain a list of "converters" which can convert from the XML to an object. If a given converter is registered, then we always run it on the XML before returning the property. So here is the pseudo-code for getProperty

public class DynamicProperty {
   Mapper xmlMapper;
   Object cache;
   long timeCached;
   String key;
}
    
   

SynapseEnvironment.getProperty(String key) {
    Object obj = hashtable.lookup(key);
    if (obj instanceof DynamicProperty) {
         XMLRegistry r = this.getRegistry;      
         DynamicProperty dp = (DynamicProperty)obj;
         //have we ever cached this?
         if (dp.cache==null) {
             OMElement el = r.lookup(dp.key);
             Object fresh = null;
             if (dp.xmlMapper==null) fresh = el;
             else fresh = dp.xmlMapper.fromOM(el);
             dp.cache = fresh;
             return fresh;
         }
         // now check if it is up to date      
         OMElement el = r.lookupIfModified(dp.key, timeCached);

         if (el == null) { // still good - return cached
             return dp.cache 
         };

         if (dp.xmlMapper==null) fresh = el;
         else fresh = dp.xmlMapper.fromOM(el);
         
         
         dp.cache = fresh;
         return fresh;

         
         if (r.isModified, 
         Object cached = cache.lookup(key);
         if (cached==null) { // first time reading this

         Object obj = r.lookup(key); // actually would use a cache but ignore that
    }
    return obj;
}

The actual pseudo code we typed was:

0. registry.lookupIfModified
1. try lookup in hash as property
2. fails, now lookupRegistry
3. XML -> Object
4. Stick in hash under name
5. next time hits on #1

The core in-memory registry is actually the SynapseEnvironment properties model. The other registry is just a mapping from keys (strings) to XML fragments (OMNode).

SynapseEnvironment {
   ...
   Object getProperty(String name);
   ...
   XMLRegistry getXMLRegistry();
   ...
}

public interface XMLRegistry {
  OMNode lookup (String key);
  OMNode lookupIfModified (String key, long since);
  void insert (key, OMNode);
}

In order to make this model efficient, we need to be able to cache objects: Imagine you have an XSLT that you are looking up from the registry. You want to be able to compile the XSLT only once. When someone asks for it again, you want to check if its been modified, and only recompile if it has.

We haven't yet fully solved this (because we concentrated on the external view) but at least Paul thinks there is a neater way than the current extension definition approach. The idea revolves around a given mediator passing over a "XMLtoObjectMapper" back to the SynapseEnvironment with a given property. Then the property lookup can check if the XML has changed, and only then rerun the compilation/conversion step.

Synapse/InProgress/RegistryAccessThoughts (last edited 2009-09-20 23:05:24 by localhost)