| /* |
| * 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.oak.namepath.impl; |
| |
| import static com.google.common.base.Preconditions.checkArgument; |
| import static com.google.common.base.Preconditions.checkNotNull; |
| import static java.util.Collections.emptyList; |
| import static java.util.Collections.emptyMap; |
| import static org.apache.jackrabbit.oak.api.Type.STRINGS; |
| import static org.apache.jackrabbit.oak.plugins.memory.EmptyNodeState.EMPTY_NODE; |
| import static org.apache.jackrabbit.oak.spi.namespace.NamespaceConstants.NAMESPACES_PATH; |
| import static org.apache.jackrabbit.oak.spi.namespace.NamespaceConstants.REP_NSDATA; |
| import static org.apache.jackrabbit.oak.spi.namespace.NamespaceConstants.REP_PREFIXES; |
| import static org.apache.jackrabbit.oak.spi.namespace.NamespaceConstants.REP_URIS; |
| import static org.apache.jackrabbit.oak.plugins.name.Namespaces.encodeUri; |
| import static org.apache.jackrabbit.oak.plugins.tree.factories.RootFactory.createReadOnlyRoot; |
| import static org.apache.jackrabbit.oak.plugins.tree.factories.TreeFactory.createReadOnlyTree; |
| import static org.apache.jackrabbit.oak.plugins.tree.TreeUtil.getString; |
| import static org.apache.jackrabbit.oak.plugins.tree.TreeUtil.getStrings; |
| |
| import java.util.Map; |
| import java.util.Map.Entry; |
| |
| import javax.jcr.RepositoryException; |
| |
| import org.apache.jackrabbit.oak.api.Root; |
| import org.apache.jackrabbit.oak.api.Tree; |
| import org.apache.jackrabbit.oak.namepath.NameMapper; |
| import org.apache.jackrabbit.oak.spi.state.NodeBuilder; |
| import org.apache.jackrabbit.oak.spi.state.NodeState; |
| import org.jetbrains.annotations.NotNull; |
| import org.jetbrains.annotations.Nullable; |
| |
| /** |
| * Name mapper with no local prefix remappings. URI to prefix mappings |
| * are read from the repository when for transforming expanded JCR names |
| * to prefixed Oak names. |
| * <p> |
| * Note that even though this class could be used to verify that all prefixed |
| * names have valid prefixes, we explicitly don't do that since this is a |
| * fairly performance-sensitive part of the codebase and since normally the |
| * NameValidator and other consistency checks already ensure that all names |
| * being committed or already in the repository should be valid. A separate |
| * consistency check can be used if needed to locate and fix any Oak names |
| * with invalid namespace prefixes. |
| */ |
| public class GlobalNameMapper implements NameMapper { |
| |
| protected static boolean isHiddenName(String name) { |
| return name.startsWith(":"); |
| } |
| |
| protected static boolean isExpandedName(String name) { |
| if (name.startsWith("{")) { |
| int brace = name.indexOf('}', 1); |
| return brace != -1 && name.substring(1, brace).indexOf(':') != -1; |
| } else { |
| return false; |
| } |
| } |
| |
| private final Root root; |
| private Tree namespaces; |
| private Tree nsdata; |
| |
| public GlobalNameMapper(Root root) { |
| this.root = root; |
| init(); |
| } |
| |
| public GlobalNameMapper(NodeState root) { |
| this(createReadOnlyRoot(root)); |
| } |
| |
| private void init() { |
| if (root != null) { |
| this.namespaces = root.getTree(NAMESPACES_PATH); |
| this.nsdata = namespaces.getChild(REP_NSDATA); |
| } |
| } |
| |
| public GlobalNameMapper(Map<String, String> mappings) { |
| NodeBuilder forward = EMPTY_NODE.builder(); |
| NodeBuilder reverse = EMPTY_NODE.builder(); |
| |
| for (Entry<String, String> entry : mappings.entrySet()) { |
| String prefix = entry.getKey(); |
| if (!prefix.isEmpty()) { |
| String uri = entry.getValue(); |
| forward.setProperty(prefix, uri); |
| reverse.setProperty(encodeUri(uri), prefix); |
| } |
| } |
| reverse.setProperty(REP_PREFIXES, mappings.keySet(), STRINGS); |
| reverse.setProperty(REP_URIS, mappings.values(), STRINGS); |
| |
| this.root = null; |
| this.namespaces = createReadOnlyTree(forward.getNodeState()); |
| this.nsdata = createReadOnlyTree(reverse.getNodeState()); |
| } |
| |
| @Override @NotNull |
| public String getJcrName(@NotNull String oakName) { |
| // Sanity checks, can be turned to assertions if needed for performance |
| checkNotNull(oakName); |
| checkArgument(!isHiddenName(oakName), oakName); |
| checkArgument(!isExpandedName(oakName), oakName); |
| |
| return oakName; |
| } |
| |
| @Override @Nullable |
| public String getOakNameOrNull(@NotNull String jcrName) { |
| if (jcrName.startsWith("{")) { |
| return getOakNameFromExpanded(jcrName); |
| } |
| |
| return jcrName; |
| } |
| |
| @Override @NotNull |
| public String getOakName(@NotNull String jcrName) throws RepositoryException { |
| String oakName = getOakNameOrNull(jcrName); |
| if (oakName == null) { |
| throw new RepositoryException("Invalid jcr name " + jcrName); |
| } |
| return oakName; |
| } |
| |
| @NotNull |
| @Override |
| public Map<String, String> getSessionLocalMappings() { |
| return emptyMap(); |
| } |
| |
| @Nullable |
| protected String getOakNameFromExpanded(String expandedName) { |
| checkArgument(expandedName.startsWith("{")); |
| |
| int brace = expandedName.indexOf('}', 1); |
| if (brace > 0) { |
| String uri = expandedName.substring(1, brace); |
| if (uri.isEmpty()) { |
| return expandedName.substring(2); // special case: {}name |
| } else if (uri.indexOf(':') != -1) { |
| // It's an expanded name, look up the namespace prefix |
| String oakPrefix = getOakPrefixOrNull(uri); |
| if (oakPrefix != null) { |
| return oakPrefix + ':' + expandedName.substring(brace + 1); |
| } else { |
| return null; // no matching namespace prefix |
| } |
| } |
| } |
| |
| return expandedName; // not an expanded name |
| } |
| |
| @Nullable |
| protected synchronized String getOakPrefixOrNull(String uri) { |
| if (uri.isEmpty()) { |
| return uri; |
| } |
| |
| return getNsData(encodeUri(uri)); |
| } |
| |
| @Nullable |
| protected synchronized String getOakURIOrNull(String prefix) { |
| if (prefix.isEmpty()) { |
| return prefix; |
| } |
| |
| return getNamespacesProperty(prefix); |
| } |
| |
| protected String getNamespacesProperty(String prefix) { |
| return getString(namespaces, prefix); |
| } |
| |
| private String getNsData(String uri) { |
| return getString(nsdata, uri); |
| } |
| |
| protected Iterable<String> getPrefixes() { |
| Iterable<String> prefs = getStrings(nsdata, REP_PREFIXES); |
| if (prefs != null) { |
| return prefs; |
| } else { |
| return emptyList(); |
| } |
| } |
| |
| public void onSessionRefresh() { |
| init(); |
| } |
| |
| } |