1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29 package org.openrdf.elmo.sesame;
30
31 import static org.openrdf.query.QueryLanguage.SERQL;
32 import info.aduna.iteration.CloseableIteration;
33
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.Collection;
37 import java.util.Collections;
38 import java.util.HashSet;
39 import java.util.Iterator;
40 import java.util.List;
41 import java.util.Set;
42
43 import javax.xml.XMLConstants;
44 import javax.xml.namespace.QName;
45
46 import org.openrdf.elmo.ResourceManager;
47 import org.openrdf.elmo.RoleMapper;
48 import org.openrdf.elmo.annotations.disjointWith;
49 import org.openrdf.elmo.exceptions.ElmoIOException;
50 import org.openrdf.elmo.exceptions.ElmoPersistException;
51 import org.openrdf.elmo.sesame.iterators.ElmoIteration;
52 import org.openrdf.model.Namespace;
53 import org.openrdf.model.Resource;
54 import org.openrdf.model.Statement;
55 import org.openrdf.model.URI;
56 import org.openrdf.model.Value;
57 import org.openrdf.model.ValueFactory;
58 import org.openrdf.model.vocabulary.RDF;
59 import org.openrdf.query.Binding;
60 import org.openrdf.query.BindingSet;
61 import org.openrdf.query.MalformedQueryException;
62 import org.openrdf.query.QueryEvaluationException;
63 import org.openrdf.query.TupleQuery;
64 import org.openrdf.query.TupleQueryResult;
65 import org.openrdf.repository.RepositoryException;
66 import org.openrdf.repository.RepositoryResult;
67 import org.openrdf.repository.contextaware.ContextAwareConnection;
68
69
70
71
72
73
74
75 public class SesameResourceManager implements ResourceManager<Resource> {
76
77 private static final String DEFAULT_PREFIX = XMLConstants.DEFAULT_NS_PREFIX;
78
79 private ContextAwareConnection conn;
80
81 private ValueFactory vf;
82
83 private RoleMapper<URI> mapper;
84
85 public void setConnection(ContextAwareConnection conn) {
86 this.conn = conn;
87 }
88
89 public void setRoleMapper(RoleMapper<URI> mapper) {
90 this.mapper = mapper;
91 }
92
93 public void setValueFactory(ValueFactory vf) {
94 this.vf = vf;
95 }
96
97 public Resource createResource(QName qname) {
98 if (qname == null)
99 return vf.createBNode();
100 String ns = qname.getNamespaceURI();
101 String name = qname.getLocalPart();
102 if (ns.equals(XMLConstants.NULL_NS_URI)) {
103 String prefix = qname.getPrefix();
104 if (prefix.equals(DEFAULT_PREFIX))
105 return vf.createURI(name);
106 try {
107 ns = conn.getNamespace(prefix);
108 return vf.createURI(ns, name);
109 } catch (RepositoryException e) {
110 throw new ElmoIOException(e);
111 }
112 }
113 return vf.createURI(ns, name);
114 }
115
116 public QName createQName(Resource res) {
117 if (res instanceof URI) {
118 URI uri = (URI) res;
119 String prefix = getPrefix(uri.getNamespace());
120 return new QName(uri.getNamespace(), uri.getLocalName(), prefix);
121 }
122 return null;
123 }
124
125 public Iterator<Resource> createRoleQuery(Class<?> concept) {
126 StringBuilder query = new StringBuilder();
127 query.append("SELECT DISTINCT subj FROM");
128 Collection<URI> types = new HashSet<URI>();
129 mapper.findSubTypes(concept, types);
130 Iterator<URI> iter = types.iterator();
131 while (iter.hasNext()) {
132 query.append(" {subj} rdf:type {<");
133 query.append(iter.next()).append(">}");
134 if (iter.hasNext())
135 query.append(" UNION SELECT subj FROM");
136 }
137 try {
138 TupleQuery q = conn.prepareTupleQueryWithinContext(SERQL, query
139 .toString(), null);
140 TupleQueryResult result;
141 result = q.evaluate();
142 final List<String> bindings = result.getBindingNames();
143 return new ElmoIteration<BindingSet, Resource>(result) {
144 @Override
145 protected Resource convert(BindingSet sol) {
146 String b0 = bindings.get(0);
147 Binding binding = sol.getBinding(b0);
148 assert binding.getValue() instanceof Resource : binding
149 .getValue();
150 return (Resource) binding.getValue();
151 }
152 };
153 } catch (QueryEvaluationException e) {
154 throw new ElmoIOException(e);
155 } catch (MalformedQueryException e) {
156 throw new ElmoIOException(e);
157 } catch (RepositoryException e) {
158 throw new ElmoIOException(e);
159 }
160 }
161
162 @SuppressWarnings("unchecked")
163 public Class<?>[] getRoles(Resource res) {
164 CloseableIteration<? extends Statement, RepositoryException> stmts = null;
165 try {
166 try {
167 stmts = conn.getStatements(res, RDF.TYPE, null);
168 List<Class<?>> roles = null;
169 if (res instanceof URI
170 && mapper.isIndividualRolesPresent((URI) res)) {
171 roles = new ArrayList<Class<?>>();
172 mapper.findIndividualRoles((URI) res, roles);
173 }
174 if (stmts.hasNext()) {
175 Value obj = stmts.next().getObject();
176 assert obj instanceof URI : obj;
177 if (roles == null && !stmts.hasNext())
178 return mapper.findRoles((URI) obj);
179 List<URI> types = new ArrayList<URI>();
180 types.add((URI) obj);
181 while (stmts.hasNext()) {
182 obj = stmts.next().getObject();
183 assert obj instanceof URI;
184 types.add((URI) obj);
185 }
186 if (roles == null) {
187 roles = new ArrayList<Class<?>>();
188 }
189 mapper.findRoles(types, roles);
190 } else if (roles == null) {
191 return mapper.findBaseRoles();
192 } else {
193 mapper.findRoles(Collections.EMPTY_SET, roles);
194 }
195 return roles.toArray(new Class<?>[roles.size()]);
196 } finally {
197 if (stmts != null)
198 stmts.close();
199 }
200 } catch (RepositoryException e) {
201 throw new ElmoIOException(e);
202 }
203 }
204
205 public Class<?>[] mergeRole(Resource resource, Class<?> role) {
206 try {
207 Class<?>[] currently = getRoles(resource);
208 for (int i = 0; i < currently.length; i++) {
209 if (role.equals(currently[i]))
210 return currently;
211 }
212 if (role.isInterface()) {
213 URI type = mapper.findType(role);
214 if (type == null)
215 throw new ElmoPersistException("Concept not registered: "
216 + role.getSimpleName());
217 conn.add(resource, RDF.TYPE, type);
218 if (currently.length == 0)
219 return mapper.findRoles(type);
220 Set<Class<?>> roles = new HashSet<Class<?>>();
221 roles.addAll(Arrays.asList(currently));
222 roles.addAll(Arrays.asList(mapper.findRoles(type)));
223 assert isDisjointWith(role, roles);
224 return roles.toArray(new Class<?>[roles.size()]);
225 }
226 Collection<URI> types = mapper.findTypes(role, new HashSet<URI>());
227 assert types.size() > 0 : "Role not registered";
228 for (URI type : types) {
229 conn.add(resource, RDF.TYPE, type);
230 }
231 if (types.size() == 1 && currently.length == 0)
232 return mapper.findRoles(types.iterator().next());
233 Set<Class<?>> roles = new HashSet<Class<?>>();
234 if (currently.length > 0)
235 roles.addAll(Arrays.asList(currently));
236 mapper.findRoles(types, roles);
237 assert isDisjointWith(role, roles);
238 return roles.toArray(new Class<?>[roles.size()]);
239 } catch (RepositoryException e) {
240 throw new ElmoPersistException(e);
241 }
242 }
243
244 public Class<?>[] removeRole(Resource resource, Class<?> role) {
245 try {
246 URI type = mapper.findType(role);
247 if (type == null)
248 throw new ElmoPersistException("Concept not registered: "
249 + role.getSimpleName());
250 conn.remove(resource, RDF.TYPE, type);
251 return getRoles(resource);
252 } catch (RepositoryException e) {
253 throw new ElmoPersistException(e);
254 }
255 }
256
257 public void removeResource(Resource resource) {
258 try {
259 boolean autoCommit = conn.isAutoCommit();
260 conn.setAutoCommit(false);
261 conn.remove(resource, (URI) null, null);
262 conn.remove(null, (URI) null, resource);
263 conn.setAutoCommit(autoCommit);
264 } catch (Exception e) {
265 throw new ElmoPersistException(e);
266 }
267 }
268
269 public void renameResource(Resource before, Resource after) {
270 try {
271 RepositoryResult<Statement> stmts;
272 boolean autoCommit = conn.isAutoCommit();
273 conn.setAutoCommit(false);
274 stmts = conn.getStatements(before, null, null, false);
275 try {
276 while (stmts.hasNext()) {
277 Statement stmt = stmts.next();
278 URI pred = stmt.getPredicate();
279 Value obj = stmt.getObject();
280 conn.remove(before, pred, obj);
281 conn.add(after, pred, obj);
282 }
283 } finally {
284 stmts.close();
285 }
286 stmts = conn.getStatements(null, null, before);
287 try {
288 while (stmts.hasNext()) {
289 Statement stmt = stmts.next();
290 Resource subj = stmt.getSubject();
291 URI pred = stmt.getPredicate();
292 conn.remove(subj, pred, before);
293 conn.add(subj, pred, after);
294 }
295 } finally {
296 stmts.close();
297 }
298 conn.setAutoCommit(autoCommit);
299 } catch (Exception e) {
300 throw new ElmoPersistException(e);
301 }
302 }
303
304 private String getPrefix(String namespace) {
305 CloseableIteration<? extends Namespace, RepositoryException> namespaces = null;
306 try {
307 try {
308 namespaces = conn.getNamespaces();
309 while (namespaces.hasNext()) {
310 Namespace ns = namespaces.next();
311 if (namespace.equals(ns.getName()))
312 return ns.getPrefix();
313 }
314 return DEFAULT_PREFIX;
315 } finally {
316 if (namespaces != null)
317 namespaces.close();
318 }
319 } catch (RepositoryException e) {
320 throw new ElmoIOException(e);
321 }
322 }
323
324 private boolean isDisjointWith(Class<?> role, Set<Class<?>> roles) {
325 disjointWith dist = role.getAnnotation(disjointWith.class);
326 if (dist == null)
327 return true;
328 for (Class<?> c : dist.value()) {
329 for (Class<?> r : roles) {
330 if (c.isAssignableFrom(r))
331 throw new AssertionError(role.getSimpleName()
332 + " cannot be assigned to a " + r.getSimpleName());
333 }
334 }
335 return true;
336 }
337
338 }