001/**
002 * Copyright 2015 DuraSpace, Inc.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016package org.fcrepo.kernel.api.utils;
017
018import java.util.Objects;
019import java.util.function.Function;
020
021import javax.jcr.NamespaceException;
022import javax.jcr.Node;
023import javax.jcr.RepositoryException;
024import javax.jcr.Session;
025
026import org.fcrepo.kernel.api.exception.FedoraInvalidNamespaceException;
027import org.fcrepo.kernel.api.exception.RepositoryRuntimeException;
028import org.modeshape.jcr.api.NamespaceRegistry;
029
030/**
031 * Tools for working with the JCR Namespace Registry
032 * (wrapping some non-standard Modeshape machinery)
033 * @author Benjamin Armintor
034 * @since May 13, 2013
035 */
036public final class NamespaceTools {
037
038    private NamespaceTools() {
039    }
040
041    /**
042     * We need the Modeshape NamespaceRegistry, because it allows us to register
043     * anonymous namespaces.
044     */
045    public static Function<Node, NamespaceRegistry> getNamespaceRegistry = new Function<Node, NamespaceRegistry>() {
046        @Override
047        public NamespaceRegistry apply(final Node n) {
048            try {
049                Objects.requireNonNull(n, "null has no Namespace Registry associated with it!");
050                return (org.modeshape.jcr.api.NamespaceRegistry)n.getSession().getWorkspace().getNamespaceRegistry();
051            } catch (final RepositoryException e) {
052                throw new IllegalStateException(e);
053            }
054        }
055
056    };
057
058    /**
059     * Return the javax.jcr.NamespaceRegistry associated with the arg session.
060     *
061     * @param session containing the NamespaceRegistry
062     * @return NamespaceRegistry
063     */
064    public static javax.jcr.NamespaceRegistry getNamespaceRegistry(final Session session) {
065        final javax.jcr.NamespaceRegistry namespaceRegistry;
066        try {
067            namespaceRegistry =
068                    session.getWorkspace().getNamespaceRegistry();
069            Objects.requireNonNull(namespaceRegistry,
070                    "Couldn't find namespace registry in repository!");
071            return namespaceRegistry;
072        } catch (final RepositoryException e) {
073            throw new RepositoryRuntimeException(e);
074        }
075    }
076
077    /**
078     * Validate resource path for unregistered namespace prefixes
079     *
080     * @param session the JCR session to use
081     * @param path the absolute path to the object
082     * @throws org.fcrepo.kernel.api.exception.FedoraInvalidNamespaceException on unregistered namespaces
083     * @throws org.fcrepo.kernel.api.exception.RepositoryRuntimeException if repository runtime exception occurred
084     */
085    public static void validatePath(final Session session, final String path) {
086
087        final javax.jcr.NamespaceRegistry namespaceRegistry = getNamespaceRegistry(session);
088
089        final String relPath = path.replaceAll("^/+", "").replaceAll("/+$", "");
090        final String[] pathSegments = relPath.split("/");
091        for (final String segment : pathSegments) {
092            if (segment.length() > 0 && segment.contains(":") &&
093                    !segment.substring(0, segment.indexOf(':')).equals("fedora")) {
094                final String prefix = segment.substring(0, segment.indexOf(':'));
095                if (prefix.length() == 0) {
096                    throw new FedoraInvalidNamespaceException(
097                            String.format("Unable to identify namespace for (%s)", segment));
098                }
099                try {
100                    namespaceRegistry.getURI(prefix);
101                } catch (final NamespaceException e) {
102                    throw new FedoraInvalidNamespaceException(
103                            String.format("The namespace prefix (%s) has not been registered", prefix), e);
104                } catch (final RepositoryException e) {
105                    throw new RepositoryRuntimeException(e);
106                }
107            }
108        }
109    }
110
111}