Package org.apache.jackrabbit.core

Source Code of org.apache.jackrabbit.core.LocalNamespaceMappings

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.core;

import org.apache.jackrabbit.name.AbstractNamespaceResolver;
import org.apache.jackrabbit.name.NameException;
import org.apache.jackrabbit.name.NameResolver;
import org.apache.jackrabbit.name.NamespaceListener;
import org.apache.jackrabbit.name.NamespaceResolver;
import org.apache.jackrabbit.name.ParsingNameResolver;
import org.apache.jackrabbit.name.ParsingPathResolver;
import org.apache.jackrabbit.name.PathResolver;
import org.apache.jackrabbit.name.QName;
import org.apache.jackrabbit.name.NameCache;
import org.apache.jackrabbit.util.XMLChar;

import javax.jcr.NamespaceException;
import javax.jcr.RepositoryException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.HashSet;

/**
* Manager for local session namespace mappings. This class is
* used by the {@link SessionImpl SessionImpl} class to implement
* the local namespace mapping functionality required by the JCR API.
* <p>
* This class holds a reference to the underlying global and persistent
* namespace registry (a {@link NamespaceRegistryImpl NamespaceRegistryImpl}
* instance) and keeps track of local namespace mappings added by the session.
* <p>
* The namespace resolution methods required by the
* {@link NamespaceResolver NamespaceResolver} are implemented by first
* looking up the local namespace mapping and then backing to the
* underlying namespace registry.
*/
class LocalNamespaceMappings extends AbstractNamespaceResolver
        implements NamespaceListener, NameCache {

    /** The underlying global and persistent namespace registry. */
    private final NamespaceRegistryImpl nsReg;

    /** Prefix to URI mappings of local namespaces. */
    private final HashMap prefixToURI = new HashMap();

    /** URI to prefix mappings of local namespaces. */
    private final HashMap uriToPrefix = new HashMap();

    private final NameResolver nameResolver;

    private final PathResolver pathResolver;

    /**
     * Creates a local namespace manager with the given underlying
     * namespace registry.
     *
     * @param nsReg namespace registry
     */
    LocalNamespaceMappings(NamespaceRegistryImpl nsReg) {
        this.nsReg = nsReg;
        this.nsReg.addListener(this);
        nameResolver = new ParsingNameResolver(this);
        pathResolver = new ParsingPathResolver(nameResolver);
    }

    /**
     * Rename a persistently registered namespace URI to the new prefix.
     *
     * @param prefix namespace prefix
     * @param uri namespace URI
     * @throws NamespaceException
     * @throws RepositoryException
     */
    void setNamespacePrefix(String prefix, String uri)
            throws NamespaceException, RepositoryException {
        if (prefix == null || uri == null) {
            throw new IllegalArgumentException("prefix/uri can not be null");
        }
        if (QName.NS_EMPTY_PREFIX.equals(prefix)
                || QName.NS_DEFAULT_URI.equals(uri)) {
            throw new NamespaceException("default namespace is reserved and can not be changed");
        }
        // special case: xml namespace
        if (uri.equals(QName.NS_XML_URI)) {
            throw new NamespaceException("xml namespace is reserved and can not be changed.");
        }
        // special case: prefixes xml*
        if (prefix.toLowerCase().startsWith(QName.NS_XML_PREFIX)) {
            throw new NamespaceException("reserved prefix: " + prefix);
        }
        // check if the prefix is a valid XML prefix
        if (!XMLChar.isValidNCName(prefix)) {
            throw new NamespaceException("invalid prefix: " + prefix);
        }

        // verify that namespace exists (the following call will
        // trigger a NamespaceException if it doesn't)
        nsReg.getPrefix(uri);

        // check new prefix for collision
        if (Arrays.asList(getPrefixes()).contains(prefix)) {
            // prefix is already in use
            if (getURI(prefix).equals(uri)) {
                // redundant mapping, silently ignore
                return;
            }
            throw new NamespaceException("prefix already in use: " + prefix);
        }

        // check if namespace is already locally mapped
        String oldPrefix = (String) uriToPrefix.get(uri);
        if (oldPrefix != null) {
            // remove old mapping
            uriToPrefix.remove(uri);
            prefixToURI.remove(oldPrefix);
        }

        // store new mapping
        prefixToURI.put(prefix, uri);
        uriToPrefix.put(uri, prefix);
    }

    /**
     * Returns all prefixes currently mapped.
     *
     * @return an array holding all currently mapped prefixes
     * @throws RepositoryException if an error occurs
     */
    String[] getPrefixes() throws RepositoryException {
        if (prefixToURI.isEmpty()) {
            // shortcut
            return nsReg.getPrefixes();
        }

        HashSet prefixes = new HashSet();
        String[] uris = nsReg.getURIs();
        for (int i = 0; i < uris.length; i++) {
            // check local mapping
            String prefix = (String) uriToPrefix.get(uris[i]);
            if (prefix == null) {
                // globally mapped
                prefix = nsReg.getPrefix(uris[i]);
            }
            prefixes.add(prefix);
        }

        return (String[]) prefixes.toArray(new String[prefixes.size()]);
    }

    /**
     * Disposes this <code>LocalNamespaceMappings</code>.
     */
    void dispose() {
        nsReg.removeListener(this);
    }

    public NameResolver getNameResolver() {
        if (prefixToURI.isEmpty()) {
            return nsReg.getNameResolver();
        } else {
            return nameResolver;
        }
    }

    public PathResolver getPathResolver() {
        if (prefixToURI.isEmpty()) {
            return nsReg.getPathResolver();
        } else {
            return pathResolver;
        }
    }

    //-------------------------------------------------------------< NameCache >

    /**
     * {@inheritDoc}
     */
    public QName retrieveName(String jcrName) {
        try {
            return getNameResolver().getQName(jcrName);
        } catch (NameException e) {
            return null;
        } catch (NamespaceException e) {
            return null;
        }
    }

    /**
     * {@inheritDoc}
     */
    public String retrieveName(QName name) {
        try {
            return getNameResolver().getJCRName(name);
        } catch (NamespaceException e) {
            return null;
        }
    }

    /**
     * {@inheritDoc}
     */
    public void cacheName(String jcrName, QName name) {
    }

    /**
     * {@inheritDoc}
     */
    public void evictAllNames() {
    }

    //-----------------------------------------------------< NamespaceResolver >
    /**
     * {@inheritDoc}
     */
    public String getURI(String prefix) throws NamespaceException {
        if (prefixToURI.isEmpty()) {
            // shortcut
            return nsReg.getURI(prefix);
        }
        // check local mappings
        String uri = (String) prefixToURI.get(prefix);
        if (uri != null) {
            return uri;
        }

        // check global mappings
        uri = nsReg.getURI(prefix);
        if (uri != null) {
            // make sure global prefix is not hidden because of
            // locally remapped uri
            if (!uriToPrefix.containsKey(uri)) {
                return uri;
            }
        }

        throw new NamespaceException(prefix + ": unknown prefix");
    }

    /**
     * {@inheritDoc}
     */
    public String getPrefix(String uri) throws NamespaceException {
        if (prefixToURI.isEmpty()) {
            // shortcut
            return nsReg.getPrefix(uri);
        }

        // check local mappings
        String prefix = (String) uriToPrefix.get(uri);
        if (prefix != null) {
            return prefix;
        }

        // check global mappings
        return nsReg.getPrefix(uri);
    }

    //-----------------------------------------------------< NamespaceListener >
    /**
     * @inheritDoc
     * This method gets called when a new namespace is registered in
     * the global NamespaceRegistry. Overridden in order to check for/resolve
     * collision of new global prefix with existing local prefix.
     */
    public void namespaceAdded(String prefix, String uri) {
        if (prefixToURI.containsKey(prefix)) {
            // the new global prefix is already in use locally;
            // need to change it locally by appending underscore(s)
            // in order to guarantee unambiguous mappings
            String uniquePrefix = prefix + "_";
            while (prefixToURI.containsKey(uniquePrefix)) {
                uniquePrefix += "_";
            }
            // add new local mapping
            prefixToURI.put(uniquePrefix, uri);
            uriToPrefix.put(uri, uniquePrefix);
        }
    }

    /**
     * @inheritDoc
     * This method gets called when an existing namespace is remapped to a new
     * prefix in the global NamespaceRegistry. Overridden in order to check
     * for/resolve collision of new global prefix with existing local prefix.
     */
    public void namespaceRemapped(String oldPrefix, String newPrefix, String uri) {
        if (prefixToURI.containsKey(newPrefix)) {
            // the new global prefix is already in use locally;
            // check uri
            if (uriToPrefix.containsKey(uri)) {
                // since namespace is already remapped locally to
                // a different prefix there's no collision
                return;
            }
            // need to change enw prefix locally by appending underscore(s)
            // in order to guarantee unambiguous mappings
            String uniquePrefix = newPrefix + "_";
            while (prefixToURI.containsKey(uniquePrefix)) {
                uniquePrefix += "_";
            }
            // add new local mapping
            prefixToURI.put(uniquePrefix, uri);
            uriToPrefix.put(uri, uniquePrefix);
        }
    }

    /**
     * @inheritDoc
     * This method gets called when an existing namespace is removed
     * in the global NamespaceRegistry. Overridden in order to check
     * for/resolve collision of new global prefix with existing local prefix.
     */
    public void namespaceRemoved(String uri) {
        if (uriToPrefix.containsKey(uri)) {
            String prefix = (String)uriToPrefix.remove(uri);
            prefixToURI.remove(prefix);
        }
    }
}
TOP

Related Classes of org.apache.jackrabbit.core.LocalNamespaceMappings

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.