The issue will be there until the jcr provider actually allows re-write of the namespace. If you look at the sources, SM calls the generic API. If the implementation supports it, everything works, if not you'll get the exception (which is thrown by the implementation itself).
croudet,
It is possible to subclass the JcrSessionFactory, and simlply rewrite registerNamespaces such then it checks an "ignoreRegisteredNamespaces" flag. If the flag is set to true, then already registered namespaces are ignored iff the already registered namespace matches the new one (both prefix and uri) -- otherwise throw a namespace exception. I realize that this is not an ideal solution, but it can get namespaces useable with very few changes.
Costin,
I am not sure you want such a hack checked in, but you could build it such that the JcrSessionFactory's registerNamespaces() used the code that checked ignoreRegisteredNamespaces. the ignoreRegisteredNamespaces could be protected, then create a JackrabbitJcrSessionFactory would just set the flag to true on construction.
This is what I put together for this. It could definitely use improvement, but it works:
Code:
package org.springmodules.jcr.jackrabbit.ext;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import javax.jcr.NamespaceException;
import javax.jcr.NamespaceRegistry;
import javax.jcr.RepositoryException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springmodules.jcr.JcrSessionFactory;
public class JackrabbitJcrSessionFactory extends JcrSessionFactory {
private static final Log log = LogFactory.getLog(JcrSessionFactory.class);
private boolean ignoreRegisteredNamespaces = true;
/**
* Register the namespaces.
*
* @param session
* @throws RepositoryException
*/
protected void registerNamespaces() throws RepositoryException {
// this is a hack, because the superclass declares overwrittenNamespaces private, without accessors
Map overwrittenNamespaces = new HashMap();
Map ignoredNamespaces = new HashMap();
if (getNamespaces() == null || getNamespaces().isEmpty())
return;
if (log.isDebugEnabled())
log.debug("registering custom namespaces " + getNamespaces());
NamespaceRegistry registry = getSession().getWorkspace()
.getNamespaceRegistry();
// unregister namespaces if told so
if (isForceNamespacesRegistration()) {
// save the old namespace only if it makes sense
if (!isKeepNamespaces())
overwrittenNamespaces = new HashMap(getNamespaces().size());
// do the lookup, so we avoid exceptions
String[] prefixes = registry.getPrefixes();
// sort the array
Arrays.sort(prefixes);
// search occurences
for (Iterator iter = getNamespaces().keySet().iterator(); iter.hasNext();) {
String prefix = (String) iter.next();
int position = Arrays.binarySearch(prefixes, prefix);
if (position >= 0) {
if (log.isDebugEnabled()) {
log.debug("prefix " + prefix
+ " was already registered; unregistering it");
}
if (!isKeepNamespaces()) {
// save old namespace
overwrittenNamespaces.put(prefix, registry
.getURI(prefix));
}
if (!ignoreRegisteredNamespaces) {
registry.unregisterNamespace(prefix);
} else {
String oldUri = registry.getURI(prefix);
String newUri = getNamespaces().getProperty(prefix);
if (!oldUri.equals(newUri)) {
throw new NamespaceException("prefix " + prefix + " was registered with uri " + oldUri +
", but is trying to be reregistered with " + newUri);
}
ignoredNamespaces.put(prefix, oldUri);
}
// postpone registration for later
}
}
}
// do the registration
for (Iterator iter = getNamespaces().entrySet().iterator(); iter.hasNext();) {
Map.Entry namespace = (Map.Entry) iter.next();
if (!ignoredNamespaces.containsKey(namespace.getKey())) {
registry.registerNamespace((String) namespace.getKey(),
(String) namespace.getValue());
}
}
}
public boolean isIgnoreRegisteredNamespaces() {
return ignoreRegisteredNamespaces;
}
public void setIgnoreRegisteredNamespaces(boolean ignoreRegisteredNamespaces) {
this.ignoreRegisteredNamespaces = ignoreRegisteredNamespaces;
}
}
Just a thought.
DW