/* * 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.stanbol.commons.namespaceprefix.impl; import static org.apache.stanbol.commons.namespaceprefix.NamespaceMappingUtils.checkNamespace; import static org.apache.stanbol.commons.namespaceprefix.NamespaceMappingUtils.checkPrefix; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Map; import java.util.SortedMap; import java.util.TreeMap; import java.util.Map.Entry; import org.apache.commons.io.IOUtils; import org.apache.commons.io.LineIterator; import org.apache.stanbol.commons.namespaceprefix.NamespaceMappingUtils; import org.apache.stanbol.commons.namespaceprefix.NamespacePrefixProvider; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * Default implementation of the {@link NamespacePrefixProvider}. * Mappings can not be modified. */ public class NamespacePrefixProviderImpl implements NamespacePrefixProvider { Logger log = LoggerFactory.getLogger(NamespacePrefixProviderImpl.class); private SortedMap<String,String> prefixMap = new TreeMap<String,String>(); private SortedMap<String,List<String>> namespaceMap = new TreeMap<String,List<String>>(); /** * Reads "{prefix}\t{namespace}\n" mappings form the parsed InputStream * @param is the stream to read the data from * @throws IOException on any error while reading from the parsed stream */ public NamespacePrefixProviderImpl(InputStream is) throws IOException { readPrefixMappings(is,true); } /** * Read the mappings form the parsed map * @param mappings Mappings */ public NamespacePrefixProviderImpl(Map<String,String> mappings){ for(Entry<String,String> mapping : mappings.entrySet()){ addMapping(mapping.getKey(),mapping.getValue(),true); } } /** * Expected to be called only during activation * @param in * @param validate if mappings should be validated before adding * @throws IOException */ private void readPrefixMappings(InputStream in,boolean validate) throws IOException { LineIterator it = IOUtils.lineIterator(in, "UTF-8"); while(it.hasNext()){ String mapping = it.nextLine(); if(mapping.charAt(0) != '#'){ int sep = mapping.indexOf('\t'); if(sep < 0 || mapping.length() <= sep+1){ log.warn("Illegal prefix mapping '{}'",mapping); } else { String old = addMapping(mapping.substring(0, sep),mapping.substring(sep+1),validate); if(old != null){ log.info("Duplicate mention of prefix {}. Override mapping from {} to {}", new Object[]{mapping.substring(0, sep), old, mapping.substring(sep+1)}); } } } else { //comment log.debug(mapping); } } } /** * Internally used to add an mapping * @param prefix the prefix * @param namespace the namespace * @param validate if true the prefix and namespace values are validated * using {@link NamespaceMappingUtils#checkPrefix(String)} and * {@link NamespaceMappingUtils#checkNamespace(String)}. * @return the previous mapping or <code>null</code> if none. */ protected String addMapping(String prefix, String namespace, boolean validate){ if(validate){ boolean p = checkPrefix(prefix); boolean n = checkNamespace(namespace); if(!p || !n){ log.warn("Invalid Namespace Mapping: prefix '{}' {} , namespace '{}' {} -> mapping ignored!", new Object[]{prefix,p?"valid":"invalid",namespace,n?"valid":"invalid"}); return null; } } String old = prefixMap.put(prefix, namespace); if(!namespace.equals(old)){ //if the mapping changed //(2) update the inverse mappings (ensure read only lists!) List<String> prefixes = namespaceMap.get(namespace); if(prefixes == null){ namespaceMap.put(namespace, Collections.singletonList(prefix)); } else { String[] ps = new String[prefixes.size()+1]; int i=0; for(;i<prefixes.size();i++){ ps[i] = prefixes.get(i); } ps[i] = prefix; namespaceMap.put(namespace, Arrays.asList(ps)); } } return old; } @Override public String getNamespace(String prefix) { return prefixMap.get(prefix); } @Override public String getPrefix(String namespace) { List<String> prefixes = namespaceMap.get(namespace); return prefixes == null || prefixes.isEmpty() ? null : prefixes.get(0); } @Override public List<String> getPrefixes(String namespace) { List<String> prefixes = namespaceMap.get(namespace); return prefixes == null ? Collections.EMPTY_LIST : prefixes; } }