blob: 5a6d5611f971da0f00ef4454d98eb76f4c56917c [file] [log] [blame]
/*
* Copyright 2004-2005 The Apache Software Foundation or its licensors,
* as applicable.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.jackrabbit.session;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Properties;
import java.util.Set;
import javax.jcr.NamespaceException;
import javax.jcr.NamespaceRegistry;
import javax.jcr.RepositoryException;
import javax.jcr.UnsupportedRepositoryOperationException;
import org.apache.xerces.util.XMLChar;
public final class SessionNamespaceRegistry implements NamespaceRegistry {
/** The underlying global namespace registry. */
private final NamespaceRegistry registry;
/** Local prefix to namespace URI mappings. */
private final Properties prefixToURI;
/** Local namespace URI to prefix mappings. */
private final Properties uriToPrefix;
/** The global prefixes hidden by local mappings. */
private final Set hiddenPrefixes;
/**
* Creates a local namespace registry based on the given global
* namespace registry. The local namespace mappings are initially empty.
*
* @param registry global namespace registry
*/
public SessionNamespaceRegistry(NamespaceRegistry registry) {
this.registry = registry;
this.prefixToURI = new Properties();
this.uriToPrefix = new Properties();
this.hiddenPrefixes = new HashSet();
}
/**
* Creates a local namespace mapping. See the JCR specification
* for the details of this rather complex operation.
* <p>
* This method implements the specified semantics of the
* Session.setNamespacePrefix method. Session implementations can use
* this method as follows:
* <pre>
* NamespaceRegistry registry = new SessionNamespaceRegistry(
* getWorkspace().getNamespaceRegistry());
*
* public void setNamespacePrefix(String prefix, String uri)
* throws NamespaceException, RepositoryException {
* return registry.registerNamespace(prefix, uri);
* }
* </pre>
*
* @param prefix namespace prefix
* @param uri namespace URI
* @throws NamespaceException if the given namespace mapping is invalid
* @throws RepositoryException on repository errors
* @see NamespaceRegistry#registerNamespace(String, String)
* @see javax.jcr.Session#setNamespacePrefix(String, String)
*/
public void registerNamespace(String prefix, String uri)
throws NamespaceException, RepositoryException {
if (prefix.length() == 0) {
throw new NamespaceException("The empty prefix is reserved");
} else if (uri.length() == 0) {
throw new NamespaceException("The empty namespace URI is reserved");
} else if (prefix.toLowerCase().startsWith("xml")) {
throw new NamespaceException("The xml* prefixes are reserved");
} else if (!XMLChar.isValidNCName(prefix)) {
throw new NamespaceException("Invalid prefix format");
}
// Note: throws a NamespaceException if the URI is not registered
String oldPrefix = getPrefix(uri);
String oldURI;
try {
oldURI = getURI(prefix);
} catch (NamespaceException e) {
oldURI = null;
}
if (oldURI == null) {
hiddenPrefixes.add(oldPrefix);
prefixToURI.remove(oldPrefix);
prefixToURI.setProperty(prefix, uri);
uriToPrefix.setProperty(uri, prefix);
} else if (!uri.equals(oldURI)) {
throw new NamespaceException(
"Cannot hide an existing namespace mapping");
}
}
/**
* Not implemented. It is not possible to unregister namespaces from
* a session, you need to access the global namespace registry directly.
*
* @param prefix namespace prefix
* @throws UnsupportedRepositoryOperationException always thrown
*/
public void unregisterNamespace(String prefix)
throws UnsupportedRepositoryOperationException {
throw new UnsupportedRepositoryOperationException();
}
/**
* Returns the currently mapped namespace prefixes. The returned set
* contains all locally mapped prefixes and those global prefixes that
* have not been hidden by local mappings.
* <p>
* This method implements the specified semantics of the
* Session.getNamespacePrefixes method. Session implementations can use
* this method as follows:
* <pre>
* NamespaceRegistry registry = new SessionNamespaceRegistry(
* getWorkspace().getNamespaceRegistry());
*
* public String getNamespacePrefixes() throws RepositoryException {
* return registry.getPrefixes();
* }
* </pre>
*
* @return namespace prefixes
* @throws RepositoryException on repository errors
* @see NamespaceRegistry#getPrefixes()
* @see javax.jcr.Session#getNamespacePrefixes()
*/
public String[] getPrefixes() throws RepositoryException {
HashSet prefixes = new HashSet();
prefixes.addAll(Arrays.asList(registry.getPrefixes()));
prefixes.removeAll(hiddenPrefixes);
prefixes.addAll(prefixToURI.keySet());
return (String[]) prefixes.toArray(new String[prefixes.size()]);
}
/**
* Returns the registered namespace URIs. This method call is simply
* forwarded to the underlying global namespace registry as it is not
* possible to locally add new namespace URIs.
*
* @return namespace URIs
* @throws RepositoryException on repository errors
* @see NamespaceRegistry#getURIs()
*/
public String[] getURIs() throws RepositoryException {
return registry.getURIs();
}
/**
* Returns the namespace URI that is mapped to the given prefix.
* Returns the local namespace mapping if the prefix is locally
* mapped, otherwise falls back to the underlying global namespace
* registry unless the prefix has been hidden by local namespace
* mappings.
* <p>
* This method implements the specified semantics of the
* Session.getNamespaceURI method. Session implementations can use
* this method as follows:
* <pre>
* NamespaceRegistry registry = new SessionNamespaceRegistry(
* getWorkspace().getNamespaceRegistry());
*
* public String getNamespaceURI(String prefix)
* throws NamespaceException, RepositoryException {
* return registry.getURI(prefix);
* }
* </pre>
*
* @param prefix namespace prefix
* @return namespace URI
* @throws NamespaceException if the prefix is not registered or
* currently visible
* @throws RepositoryException on repository errors
* @see NamespaceRegistry#getURI(String)
* @see javax.jcr.Session#getNamespaceURI(String)
*/
public String getURI(String prefix)
throws NamespaceException, RepositoryException {
String uri = prefixToURI.getProperty(prefix);
if (uri != null) {
return uri;
} else if (!hiddenPrefixes.contains(prefix)) {
return registry.getURI(prefix);
} else {
throw new NamespaceException(
"Namespace mapping not found for prefix " + prefix);
}
}
/**
* Returns the prefix that is mapped to the given namespace URI.
* Returns the local prefix if the namespace URI is locally mapped,
* otherwise falls back to the underlying global namespace registry.
* <p>
* This method implements the specified semantics of the
* Session.getNamespacePrefix method. Session implementations can use
* this method as follows:
* <pre>
* NamespaceRegistry registry = new SessionNamespaceRegistry(
* getWorkspace().getNamespaceRegistry());
*
* public String getNamespacePrefix(String uri)
* throws NamespaceException, RepositoryException {
* return registry.getPrefix(uri);
* }
* </pre>
*
* @param uri namespace URI
* @return namespace prefix
* @throws NamespaceException if the namespace URI is not registered
* @throws RepositoryException on repository errors
* @see NamespaceRegistry#getPrefix(String)
* @see javax.jcr.Session#getNamespacePrefix(String)
*/
public String getPrefix(String uri)
throws NamespaceException, RepositoryException {
String prefix = uriToPrefix.getProperty(uri);
if (prefix != null) {
return prefix;
} else {
return registry.getPrefix(uri);
}
}
}