001/*
002 * Licensed to DuraSpace under one or more contributor license agreements.
003 * See the NOTICE file distributed with this work for additional information
004 * regarding copyright ownership.
005 *
006 * DuraSpace licenses this file to you under the Apache License,
007 * Version 2.0 (the "License"); you may not use this file except in
008 * compliance with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.fcrepo.kernel.modeshape.utils;
019
020import static com.google.common.collect.ImmutableSet.of;
021import static java.util.Objects.requireNonNull;
022import static java.util.Arrays.stream;
023import static javax.jcr.NamespaceRegistry.PREFIX_EMPTY;
024import static javax.jcr.NamespaceRegistry.PREFIX_JCR;
025import static javax.jcr.NamespaceRegistry.PREFIX_MIX;
026import static javax.jcr.NamespaceRegistry.PREFIX_NT;
027
028import java.util.HashMap;
029import java.util.Map;
030import java.util.Set;
031import java.util.function.Predicate;
032
033import javax.jcr.NamespaceException;
034import javax.jcr.NamespaceRegistry;
035import javax.jcr.RepositoryException;
036import javax.jcr.Session;
037
038import org.fcrepo.kernel.api.exception.FedoraInvalidNamespaceException;
039import org.fcrepo.kernel.api.exception.RepositoryRuntimeException;
040
041/**
042 * Tools for working with the JCR Namespace Registry
043 * @author Benjamin Armintor
044 * @author acoburn
045 * @author ajs6f
046 * @since May 13, 2013
047 */
048public final class NamespaceTools {
049
050    private NamespaceTools() {
051    }
052
053    // Internal namespaces defined in the modeshape CND file
054    private static final Set<String> INTERNAL_PREFIXES = of(PREFIX_EMPTY, PREFIX_JCR, PREFIX_MIX, PREFIX_NT,
055            "mode", "sv", "image");
056
057    /**
058     * Return the {@link NamespaceRegistry} associated with the arg session.
059     *
060     * @param session containing the NamespaceRegistry
061     * @return NamespaceRegistry
062     */
063    public static NamespaceRegistry getNamespaceRegistry(final Session session) {
064        try {
065            return requireNonNull(session.getWorkspace().getNamespaceRegistry(),
066                    "Couldn't find namespace registry in repository!");
067        } catch (final RepositoryException e) {
068            throw new RepositoryRuntimeException(e);
069        }
070    }
071
072    /**
073     * Validate resource path for unregistered namespace prefixes
074     *
075     * @param session the JCR session to use
076     * @param path the absolute path to the object
077     * @throws org.fcrepo.kernel.api.exception.FedoraInvalidNamespaceException on unregistered namespaces
078     * @throws org.fcrepo.kernel.api.exception.RepositoryRuntimeException if repository runtime exception occurred
079     */
080    public static void validatePath(final Session session, final String path) {
081
082        final NamespaceRegistry namespaceRegistry = getNamespaceRegistry(session);
083        final String[] pathSegments = path.replaceAll("^/+", "").replaceAll("/+$", "").split("/");
084        for (final String segment : pathSegments) {
085            final int colonPosition = segment.indexOf(':');
086            if (segment.length() > 0 && colonPosition > -1) {
087                final String prefix = segment.substring(0, colonPosition);
088                if (!prefix.equals("fedora")) {
089                    if (prefix.length() == 0) {
090                        throw new FedoraInvalidNamespaceException("Empty namespace in " + segment);
091                    }
092                    try {
093                        namespaceRegistry.getURI(prefix);
094                    } catch (final NamespaceException e) {
095                        throw new FedoraInvalidNamespaceException("Prefix " + prefix + " has not been registered", e);
096                    } catch (final RepositoryException e) {
097                        throw new RepositoryRuntimeException(e);
098                    }
099                }
100            }
101        }
102    }
103
104    /**
105     * Retrieve the namespaces as a Map
106     *
107     * @param session the JCR session to use
108     * @return a mapping of the prefix to URI
109     */
110    public static Map<String, String> getNamespaces(final Session session) {
111        final NamespaceRegistry registry = getNamespaceRegistry(session);
112        final Map<String, String> namespaces = new HashMap<>();
113
114        try {
115            stream(registry.getPrefixes()).filter(internalPrefix.negate()).forEach(x -> {
116                try {
117                    namespaces.put(x, registry.getURI(x));
118                } catch (final RepositoryException e) {
119                    throw new RepositoryRuntimeException(e);
120                }
121            });
122        } catch (final RepositoryException e) {
123            throw new RepositoryRuntimeException(e);
124        }
125        return namespaces;
126    }
127
128    private static Predicate<String> internalPrefix = INTERNAL_PREFIXES::contains;
129}