View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *  http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.any23.rdf;
19  
20  import org.eclipse.rdf4j.model.IRI;
21  import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
22  
23  import java.util.Collections;
24  import java.util.HashMap;
25  import java.util.HashSet;
26  import java.util.Map;
27  import java.util.Map.Entry;
28  import java.util.Set;
29  
30  /**
31   * A mapping from prefixes to namespace IRIs. Supports "volatile mappings", which will be overwritten without notice
32   * when mappings are merged, while for normal mappings this causes an exception. This allows combining "hard" mappings
33   * (which must be retained or something breaks) and "soft" mappings (which might be read from input RDF files and should
34   * be retained only if they are not in conflict with the hard ones).
35   *
36   * @author Richard Cyganiak (richard@cyganiak.de)
37   */
38  public class Prefixes {
39  
40      public static Prefixes create1(String prefix, String namespaceIRI) {
41          Prefixeshtml#Prefixes">Prefixes result = new Prefixes();
42          result.add(prefix, namespaceIRI);
43          return result;
44      }
45  
46      public static Prefixes createFromMap(Map<String, String> prefixesToNamespaceIRIs, boolean areVolatile) {
47          Prefixeshtml#Prefixes">Prefixes result = new Prefixes();
48          for (Entry<String, String> entry : prefixesToNamespaceIRIs.entrySet()) {
49              if (areVolatile) {
50                  result.addVolatile(entry.getKey(), entry.getValue());
51              } else {
52                  result.add(entry.getKey(), entry.getValue());
53              }
54          }
55          return result;
56      }
57  
58      public static Prefixes.html#Prefixes">Prefixes EMPTY = new Prefixes(Collections.<String, String> emptyMap());
59  
60      private final Map<String, String> mappings;
61      private final Set<String> volatilePrefixes = new HashSet<String>();
62  
63      public Prefixes() {
64          this(new HashMap<String, String>());
65      }
66  
67      public Prefixes" href="../../../../org/apache/any23/rdf/Prefixes.html#Prefixes">Prefixes(Prefixes initial) {
68          this();
69          add(initial);
70      }
71  
72      private Prefixes(Map<String, String> mappings) {
73          this.mappings = mappings;
74      }
75  
76      public IRI expand(String curie) {
77          String prefix = parsePrefix(curie);
78          if (prefix == null || !hasPrefix(prefix)) {
79              return null;
80          }
81          return SimpleValueFactory.getInstance().createIRI(getNamespaceIRIFor(prefix) + parseLocalName(curie));
82      }
83  
84      public String abbreviate(String uri) {
85          for (Entry<String, String> namespace : mappings.entrySet()) {
86              if (uri.startsWith(namespace.getValue())) {
87                  return namespace.getKey() + ":" + uri.substring(namespace.getValue().length());
88              }
89          }
90          return null;
91      }
92  
93      public boolean canExpand(String curie) {
94          String prefix = parsePrefix(curie);
95          return prefix != null && hasPrefix(prefix);
96      }
97  
98      public boolean canAbbreviate(String uri) {
99          for (Entry<String, String> namespace : mappings.entrySet()) {
100             if (uri.startsWith(namespace.getValue())) {
101                 return true;
102             }
103         }
104         return false;
105     }
106 
107     public String getNamespaceIRIFor(String prefix) {
108         return mappings.get(prefix);
109     }
110 
111     public boolean hasNamespaceIRI(String uri) {
112         return mappings.containsValue(uri);
113     }
114 
115     public boolean hasPrefix(String prefix) {
116         return mappings.containsKey(prefix);
117     }
118 
119     public Set<String> allPrefixes() {
120         return mappings.keySet();
121     }
122 
123     public boolean isEmpty() {
124         return mappings.isEmpty();
125     }
126 
127     public void add(String prefix, String namespaceIRI) {
128         if (isVolatile(prefix)) {
129             volatilePrefixes.remove(prefix);
130         } else {
131             if (hasPrefix(prefix)) {
132                 if (getNamespaceIRIFor(prefix).equals(namespaceIRI)) {
133                     return; // re-assigned same prefix to same IRI, let's just ignore it
134                 }
135                 throw new IllegalStateException("Attempted to re-assign prefix '" + prefix + "'; clashing values '"
136                         + getNamespaceIRIFor(prefix) + "' and '" + namespaceIRI);
137             }
138         }
139         mappings.put(prefix, namespaceIRI);
140     }
141 
142     public void add(Prefixes other) {
143         for (String otherPrefix : other.allPrefixes()) {
144             if (other.isVolatile(otherPrefix)) {
145                 addVolatile(otherPrefix, other.getNamespaceIRIFor(otherPrefix));
146             } else {
147                 add(otherPrefix, other.getNamespaceIRIFor(otherPrefix));
148             }
149         }
150     }
151 
152     public void removePrefix(String prefix) {
153         mappings.remove(prefix);
154         volatilePrefixes.remove(prefix);
155     }
156 
157     public Prefixes createSubset(String... prefixes) {
158         Prefixeshtml#Prefixes">Prefixes result = new Prefixes();
159         for (String prefix : prefixes) {
160             if (!hasPrefix(prefix)) {
161                 throw new IllegalArgumentException("No namespace IRI declared for prefix " + prefix);
162             }
163             result.add(prefix, getNamespaceIRIFor(prefix));
164         }
165         return result;
166     }
167 
168     public void addVolatile(String prefix, String namespaceIRI) {
169         if (hasPrefix(prefix)) {
170             return; // new prefix is volatile, so we don't overwrite the old one
171         }
172         mappings.put(prefix, namespaceIRI);
173         volatilePrefixes.add(prefix);
174     }
175 
176     public void addVolatile(Prefixes other) {
177         for (String otherPrefix : other.allPrefixes()) {
178             addVolatile(otherPrefix, other.getNamespaceIRIFor(otherPrefix));
179         }
180     }
181 
182     public boolean isVolatile(String prefix) {
183         return volatilePrefixes.contains(prefix);
184     }
185 
186     private Map<String, String> mapUnmodifiable = null;
187 
188     public Map<String, String> asMap() {
189         // Optimization: Create the unmodifiable map only once, lazily
190         if (mapUnmodifiable == null) {
191             mapUnmodifiable = Collections.unmodifiableMap(mappings);
192         }
193         return mapUnmodifiable;
194     }
195 
196     private String parsePrefix(String curie) {
197         int index = curie.indexOf(':');
198         if (index == -1) {
199             throw new IllegalArgumentException("Not a CURIE: '" + curie + "'");
200         }
201         return curie.substring(0, index);
202     }
203 
204     private String parseLocalName(String curie) {
205         int index = curie.indexOf(':');
206         if (index == -1) {
207             throw new IllegalArgumentException("Not a CURIE: '" + curie + "'");
208         }
209         return curie.substring(index + 1);
210     }
211 
212 }