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.vocab;
19
20 import org.eclipse.rdf4j.model.IRI;
21 import org.eclipse.rdf4j.model.impl.SimpleValueFactory;
22 import java.lang.annotation.Retention;
23 import java.lang.annotation.Target;
24 import java.lang.reflect.Field;
25 import java.util.Collection;
26 import java.util.Collections;
27 import java.util.HashMap;
28 import java.util.Map;
29
30 import static java.lang.annotation.ElementType.FIELD;
31 import static java.lang.annotation.RetentionPolicy.RUNTIME;
32
33 /**
34 * Base class for the definition of a vocabulary.
35 *
36 * @author Michele Mostarda ( michele.mostarda@gmail.com )
37 *
38 * @version $Id$
39 */
40 public abstract class Vocabulary {
41
42 /**
43 * Allows to add comments to <code>namespaces</code>, <code>classes</code> and <code>properties</code>.
44 */
45 @Target({ FIELD })
46 @Retention(RUNTIME)
47 @interface Comment {
48 String value();
49 }
50
51 /**
52 * Vocabulary namespace.
53 */
54 private final IRI namespace;
55
56 /**
57 * Map of vocabulary resources.
58 */
59 private Map<String, IRI> classes;
60
61 /**
62 * Map of vocabulary properties.
63 */
64 private Map<String, IRI> properties;
65
66 /**
67 * Map any resource with the relative comment.
68 */
69 private Map<IRI, String> resourceToCommentMap;
70
71 /**
72 * Overloaded Constructor.
73 *
74 * @param namespace
75 * the namespace IRI prefix.
76 */
77 public Vocabulary(String namespace) {
78 try {
79 this.namespace = SimpleValueFactory.getInstance().createIRI(namespace);
80 } catch (Exception e) {
81 throw new IllegalArgumentException("Invalid namespace '" + namespace + "'", e);
82 }
83 }
84
85 /**
86 * @return the namespace associated to this vocabulary.
87 */
88 public IRI getNamespace() {
89 return this.namespace;
90 }
91
92 /**
93 * Returns a class defined within this vocabulary.
94 *
95 * @param name
96 * class name.
97 *
98 * @return the IRI associated to such resource.
99 */
100 public IRI getClass(String name) {
101 IRI res = this.classes.get(name);
102 if (null == res) {
103 throw new IllegalArgumentException("Unknown resource name '" + name + "'");
104 }
105 return res;
106 }
107
108 /**
109 * Returns a property defined within this vocabulary.
110 *
111 * @param name
112 * property name.
113 *
114 * @return the IRI associated to such property.
115 */
116 public IRI getProperty(String name) {
117 IRI prop = this.properties.get(name);
118 if (null == prop) {
119 throw new IllegalArgumentException("Unknown property name '" + name + "'");
120 }
121 return prop;
122 }
123
124 /**
125 * Returns a property defined within this vocabulary, if not found the <code>defaultValue</code> will be returned.
126 *
127 * @param name
128 * property name.
129 * @param defaultValue
130 * the default value if property name not found.
131 *
132 * @return the IRI associated to such property.
133 */
134 public IRI getProperty(String name, IRI defaultValue) {
135 IRI prop = this.properties.get(name);
136 if (null == prop) {
137 return defaultValue;
138 }
139 return prop;
140 }
141
142 /**
143 * Returns the property IRI for the specified property string. If the string contains a list of words separated by
144 * blank chars, such words are merged and camel case separated.
145 *
146 * @param property
147 * property name.
148 *
149 * @return property IRI.
150 */
151 public IRI getPropertyCamelCase(String property) {
152 String[] names = property.split("\\W");
153 String camelCase = names[0];
154 for (int i = 1; i < names.length; i++) {
155 String tmp = names[i];
156 camelCase += tmp.replaceFirst("(.)", tmp.substring(0, 1).toUpperCase(java.util.Locale.ROOT));
157 }
158 return getProperty(camelCase);
159 }
160
161 /**
162 * @return the list of all defined classes.
163 */
164 public IRI[] getClasses() {
165 if (this.classes == null) {
166 return new IRI[0];
167 }
168 final Collection<IRI> iris = this.classes.values();
169 return iris.toArray(new IRI[iris.size()]);
170 }
171
172 /**
173 * @return the list of all defined properties.
174 */
175 public IRI[] getProperties() {
176 if (this.properties == null) {
177 return new IRI[0];
178 }
179 final Collection<IRI> iris = this.properties.values();
180 return iris.toArray(new IRI[iris.size()]);
181 }
182
183 /**
184 * Returns all the defined comments for resources.
185 *
186 * @return unmodifiable list of comments.
187 */
188 public Map<IRI, String> getComments() {
189 fillResourceToCommentMap();
190 return Collections.unmodifiableMap(this.resourceToCommentMap);
191 }
192
193 /**
194 * Returns the comment for the given resource.
195 *
196 * @param resource
197 * input resource to have a comment.
198 *
199 * @return the human readable comment associated to the given resource.
200 */
201 public String getCommentFor(IRI resource) {
202 fillResourceToCommentMap();
203 return this.resourceToCommentMap.get(resource);
204 }
205
206 /**
207 * Creates a IRI.
208 *
209 * @param iriStr
210 * the IRI string
211 *
212 * @return the IRI instance.
213 */
214 protected static IRI createIRI(String iriStr) {
215 return SimpleValueFactory.getInstance().createIRI(iriStr);
216 }
217
218 /**
219 * Creates a resource and register it to the {@link #classes} map.
220 *
221 * @param namespace
222 * vocabulary namespace.
223 * @param resource
224 * name of the resource.
225 *
226 * @return the created resource IRI.
227 */
228 protected IRI createClass(String namespace, String resource) {
229 IRI res = createIRI(namespace, resource);
230 if (this.classes == null) {
231 this.classes = new HashMap<>(10);
232 }
233 this.classes.put(resource, res);
234 return res;
235 }
236
237 /**
238 * Creates a property and register it to the {@link #properties} map.
239 *
240 * @param namespace
241 * vocabulary namespace.
242 * @param property
243 * name of the property.
244 *
245 * @return the created property IRI.
246 */
247 protected IRI createProperty(String namespace, String property) {
248 IRI res = createIRI(namespace, property);
249 if (this.properties == null) {
250 this.properties = new HashMap<>(10);
251 }
252 this.properties.put(property, res);
253 return res;
254 }
255
256 /**
257 * Creates a IRI.
258 *
259 * @param namespace
260 * @param localName
261 *
262 * @return
263 */
264 private static IRI createIRI(String namespace, String localName) {
265 return SimpleValueFactory.getInstance().createIRI(namespace, localName);
266 }
267
268 private void fillResourceToCommentMap() {
269 if (this.resourceToCommentMap != null)
270 return;
271 final Map<IRI, String> newMap = new HashMap<>();
272 for (Field field : this.getClass().getFields()) {
273 try {
274 final Object value = field.get(this);
275 if (value instanceof IRI) {
276 final Comment comment = field.getAnnotation(Comment.class);
277 if (comment != null)
278 newMap.put((IRI) value, comment.value());
279 }
280 } catch (IllegalAccessException iae) {
281 throw new RuntimeException("Error while creating resource to comment map.", iae);
282 }
283 }
284 this.resourceToCommentMap = newMap;
285 }
286
287 }