1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 package cz.zcu.mre.service.data;
23
24 import cz.zcu.mre.data.core.MREData;
25 import cz.zcu.mre.data.core.MREStringLang;
26 import cz.zcu.mre.mrelib.util.DateUtil;
27 import java.time.LocalDate;
28 import java.time.LocalDateTime;
29 import java.util.ArrayList;
30 import java.util.Date;
31 import java.util.Iterator;
32 import java.util.List;
33 import java.util.Set;
34 import org.apache.jena.arq.querybuilder.AbstractQueryBuilder;
35 import org.apache.jena.arq.querybuilder.AskBuilder;
36 import org.apache.jena.arq.querybuilder.ConstructBuilder;
37 import org.apache.jena.arq.querybuilder.DescribeBuilder;
38 import org.apache.jena.arq.querybuilder.SelectBuilder;
39 import org.apache.jena.arq.querybuilder.UpdateBuilder;
40 import org.apache.jena.datatypes.xsd.impl.XSDDateType;
41 import org.apache.jena.graph.Node;
42 import org.apache.jena.graph.NodeFactory;
43 import org.apache.jena.graph.Triple;
44 import org.apache.jena.ontology.Individual;
45 import org.apache.jena.query.Query;
46 import org.apache.jena.rdf.model.Literal;
47 import org.apache.jena.rdf.model.Resource;
48 import org.apache.jena.rdf.model.ResourceFactory;
49 import org.apache.jena.sparql.modify.request.UpdateDeleteInsert;
50 import org.apache.jena.vocabulary.RDF;
51 import org.slf4j.Logger;
52 import org.slf4j.LoggerFactory;
53
54
55
56
57
58 public class SPARQLBuilderImpl implements SPARQLBuilder {
59
60 private static final Logger LOG = LoggerFactory.getLogger(SPARQLBuilderImpl.class);
61
62
63 private MREDataService dataService;
64
65
66
67
68 public SPARQLBuilderImpl() {
69 }
70
71 public SPARQLBuilderImpl(MREDataService dataService) {
72 this.dataService = dataService;
73 }
74
75 public void setDataService(MREDataService dataService) {
76 this.dataService = dataService;
77 }
78
79
80
81
82
83
84
85 @Override
86 public Query ask(Object instance) {
87
88 AbstractQueryBuilder b = builderQuery(QUERY.ASK, instance, false, true);
89 return b.build();
90 }
91
92
93
94
95
96
97
98
99
100
101 @Override
102 public Query askExist(Object instance) {
103
104 AskBuilder builder = (AskBuilder) builderQuery(QUERY.ASK, instance, false, false);
105
106 return builder.build();
107 }
108
109
110
111
112
113
114
115
116
117
118 @Override
119 public Query askExistAll(Object instance) {
120
121 AskBuilder builder = (AskBuilder) builderQuery(QUERY.ASK, instance, false, true);
122
123 return builder.build();
124 }
125
126
127
128
129
130
131
132
133
134
135
136 @Override
137 public Query select(Object instance) {
138
139 return builderQuery(QUERY.SELECT, instance, false, true).build();
140 }
141
142
143
144
145
146
147
148
149
150
151
152 @Override
153 public Query selectAll(MREData instance) {
154
155 return selectAllBuilder(instance).build();
156 }
157
158 @Override
159 public SelectBuilder selectAllBuilder(MREData instance) {
160
161 return (SelectBuilder) builderQuery(QUERY.SELECT, instance, false, false);
162 }
163
164
165
166
167
168
169
170 @Override
171 public Query selectType(String resourceURI) {
172
173 return selectType(ResourceFactory.createResource(resourceURI));
174 }
175
176
177
178
179
180
181
182 @Override
183 public Query selectType(Resource resource) {
184
185 SelectBuilder selectBuilder = new SelectBuilder();
186 selectBuilder.setDistinct(true);
187 selectBuilder.addVar("type");
188 selectBuilder.addWhere(Triple.create(resource.asNode(), RDF.type.asNode(), NodeFactory.createVariable("type")));
189
190 return selectBuilder.build();
191 }
192
193
194
195
196
197
198
199 @Override
200 public UpdateBuilder delete(Object instance) {
201
202 return builderUpdate(QUERY.DELETE, instance, false);
203 }
204
205
206
207
208
209
210
211
212 @Override
213 public UpdateBuilder deleteAll(Object instance) {
214
215 return builderUpdate(QUERY.DELETE, instance, true);
216 }
217
218
219
220
221
222
223
224 @Override
225 public UpdateBuilder insert(Object instance) {
226 return builderUpdate(QUERY.INSERT, instance, false);
227 }
228
229
230
231
232
233
234
235
236 @Override
237 public UpdateBuilder insertAll(Object instance) {
238 return builderUpdate(QUERY.INSERT, instance, true);
239 }
240
241
242
243
244
245
246
247
248 @Override
249 public UpdateDeleteInsert update(Object instanceOld, Object instanceNew) {
250
251 return update(instanceOld, instanceNew, false);
252 }
253
254
255
256
257
258
259
260
261
262 @Override
263 public UpdateDeleteInsert updateAll(Object instanceOld, Object instanceNew) {
264 return update(instanceOld, instanceNew, true);
265 }
266
267
268
269
270
271
272
273
274
275
276
277 private UpdateDeleteInsert update(Object instanceOld, Object instanceNew, boolean deep) {
278
279 List<Triple> triplesOld = buildTriples(QUERY.DELETE, instanceOld, deep);
280 List<Triple> triplesNew = buildTriples(QUERY.INSERT, instanceNew, deep);
281
282 UpdateDeleteInsert update = new UpdateDeleteInsert();
283 triplesOld.stream().forEach(t -> update.getDeleteAcc().addTriple(t));
284 triplesNew.stream().forEach(t -> update.getInsertAcc().addTriple(t));
285
286 return update;
287 }
288
289
290
291
292
293
294
295
296
297
298
299
300
301 private AbstractQueryBuilder builderQuery(QUERY type, Object instance, boolean deep, boolean withValues) {
302
303 AbstractQueryBuilder queryBuilder = null;
304 List<Triple> triples = buildTriples(type, instance, deep);
305
306 switch (type) {
307 case ASK:
308 AskBuilder askBuilder = new AskBuilder();
309
310
311 if (!withValues) {
312 triples.clear();
313
314
315 MREDataFieldValue[] fields = dataService.builderValuesGet(instance);
316 addTripleRDFType(triples, fields, instance);
317 }
318 triples.stream().forEach(t -> {
319 askBuilder.addWhere(t);
320 });
321
322 queryBuilder = askBuilder;
323 break;
324 case CONSTRUCT:
325 ConstructBuilder constructBuilder = new ConstructBuilder();
326 triples.stream().forEach(t -> constructBuilder.addWhere(t));
327 queryBuilder = constructBuilder;
328 break;
329 case DESCRIBE:
330 DescribeBuilder describeBuilder = new DescribeBuilder();
331 triples.stream().forEach(t -> describeBuilder.addWhere(t));
332 queryBuilder = describeBuilder;
333 break;
334
335 case SELECT:
336 SelectBuilder selectBuilder = new SelectBuilder();
337
338 if (!withValues) {
339
340 MREDataFieldValue[] fields = dataService.builderValuesGet(instance);
341 triples.clear();
342 addTripleRDFType(triples, fields, instance);
343 }
344 triples.stream().forEach(t -> {
345 selectBuilder.addWhere(t);
346 });
347
348 selectAddVariables(selectBuilder, instance);
349 selectAddWhereVariables(selectBuilder, instance);
350
351
352 Resource subject = ((MREData) instance).getResource();
353 if (subject != null) {
354 selectBuilder.addValueVar(SPARQLBuilderVariables.VARIABLE_URI, ((MREData) instance).getResource());
355 }
356
357 queryBuilder = selectBuilder;
358 break;
359
360 default: {
361 throw new IllegalArgumentException("Method does not produce update queries.");
362 }
363 }
364
365 return queryBuilder;
366 }
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381 private UpdateBuilder builderUpdate(QUERY type, Object instance, boolean deep) {
382
383 UpdateBuilder updateBuilder = new UpdateBuilder();
384 List<Triple> triples = buildTriples(type, instance, deep);
385
386 switch (type) {
387
388 case INSERT:
389 triples.stream().forEach(t -> updateBuilder.addInsert(t));
390 break;
391
392 case DELETE:
393 triples.stream().forEach(t -> updateBuilder.addDelete(t));
394 break;
395
396 case UPDATE:
397
398 break;
399
400 default: {
401 throw new IllegalArgumentException("Method does not produce update queries.");
402 }
403 }
404
405 return updateBuilder;
406 }
407
408
409
410
411
412
413
414
415
416
417 private List<Triple> buildTriples(QUERY type, Object instance, boolean deep) {
418
419 List<Triple> triples = new ArrayList<>();
420
421 if (type == null || instance == null) {
422 return triples;
423 }
424
425 checkMREData(type, instance);
426
427
428 if (dataService.isPrimitiveDataType(instance)) {
429
430 LOG.debug("Primitive data type {} has value {}", instance.getClass(), instance);
431 return triples;
432 }
433
434 MREDataFieldValue[] fields = dataService.builderValuesGet(instance);
435 for (int i = 0; i < fields.length; i++) {
436
437 Set<Object> fieldValues = fields[i].getValue();
438
439
440 if (fieldValues.isEmpty()) {
441 continue;
442 }
443
444
445 if (i == 0) {
446 addTripleRDFType(triples, fields, instance);
447 }
448
449
450 Iterator<Object> it = fieldValues.iterator();
451 while (it.hasNext()) {
452 Object object = it.next();
453
454
455 if (object == null) {
456 continue;
457 }
458
459 if (object instanceof List) {
460
461
462 List list = (List) object;
463 for (Object o : list) {
464 LOG.debug("Build triples - {}, List field '{}'", o.getClass(), fields[i].getName());
465 addTriples(triples, type, fields[i], o, deep);
466 if (deep) {
467 triples.addAll(buildTriples(type, o, deep));
468 }
469 }
470
471 } else if (object instanceof Set) {
472
473
474 Set set = (Set) object;
475 for (Object o : set) {
476 LOG.debug("Build triples - {}, Set field '{}'", o.getClass(), fields[i].getName());
477 addTriples(triples, type, fields[i], o, deep);
478 if (deep) {
479 triples.addAll(buildTriples(type, o, deep));
480 }
481 }
482
483 } else if (object instanceof MREData) {
484
485
486 if (!((MREData) object).hasURI() && (type == QUERY.INSERT || type == QUERY.DELETE)) {
487 ((MREData) object).generateNewResource();
488 }
489
490 LOG.debug("Build triples - {}, MREData field '{}', type {}", instance.getClass(), fields[i].getName(), object.getClass());
491 addTripleObject(triples, type, fields[i], object);
492
493 } else if (object instanceof Individual) {
494
495 LOG.debug("Build triples - {}, Individual field '{}', type {}", instance.getClass(), fields[i].getName(), object.getClass());
496 addTripleObject(triples, type, fields[i], object);
497
498 } else {
499 LOG.debug("Build triples - {}, primitive type field '{}', type {}", instance.getClass(), fields[i].getName(), object.getClass());
500 addTriples(triples, type, fields[i], object, deep);
501 }
502 }
503 }
504
505
506 return triples;
507 }
508
509
510
511
512
513
514
515
516
517 private static void addTripleRDFType(List<Triple> triples, MREDataFieldValue[] fields, Object instance) {
518
519 int i = 0;
520
521 Node s;
522 if (fields[i].getSubject() != null) {
523 s = NodeFactory.createURI(fields[i].getSubject());
524 } else {
525 s = VARIABLE_URI;
526 }
527
528 Node p = RDF.type.asNode();
529 Node o;
530
531 String object;
532 if (fields[i].getConfig().getTypeRDF() == null) {
533 object = fields[i].getConfig().getOntology().concat(instance.getClass().getSimpleName());
534 } else {
535 object = fields[i].getConfig().getTypeRDF();
536 }
537 o = NodeFactory.createURI(object);
538
539
540 triples.add(Triple.create(s, p, o));
541 }
542
543
544
545
546
547
548
549
550
551 private void addTriples(List<Triple> triples, QUERY type, MREDataFieldValue field, Object object, boolean deep) {
552
553 if (object == null) {
554 return;
555 }
556
557 if (object instanceof List) {
558 triples.addAll(buildTriples(type, object, deep));
559 } else if (object instanceof Set) {
560 triples.addAll(buildTriples(type, object, deep));
561 } else if (object instanceof Individual) {
562 addTripleObject(triples, type, field, ((Individual) object).getURI());
563 } else if (object instanceof MREData) {
564 checkMREData(type, (MREData) object);
565 addTripleObject(triples, type, field, ((MREData) object).getUri());
566 } else {
567 addTripleDatatype(triples, type, field, object);
568 }
569 }
570
571
572
573
574
575
576
577
578 private static void checkMREData(QUERY type, Object instance) {
579
580 if (type == QUERY.INSERT && instance instanceof MREData && !((MREData) instance).hasURI()) {
581 ((MREData) instance).generateNewResource();
582 LOG.info("Auto-generated new resource URI for the instance: {}", ((MREData) instance).getResource());
583 }
584
585 }
586
587
588
589
590
591
592
593
594
595 private static void addTripleObject(List<Triple> triples, QUERY type, MREDataFieldValue field, Object object) {
596
597 if (object == null) {
598 return;
599 }
600
601 if (field.getSubject() == null) {
602 throw new IllegalArgumentException("Subject cannot be null.");
603 }
604
605 Node s = NodeFactory.createURI(field.getSubject());
606 Node p = NodeFactory.createURI(field.getProperty().toString());
607 Node o;
608
609 if (object instanceof MREData) {
610
611 o = ((MREData) object).getResource().asNode();
612 } else if (object instanceof Individual) {
613 o = ((Individual) object).asNode();
614 } else if (object instanceof String) {
615 o = NodeFactory.createURI(((String) object));
616 } else {
617 LOG.warn("Unsupported Java {} value {}. Using toString() method.", object.getClass(), object);
618
619 o = NodeFactory.createURI(object.toString());
620 }
621
622
623 triples.add(Triple.create(s, p, o));
624 }
625
626
627
628
629
630
631
632
633
634 private static void addTripleDatatype(List<Triple> triples, QUERY type, MREDataFieldValue field, Object value) {
635
636 Node s;
637 if (field.getSubject() != null) {
638 s = NodeFactory.createURI(field.getSubject());
639 } else {
640 s = VARIABLE_URI;
641 }
642
643 Node p = NodeFactory.createURI(field.getProperty().toString());
644 Node o = null;
645
646 Literal literalValue;
647 if (value instanceof Date) {
648
649 String date = DateUtil.xsdDate((Date) value);
650 literalValue = ResourceFactory.createTypedLiteral(date);
651
652 } else if (value instanceof LocalDate) {
653
654 LocalDate localDate = (LocalDate) value;
655 String date = localDate.toString();
656 literalValue = ResourceFactory.createTypedLiteral(date, XSDDateType.XSDdate);
657
658 } else if (value instanceof LocalDateTime) {
659
660 LocalDateTime localDateTime = (LocalDateTime) value;
661 String dateTime = localDateTime.toString();
662
663
664 literalValue = ResourceFactory.createTypedLiteral(dateTime, XSDDateType.XSDdateTime);
665
666 } else {
667
668 literalValue = createLiteralValue(type, field, value);
669 }
670
671
672 if (literalValue != null) {
673 o = literalValue.asNode();
674 }
675
676
677 triples.add(Triple.create(s, p, o));
678 }
679
680
681
682
683
684
685
686
687
688 private static Literal createLiteralValue(QUERY type, MREDataFieldValue field, Object value) {
689
690 if (value == null) {
691 return null;
692 }
693
694 if (value instanceof String) {
695
696 return ResourceFactory.createPlainLiteral((String) value);
697
698 } else if (value instanceof MREStringLang) {
699
700
701 if (((MREStringLang) value).getLang() == null) {
702 return ResourceFactory.createPlainLiteral(((MREStringLang) value).getString());
703 }
704
705
706 return ResourceFactory.createLangLiteral(((MREStringLang) value).getString(), ((MREStringLang) value).getLang());
707 }
708
709
710 return ResourceFactory.createTypedLiteral(value);
711 }
712
713
714
715
716
717
718
719 private void selectAddVariables(SelectBuilder selectBuilder, Object instance) {
720
721 selectBuilder.addVar(VARIABLE_URI);
722 selectBuilder.addVar(VARIABLE_TYPE);
723
724 MREDataFieldValue[] fields = dataService.builderValuesGet(instance);
725 for (MREDataFieldValue field : fields) {
726 selectBuilder.addVar(field.getName());
727 }
728 }
729
730
731
732
733
734
735
736
737
738 private void selectAddWhereVariables(SelectBuilder selectBuilder, Object instance) {
739
740 MREDataFieldValue[] fields = dataService.builderValuesGet(instance);
741
742
743 selectBuilder.addWhere(VARIABLE_URI, RDF.type, VARIABLE_TYPE);
744
745
746 for (MREDataFieldValue field : fields) {
747
748
749 selectBuilder.addOptional(VARIABLE_URI, field.getProperty(), NodeFactory.createVariable(field.getName()));
750 }
751 }
752
753 }