Hi -
I was successful in implementing the behavior I was after. Attached is
an implementation of a WildcardMatchMap class that allows for mapping of
multiple keys that match a given pattern to a single common string. I
included some comments in the class header describing how it can be used
in conjunction with XmlBeans - basically identical to the steps David
provided. The upshot is that I can now set up my services that are based
on XmlBeans so that they still work when messages are received from
Service Clients based on newer versions of a service schema.
Thanks for the help!
-Oliver
Oliver Newell wrote:
David - Thanks - that does help!
Maybe I can just create a suitable WildcardMatchMap<String,String>
object that conforms to the Map interface? I'll give that a shot and
post on success :-) (or failure :-( )
-Oliver
David Jencks wrote:
AFAIK there's no wildcard support but there is support for swapping
known namespaces when you read a document.
private static Map<String, String> NAMESPACE_UPDATES = new
HashMap<String, String>();
//load the map somehow
XmlOptions options = new XmlOptions();
options.setLoadSubstituteNamespaces(NAMESPACE_UPDATES);
XmlObject parsed = XmlObject.Factory.parse(element, options);
If you want to pursue wildcards I'd look for what happens to this map
in the xmlbeans code. I think that its fed into the STAX layer:
OpenEJB does something similar with something that just plugs into STAX.
hope this helps
david jencks
On Aug 31, 2007, at 12:57 PM, Oliver Newell wrote:
Hi - I'm working with a set of schemas that embed numbers of the
form $major.$minor in the XML namespaces to convey version
information. The numbering scheme extends to the imported namespaces
- not just the target namespace of the schema, as shown below. By
convention, minor numbers are used to indicate changes that are
backwards compatible with previous versions - /additions/ to the
schema. Major numbers are incremented when changes are made that
break backwards compatibility.
<?xml version="1.0" encoding="UTF-8" ?>
<WMS_Capabilities xmlns="http://www.opengis.net/wms/1.3"
xmlns:gml="http://www.opengis.net/gml/3.1" >
<Service>
<Name>Web Map Service</Name>
<KeywordList>
<Keyword>Topography</Keyword>
<Keyword>Contour</Keyword>
</KeywordList>
etc.....
</Service>
</WMS_Capabilities>
I am interested in having the capability for XMLBeans-based
applications to happily consume instance documents that are produced
using new minor versions of a schema. I also want to only generating
new package names for new major versions of the schema. I see there
is a facility in the XMLBeans configuration mechanism to specify the
package names that are generated, so I can do the latter. I don't
see a way to do the former - it seems like some kind of a wildcard
mapping rule is needed so that an application based on version 1.3
of a schema will know how to unmarshall a version 1.4 instance
document to the 1.3 data model. In other words, a configuration rule
that stated something like:
http://www.opengis.net/wms/1.* --> mapsTo -->
http://www.opengis.net/wms/1
so that all versions with major number of 1 map to the same
namespace as far as XMLbeans is concerned.
The usefulness of the wildcard capability wouldn't be limited to the
particular $major.$minor numbering approach shown above. It should
also be capable of supporting some of the W3C namespace versioning
practices (which tend to embed a year in the namespace). This
capability would allow for significantly increased system agility as
schemas evolve. Right now, if I bump a minor version number in a
schema namespace, I have to make sure ALL XMLBeans consumers are
updated to use the new namespace, which isn't very practical for the
distributed, 24/7 systems we are working on.
Is there an existing way to accomplish what I am describing in
XMLBeans? If not, is there any developer interest, or can someone
give me a hint as to how hard this would be to implement? (and where
to start?)
Thanks!
-Oliver
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]
/*
*/
package edu.mit.ll.common.util;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Map;
import java.util.Set;
import java.util.Iterator;
import java.util.AbstractMap;
import java.util.AbstractSet;
import java.util.regex.*;
/**
* Map implementation that supports wildcards. This allows for a number
* of strings that matches a given pattern to be mapped to a single
* common string.
*
* This class was originally written for the purpose of mapping XML
* namespaces to their 'ancestors' when the namespaces are set up to
* include versioning information (typically using major/minor version
* numbers at the end of each namespace). This is useful when implementing
* applications using Java/XML binding technologies (e.g. XMLBeans) to
* allow the applications to remain compatible with incoming XML messages
* whose namespaces have been modified to reflect new (but backwards-
* compatible) capabilities.
*
* The following code fragment illustrates the usage in the context of
* XmlBeans. In this example, the application is being built with
* objects that use the "http://www.opengis.net/wcs/1.1" and
* "http://www.opengis.net/ows/2.1" XML namespaces. In order to make
* the application work with new versions of the schema that are
* backwards-compatible (only minor version changes), mappings are
* created that make namespaces matching the patterns 'wcs/1.*' and
* 'ows/2.*' map to 'wcs/1.1' and 'ows/2.1', respectively.
*
* ...
*
* WildcardMatchMap map = new WildcardMatchMap();
* map.put("http://www.opengis.net/wcs/1\\..*",
* "http://www.opengis.net/wcs/1.1" );
* map.put("http://www.opengis.net/ows/2\\..*",
* "http://www.opengis.net/ows/2.1" );
*
* XmlOptions options = new XmlOptions();
* options.setLoadSubstituteNamespaces( map );
*
* InputStream xmlStream = getClass().getResourceAsStream( resourceName );
*
* net.opengis.wcs.v1.GetCapabilitiesDocument getCapDoc =
* net.opengis.wcs.v1.GetCapabilitiesDocument.Factory.parse( xmlStream,
* options );
*
* ....
*
*
* Note that XmlBeans is tolerant of unknown elements as well as newly-added
* namespaces. Coupled with the namespace mapping capability above, this
* provides the flexibility needed to manage the schema versioning problem.
*
*/
public class WildcardMatchMap extends AbstractMap
implements Cloneable, Serializable
{
/**
* Map entry - The assumption is that each key is a regular expression
* pattern. For efficiency, the pattern is compiled once when the Entry
* is created.
*/
static class Entry implements Map.Entry {
protected Object key, value;
protected Pattern patt;
public Entry(Object key, Object value) {
this.key = key;
this.value = value;
this.patt = Pattern.compile( (String)key, Pattern.DOTALL );
}
public Object getKey() {
return key;
}
public Object getValue() {
return value;
}
public Pattern getPatt() {
return patt;
}
public Object setValue(Object newValue) {
Object oldValue = value;
value = newValue;
return oldValue;
}
public boolean equals(Object o) {
if (!(o instanceof Map.Entry)) {
return false;
}
Map.Entry e = (Map.Entry)o;
return (key==null ? e.getKey()==null : key.equals(e.getKey())) &&
(value==null ? e.getValue()==null : value.equals(e.getValue()));
}
public int hashCode() {
int keyHash = (key==null ? 0 : key.hashCode());
int valueHash = (value==null ? 0 : value.hashCode());
return keyHash ^ valueHash;
}
public String toString() {
return key + "=" + value;
}
}
private Set entries = null;
private ArrayList list;
public WildcardMatchMap() {
list = new ArrayList();
}
public WildcardMatchMap(Map map) {
list = new ArrayList();
putAll(map);
}
public WildcardMatchMap(int initialCapacity) {
list = new ArrayList(initialCapacity);
}
public Set entrySet() {
if (entries==null) {
entries = new AbstractSet() {
public void clear() {
list.clear();
}
public Iterator iterator() {
return list.iterator();
}
public int size() {
return list.size();
}
};
}
return entries;
}
public Object put(Object key, Object value) {
int size = list.size();
Entry entry = null;
int i;
if (key==null) {
for (i=0; i<size; i++) {
entry = (Entry)(list.get(i));
if (entry.getKey() == null) {
break;
}
}
} else {
for (i=0; i<size; i++) {
entry = (Entry)(list.get(i));
if (key.equals(entry.getKey())) {
break;
}
}
}
Object oldValue = null;
if (i<size) {
oldValue = entry.getValue();
entry.setValue(value);
} else {
list.add(new Entry(key, value));
}
return oldValue;
}
/**
* Check if map contains the specified key. Unlike most map implementations,
* an exact match is not performed in this case. Rather, a check is made
* to see if the key matches one of the wildcard patterns stored in the
* map, and if so, returns true.
*/
public boolean containsKey(Object key) {
Iterator<Entry> i = entrySet().iterator();
if (key==null) {
while (i.hasNext()) {
Entry e = i.next();
if (e.getKey()==null)
return true;
}
} else {
while (i.hasNext()) {
Entry e = i.next();
//
// Check direct comparison first, then pattern match (optimization)
//
if (key.equals(e.getKey()))
return true;
Matcher matcher = e.getPatt().matcher( (String)key );
if( matcher.find() )
return true;
}
}
return false;
}
/**
* Get the object associated with the specified key. Unlike most map
* implementations, an exact match is not performed in this case.
* Rather, a check is made to see if the key matches one of the
* wildcard patterns stored in the map, and if so, the map value
* associated with the pattern is returned.
*/
public Object get(Object key) {
Iterator<Entry> i = entrySet().iterator();
if (key==null) {
while (i.hasNext()) {
Entry e = i.next();
if (e.getKey()==null)
return e.getValue();
}
} else {
while (i.hasNext()) {
Entry e = i.next();
//
// Check direct comparison first, then pattern match (optimization)
//
if (key.equals(e.getKey()))
{
return e.getValue();
}
else
{
Matcher matcher = e.getPatt().matcher( (String)key );
if( matcher.find() )
{
return e.getValue();
}
}
}
}
return null;
}
public Object clone() {
return new WildcardMatchMap(this);
}
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]