View Javadoc

1   /*
2    * Copyright (c) 2007, James Leigh All rights reserved.
3    * 
4    * Redistribution and use in source and binary forms, with or without
5    * modification, are permitted provided that the following conditions are met:
6    * 
7    * - Redistributions of source code must retain the above copyright notice, this
8    *   list of conditions and the following disclaimer.
9    * - Redistributions in binary form must reproduce the above copyright notice,
10   *   this list of conditions and the following disclaimer in the documentation
11   *   and/or other materials provided with the distribution. 
12   * - Neither the name of the openrdf.org nor the names of its contributors may
13   *   be used to endorse or promote products derived from this software without
14   *   specific prior written permission.
15   * 
16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
20   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26   * POSSIBILITY OF SUCH DAMAGE.
27   * 
28   */
29  package org.openrdf.elmo.dynabean.helpers;
30  
31  import info.aduna.iteration.CloseableIteration;
32  
33  import java.util.ArrayList;
34  import java.util.Collection;
35  import java.util.HashSet;
36  import java.util.List;
37  import java.util.Set;
38  
39  import org.openrdf.elmo.exceptions.ElmoCompositionException;
40  import org.openrdf.model.Literal;
41  import org.openrdf.model.Resource;
42  import org.openrdf.model.Statement;
43  import org.openrdf.model.URI;
44  import org.openrdf.model.Value;
45  import org.openrdf.model.vocabulary.OWL;
46  import org.openrdf.model.vocabulary.RDF;
47  import org.openrdf.model.vocabulary.RDFS;
48  import org.openrdf.query.BindingSet;
49  import org.openrdf.query.MalformedQueryException;
50  import org.openrdf.query.QueryEvaluationException;
51  import org.openrdf.query.QueryLanguage;
52  import org.openrdf.query.TupleQuery;
53  import org.openrdf.query.TupleQueryResult;
54  import org.openrdf.repository.RepositoryException;
55  import org.openrdf.repository.contextaware.ContextAwareConnection;
56  
57  /**
58   * Reads class properties form the repository for a new DynaClass.
59   * 
60   * @author James Leigh
61   * 
62   */
63  public class RdfsClassInterpreter {
64  
65  	private ContextAwareConnection conn;
66  
67  	public RdfsClassInterpreter(ContextAwareConnection conn) {
68  		this.conn = conn;
69  	}
70  
71  	public void interpetRdfClass(Collection<URI> types,
72  			OntologyDigester digester) throws RepositoryException,
73  			QueryEvaluationException {
74  		Collection<URI> rdfTypes = types;
75  		rdfTypes = includeSubclasses(rdfTypes);
76  		digestDeclaredProperties(rdfTypes, digester);
77  		for (Resource restriction : getRestrictions(rdfTypes)) {
78  			digestRestrictionProperties(restriction, digester);
79  		}
80  		cleanup(digester);
81  	}
82  
83  	private void digestDeclaredProperties(Collection<URI> rdfTypes,
84  			OntologyDigester digester) throws RepositoryException,
85  			QueryEvaluationException {
86  		TupleQueryResult result = null;
87  		StringBuilder query = null;
88  		try {
89  			for (URI rdfType : rdfTypes) {
90  				if (query == null) {
91  					query = new StringBuilder();
92  					query.append("SELECT p FROM {p} rdfs:domain {c}");
93  					query.append(" WHERE c = <");
94  					query.append(rdfType);
95  					query.append(">");
96  				} else {
97  					query.append(" OR c = <");
98  					query.append(rdfType);
99  					query.append(">");
100 				}
101 			}
102 			assert query != null;
103 			TupleQuery preparedQuery = conn.prepareTupleQuery(
104 					QueryLanguage.SERQL, query.toString());
105 			result = preparedQuery.evaluate();
106 			while (result.hasNext()) {
107 				BindingSet sol = result.next();
108 				URI pred = (URI) sol.getValue("p");
109 				digester.addPredicate(pred);
110 				CloseableIteration<? extends Statement, RepositoryException> iter2 = null;
111 				try {
112 					iter2 = conn.getStatements(pred, RDFS.RANGE, null, true);
113 					while (iter2.hasNext()) {
114 						Value val = iter2.next().getObject();
115 						assert val instanceof URI : val;
116 						digester.addRdfType(pred, (URI) val);
117 					}
118 				} finally {
119 					if (iter2 != null)
120 						iter2.close();
121 				}
122 				// maxCardinality
123 				if (conn.hasStatement(pred, RDF.TYPE, OWL.FUNCTIONALPROPERTY,
124 						true))
125 					digester.setFunctional(pred, true);
126 			}
127 		} catch (MalformedQueryException e) {
128 			throw new ElmoCompositionException(e);
129 		} finally {
130 			if (result != null)
131 				result.close();
132 		}
133 	}
134 
135 	private Iterable<Resource> getRestrictions(Collection<URI> rdfTypes)
136 			throws RepositoryException, QueryEvaluationException {
137 		Set<Resource> classes = new HashSet<Resource>();
138 		TupleQueryResult result = null;
139 		try {
140 			StringBuilder query = null;
141 			for (URI rdfType : rdfTypes) {
142 				if (query == null) {
143 					query = new StringBuilder();
144 					query
145 							.append("SELECT r FROM {c} rdfs:subClassOf {r} rdf:type {<");
146 					query.append(OWL.RESTRICTION);
147 					query.append(">}");
148 					query.append(" WHERE c = <");
149 					query.append(rdfType);
150 					query.append(">");
151 				} else {
152 					query.append(" OR c = <");
153 					query.append(rdfType);
154 					query.append(">");
155 				}
156 			}
157 			assert query != null;
158 			TupleQuery preparedQuery = conn.prepareTupleQuery(
159 					QueryLanguage.SERQL, query.toString());
160 			result = preparedQuery.evaluate();
161 			while (result.hasNext()) {
162 				BindingSet sol = result.next();
163 				classes.add((Resource) sol.getValue("r"));
164 			}
165 		} catch (MalformedQueryException e) {
166 			throw new ElmoCompositionException(e);
167 		} finally {
168 			if (result != null)
169 				result.close();
170 		}
171 		return classes;
172 	}
173 
174 	private void digestRestrictionProperties(Resource restriction,
175 			OntologyDigester digester) throws RepositoryException {
176 		URI pred = (URI) getFirstValue(restriction, OWL.ONPROPERTY);
177 		if (pred == null)
178 			return;
179 		digester.addPredicate(pred);
180 		CloseableIteration<? extends Statement, RepositoryException> iter = null;
181 		try {
182 			iter = conn.getStatements(restriction, OWL.ALLVALUESFROM, null,
183 					true);
184 			while (iter.hasNext()) {
185 				Value val = iter.next().getObject();
186 				assert val instanceof URI;
187 				digester.addRdfType(pred, (URI) val);
188 			}
189 		} finally {
190 			if (iter != null)
191 				iter.close();
192 		}
193 		int cardinality = getFirstInt(restriction, OWL.CARDINALITY);
194 		if (cardinality == 1)
195 			digester.setFunctional(pred, true);
196 		cardinality = getFirstInt(restriction, OWL.MAXCARDINALITY);
197 		if (cardinality == 1)
198 			digester.setFunctional(pred, true);
199 	}
200 
201 	private void cleanup(OntologyDigester digester) throws RepositoryException {
202 		for (URI pred : digester.getPredicates()) {
203 			List<URI> rdfTypes = digester.getRdfTypes(pred);
204 			if (rdfTypes == null)
205 				continue;
206 			rdfTypes = filterOutSuperclasses(rdfTypes);
207 			digester.setRdfTypes(pred, rdfTypes);
208 		}
209 		digester.end();
210 	}
211 
212 	private List<URI> filterOutSuperclasses(List<URI> types)
213 			throws RepositoryException {
214 		if (types.size() < 2)
215 			return types;
216 		ArrayList<URI> list = new ArrayList<URI>(types.size());
217 		for (int i = 0, n = types.size(); i < n; i++) {
218 			URI c = types.get(i);
219 			boolean isSubClass = false;
220 			for (int j = 0, m = types.size(); j < m; j++) {
221 				if (i == j)
222 					continue;
223 				URI d = types.get(j);
224 				if (c.equals(d)) {
225 					isSubClass = true;
226 					break;
227 				}
228 				boolean subclass = conn.hasStatement(d, RDFS.SUBCLASSOF, c,
229 						true);
230 				if (subclass) {
231 					isSubClass = true;
232 					break;
233 				}
234 			}
235 			if (!isSubClass)
236 				list.add(c);
237 		}
238 		return list;
239 	}
240 
241 	private Collection<URI> includeSubclasses(Collection<URI> rdfTypes)
242 			throws RepositoryException {
243 		Set<URI> classes = new HashSet<URI>();
244 		for (URI rdfType : rdfTypes) {
245 			includeSubclasses(rdfType, classes);
246 		}
247 		return classes;
248 	}
249 
250 	private Collection<URI> includeSubclasses(URI rdfType, Set<URI> result)
251 			throws RepositoryException {
252 		CloseableIteration<? extends Statement, RepositoryException> iter = null;
253 		try {
254 			result.add(rdfType);
255 			iter = conn.getStatements(rdfType, RDFS.SUBCLASSOF, null, true);
256 			while (iter.hasNext()) {
257 				Value uri = iter.next().getObject();
258 				if (uri instanceof URI && !result.contains(uri)) {
259 					includeSubclasses((URI) uri, result);
260 				}
261 			}
262 		} finally {
263 			if (iter != null)
264 				iter.close();
265 		}
266 		return result;
267 	}
268 
269 	private Value getFirstValue(Resource subj, URI pred)
270 			throws RepositoryException {
271 		CloseableIteration<? extends Statement, RepositoryException> iter = null;
272 		try {
273 			iter = conn.getStatements(subj, pred, null, false);
274 			if (iter.hasNext())
275 				return iter.next().getObject();
276 			return null;
277 		} finally {
278 			if (iter != null)
279 				iter.close();
280 		}
281 	}
282 
283 	private int getFirstInt(Resource subj, URI pred) throws RepositoryException {
284 		Literal lit = (Literal)getFirstValue(subj, pred);
285 		if (lit == null)
286 			return 0;
287 		return Integer.parseInt(lit.getLabel());
288 	}
289 }