/* * Copyright (c) 2009, James Leigh All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * - Redistributions in binary form must reproduce the above copyright notice, * this list of conditions and the following disclaimer in the documentation * and/or other materials provided with the distribution. * - Neither the name of the openrdf.org nor the names of its contributors may * be used to endorse or promote products derived from this software without * specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * */ package org.openrdf.repository.object.managers.helpers; import java.util.Collection; import java.util.Comparator; import java.util.Map; import java.util.NavigableMap; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; import java.util.concurrent.ConcurrentNavigableMap; import java.util.concurrent.ConcurrentSkipListMap; import java.util.concurrent.CopyOnWriteArrayList; /** * Matches concepts with @matches annotation to URIs as their are loaded from * the repository. */ public class RoleMatcher implements Cloneable { private Comparator<String> reverse = new Comparator<String>() { public int compare(String o1, String o2) { int i = o1.length(); int j = o2.length(); while (i > 0 && j > 0) { char c1 = o1.charAt(--i); char c2 = o2.charAt(--j); if (c1 != c2) { return c1 - c2; } } return i - j; } }; private ConcurrentNavigableMap<String, ConcurrentNavigableMap<String, Collection<Class<?>>>> hostsufPathpre = new ConcurrentSkipListMap(reverse); private ConcurrentNavigableMap<String, ConcurrentMap<String, Collection<Class<?>>>> hostsufPath = new ConcurrentSkipListMap(reverse); private ConcurrentNavigableMap<String, Collection<Class<?>>> uriprefix = new ConcurrentSkipListMap(); private ConcurrentMap<String, Collection<Class<?>>> uris = new ConcurrentHashMap(); private boolean empty = true; public RoleMatcher clone() { RoleMatcher cloned = new RoleMatcher(); for (String host : hostsufPathpre.keySet()) { for (String path : hostsufPathpre.get(host).keySet()) { for (Class<?> role : hostsufPathpre.get(host).get(path)) { cloned.addRoles('*' + host + path + '*', role); } } } for (String host : hostsufPath.keySet()) { for (String path : hostsufPath.get(host).keySet()) { for (Class<?> role : hostsufPath.get(host).get(path)) { cloned.addRoles('*' + host + path, role); } } } for (String key : uriprefix.keySet()) { for (Class<?> role : uriprefix.get(key)) { cloned.addRoles(key + '*', role); } } for (String key : uris.keySet()) { for (Class<?> role : uris.get(key)) { cloned.addRoles(key, role); } } return cloned; } public boolean isEmpty() { return empty; } public void addRoles(String pattern, Class<?> role) { if (pattern.endsWith("*")) { String prefix = pattern.substring(0, pattern.length() - 1); if (prefix.startsWith("/")) { addPathPrefix(hostsufPathpre, "", prefix, role); } else if (prefix.startsWith("*") && prefix.contains("/")) { int idx = prefix.indexOf('/'); String suffix = prefix.substring(1, idx); prefix = prefix.substring(idx); addPathPrefix(hostsufPathpre, suffix, prefix, role); } else if (prefix.startsWith("*")) { String suffix = prefix.substring(1); addPathPrefix(hostsufPathpre, suffix, "", role); } else { add(uriprefix, prefix, role); } } else { if (pattern.startsWith("/")) { addPath(hostsufPath, "", pattern, role); } else if (pattern.startsWith("*") && pattern.contains("/")) { int idx = pattern.indexOf('/'); String suffix = pattern.substring(1, idx); pattern = pattern.substring(idx); addPath(hostsufPath, suffix, pattern, role); } else if (pattern.startsWith("*")) { String suffix = pattern.substring(1); addPath(hostsufPath, suffix, "", role); } else { add(uris, pattern, role); } } empty = false; } public void findRoles(String uri, Collection<Class<?>> roles) { findExactRoles(uris, uri, roles); findRoles(uriprefix, uri, roles); int idx = uri.indexOf("://") + 3; if (idx > 3 && idx < uri.length()) { int sidx = uri.indexOf('/', idx); if (sidx > 0) { String auth = uri.substring(idx, sidx); String path = uri.substring(sidx); findPathPrefixRoles(auth, path, roles); findPathRoles(auth, path, roles); } else { String auth = uri.substring(idx); findPathPrefixRoles(auth, "", roles); findPathRoles(auth, "", roles); } } } private void addPathPrefix( ConcurrentNavigableMap<String, ConcurrentNavigableMap<String, Collection<Class<?>>>> map, String suffix, String prefix, Class<?> role) { ConcurrentNavigableMap<String, Collection<Class<?>>> m, o; m = map.get(suffix); if (m == null) { m = new ConcurrentSkipListMap<String, Collection<Class<?>>>(); o = map.putIfAbsent(suffix, m); if (o != null) { m = o; } } add(m, prefix, role); } private void addPath( ConcurrentNavigableMap<String, ConcurrentMap<String, Collection<Class<?>>>> map, String suffix, String prefix, Class<?> role) { ConcurrentMap<String, Collection<Class<?>>> m, o; m = map.get(suffix); if (m == null) { m = new ConcurrentHashMap<String, Collection<Class<?>>>(); o = map.putIfAbsent(suffix, m); if (o != null) { m = o; } } add(m, prefix, role); } private void add(ConcurrentMap<String, Collection<Class<?>>> map, String pattern, Class<?> role) { Collection<Class<?>> list = map.get(pattern); if (list == null) { list = new CopyOnWriteArrayList<Class<?>>(); Collection<Class<?>> o = map.putIfAbsent(pattern, list); if (o != null) { list = o; } } if (!list.contains(role)) { list.add(role); } } private void findPathRoles(String auth, String path, Collection<Class<?>> roles) { Map<String, Collection<Class<?>>> map = hostsufPath.get(auth); if (map != null) { findExactRoles(map, path, roles); } String key = hostsufPath.lowerKey(auth); if (key == null) { return; } else if (auth.endsWith(key)) { findPathRoles(key, path, roles); } else if (auth.length() > 0) { int i = auth.length() - 1; int j = key.length() - 1; while (i >= 0 && j >=0 && auth.charAt(i) == key.charAt(j)) { i--; j--; } String suffix = auth.substring(i + 1); findPathRoles(suffix, path, roles); } } private void findPathPrefixRoles(String auth, String path, Collection<Class<?>> roles) { NavigableMap<String, Collection<Class<?>>> map = hostsufPathpre.get(auth); if (map != null) { findRoles(map, path, roles); } String key = hostsufPathpre.lowerKey(auth); if (key == null) { return; } else if (auth.endsWith(key)) { findPathPrefixRoles(key, path, roles); } else if (auth.length() > 0) { int i = auth.length() - 1; int j = key.length() - 1; while (i >= 0 && j >= 0 && auth.charAt(i) == key.charAt(j)) { i--; j--; } String suffix = auth.substring(i + 1); findPathPrefixRoles(suffix, path, roles); } } private void findRoles(NavigableMap<String, Collection<Class<?>>> map, String full, Collection<Class<?>> roles) { findExactRoles(map, full, roles); String key = map.lowerKey(full); if (key == null) { return; } else if (full.startsWith(key)) { findRoles(map, key, roles); } else if (full.length() > 0) { int idx = 0; while (idx < full.length() && idx < key.length() && full.charAt(idx) == key.charAt(idx)) { idx++; } String prefix = full.substring(0, idx); findRoles(map, prefix, roles); } } private void findExactRoles(Map<String, Collection<Class<?>>> map, String uri, Collection<Class<?>> roles) { Collection<Class<?>> list = map.get(uri); if (list != null) { roles.addAll(list); } } }