View Javadoc
1   /*
2    * Copyright 2018-2022 Medical Information Systems Research Group (https://medical.zcu.cz),
3    * Department of Computer Science and Engineering, University of West Bohemia.
4    * Address: Univerzitni 8, 306 14 Plzen, Czech Republic.
5    *
6    * Author Petr Vcelak (vcelak@kiv.zcu.cz).
7    *
8    * This file is part of MRECore project.
9    *
10   * MRECore is free software: you can redistribute it and/or modify
11   * it under the terms of the GNU General Public License as published by
12   * the Free Software Foundation, either version 3 of the License.
13   *
14   * MRECore is distributed in the hope that it will be useful,
15   * but WITHOUT ANY WARRANTY; without even the implied warranty of
16   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17   * GNU General Public License for more details.
18   *
19   * You should have received a copy of the GNU General Public License
20   * along with MRECore. If not, see <http://www.gnu.org/licenses/>.
21   */
22  package cz.zcu.mre.service.data;
23  
24  import cz.zcu.mre.annotation.data.MREDataOntology;
25  import cz.zcu.mre.annotation.data.MREDataPropertyName;
26  import cz.zcu.mre.annotation.data.MREDataPropertyURI;
27  import cz.zcu.mre.annotation.data.MREDataURIBasename;
28  import cz.zcu.mre.dao.SPARQLRepository;
29  import cz.zcu.mre.data.core.MREData;
30  import cz.zcu.mre.data.core.MREDataException;
31  import cz.zcu.mre.util.ReflectionsUtil;
32  import cz.zcu.mre.vocab.MRE;
33  import cz.zcu.mre.vocab.NS;
34  import java.lang.reflect.Field;
35  import java.time.LocalDate;
36  import java.time.LocalDateTime;
37  import java.util.ArrayList;
38  import java.util.HashMap;
39  import java.util.HashSet;
40  import java.util.LinkedHashMap;
41  import java.util.List;
42  import java.util.Map;
43  import java.util.Set;
44  import java.util.stream.Collectors;
45  import java.util.stream.Stream;
46  import org.apache.commons.lang3.reflect.FieldUtils;
47  import org.apache.jena.arq.querybuilder.UpdateBuilder;
48  import org.apache.jena.datatypes.xsd.XSDDateTime;
49  import org.apache.jena.ontology.Individual;
50  import org.apache.jena.query.Query;
51  import org.apache.jena.query.QuerySolution;
52  import org.apache.jena.rdf.model.Resource;
53  import org.apache.jena.rdf.model.ResourceFactory;
54  import org.apache.jena.sparql.modify.request.UpdateDeleteInsert;
55  import org.slf4j.Logger;
56  import org.slf4j.LoggerFactory;
57  import org.springframework.beans.factory.annotation.Autowired;
58  import org.springframework.core.convert.ConversionService;
59  
60  /**
61   *
62   * MRE Data Service Implementation.
63   *
64   * @author Petr Vcelak (vcelak@kiv.zcu.cz)
65   */
66  public class MREDataServiceImpl implements MREDataService {
67  
68      private static final Logger LOG = LoggerFactory.getLogger(MREDataServiceImpl.class);
69  
70      private static final Map<Class, List<MREDataBuilderConfig>> converterConfig = new HashMap<>();
71  
72      @Autowired
73      private SPARQLRepository sparqlRepository;
74  
75      @Autowired
76      private SPARQLBuilder sparqlBuilder;
77  
78      @Autowired
79      private ConversionService conversionService;
80  
81      /**
82       * Default constructor.
83       */
84      public MREDataServiceImpl() {
85      }
86  
87      /**
88       * Initialization constructor.
89       *
90       * @param sparqlBuilder SPARQL Builder
91       * @param repository The SPARQL Repository.
92       * @param conversionService The conversion service.
93       */
94      public MREDataServiceImpl(SPARQLBuilder sparqlBuilder, SPARQLRepository repository, ConversionService conversionService) {
95  
96          this.sparqlBuilder = sparqlBuilder;
97          this.sparqlRepository = repository;
98          this.conversionService = conversionService;
99      }
100 
101     public SPARQLBuilder getSparqlBuilder() {
102         return sparqlBuilder;
103     }
104 
105     public void setSparqlBuilder(SPARQLBuilder sparqlBuilder) {
106         this.sparqlBuilder = sparqlBuilder;
107     }
108 
109     public ConversionService getConversionService() {
110         return conversionService;
111     }
112 
113     public SPARQLRepository getSparqlRepository() {
114         return sparqlRepository;
115     }
116 
117     public void setSparqlRepository(SPARQLRepository sparqlRepository) {
118         this.sparqlRepository = sparqlRepository;
119     }
120 
121     public void setConversionService(ConversionService conversionService) {
122         this.conversionService = conversionService;
123     }
124 
125     @Override
126     public MREData createInstance(MREData example) {
127         return createInstance(example, null, null);
128     }
129 
130     @Override
131     public MREData createInstance(MREData example, Resource uri) {
132         return createInstance(example, uri, null);
133     }
134 
135     @Override
136     public MREData createInstance(Resource type) {
137         return createInstance(null, null, type);
138     }
139 
140     @Override
141     public MREData createInstance(Resource type, Resource uri) {
142         return createInstance(null, uri, type);
143     }
144 
145     @Override
146     public MREData createInstance(String typeURI) {
147         return createInstance(null, null, ResourceFactory.createResource(typeURI));
148     }
149 
150     @Override
151     public MREData createInstance(String typeURI, Resource uri) {
152         return createInstance(null, uri, ResourceFactory.createResource(typeURI));
153     }
154 
155     private MREData createInstance(MREData example, Resource uri, Resource type) {
156 
157         MREData instance = null;
158         Class clazz;
159         String instanceTypeURI = null;
160         try {
161 
162             if (example != null) {
163                 clazz = example.getClass();
164 
165                 String namespace = ((MREDataOntology) clazz.getAnnotation(MREDataOntology.class)).namespace();
166                 String name = clazz.getSimpleName();
167                 instanceTypeURI = namespace.concat(name);
168             } else if (type != null) {
169                 // look for annotated Java Bean class
170                 clazz = ReflectionsUtil.lookForAnnotatedJavaClass(type);
171             } else {
172                 // no example and no type, cannot recognize class
173                 return null;
174             }
175 
176             instance = (MREData) clazz.newInstance();
177             if (uri != null) {
178                 instance.setResource(uri);
179             }
180             if (type != null) {
181                 instance.setType(type);
182             } else if (instanceTypeURI != null) {
183                 instance.setType(ResourceFactory.createResource(instanceTypeURI));
184             }
185 
186         } catch (InstantiationException | IllegalAccessException ex) {
187             LOG.error("Cannot instantiate class", ex);
188         }
189 
190         return instance;
191     }
192 
193     /**
194      * ASK if instance is persistent.
195      *
196      * @param instance The MREData instance.
197      * @return true or false.
198      */
199     @Override
200     public boolean isPersistent(MREData instance) {
201         LOG.info("Check persistent instance {} with URI {}", instance.getClass(), instance.getUri());
202 
203         Query query = sparqlBuilder.askExist(instance);
204 
205         return sparqlRepository.queryAsk(query.serialize());
206     }
207 
208     /**
209      * Save MREData instance.
210      *
211      * @param instance The instance.
212      */
213     @Override
214     public boolean save(MREData instance) {
215         LOG.info("Save MREData instance of type {} with URI {}", instance.getClass(), instance.getUri());
216 
217         if (!instance.hasURI()) {
218             return insert(instance);
219         } else if (isPersistent(instance)) {
220             return update(instance);
221         } else {
222             return insert(instance);
223         }
224     }
225 
226     /**
227      * Deeply save MREData instance.
228      *
229      * @param instance The MREData instance.
230      */
231     @Override
232     public boolean saveAll(MREData instance) {
233         LOG.info("Save all MREData instance of type {} with URI {}", instance.getClass(), instance.getUri());
234 
235         if (!instance.hasURI()) {
236             return insertAll(instance);
237         } else if (isPersistent(instance)) {
238             return updateAll(instance);
239         } else {
240             return insertAll(instance);
241         }
242     }
243 
244     /**
245      * Insert MREData instance.
246      *
247      * @param instance The MREData instance.
248      */
249     @Override
250     public boolean insert(MREData instance) {
251 
252         if (!instance.hasURI()) {
253             LOG.info("Resource URI auto-generated for the instance: {}", instance.getResource());
254             instance.generateNewResource();
255         }
256 
257         LOG.info("Insert MREData instance of type {} with URI {}", instance.getClass(), instance.getUri());
258 
259         UpdateBuilder updateBuilder = sparqlBuilder.insert(instance);
260         if (sparqlRepository.queryInsert(updateBuilder.build())) {
261             LOG.debug("Successfully saved MREData instance {}.", instance.getResource().getURI());
262             return true;
263         }
264 
265         final String msg = "MREData instance not saved.";
266         LOG.error(msg);
267         throw new MREDataException(msg);
268         //return false;
269     }
270 
271     /**
272      * Deeply insert MREData instance.
273      *
274      * @param instance The MREData instance.
275      */
276     @Override
277     public boolean insertAll(MREData instance) {
278 
279         if (!instance.hasURI()) {
280             instance.generateNewResource();
281             LOG.info("Resource URI auto-generated for the instance: {}", instance.getResource());
282         }
283 
284         LOG.info("Insert all MREData of type {} with URI {}", instance.getClass(), instance.getUri());
285 
286         UpdateBuilder builder = sparqlBuilder.insertAll(instance);
287         if (sparqlRepository.queryInsert(builder.build())) {
288             LOG.debug("Successfully deeply saved MREData instance {}.", instance.getResource().getURI());
289             return true;
290         }
291 
292         final String msg = "MREData instance not deeply saved.";
293         LOG.error(msg);
294         throw new MREDataException(msg);
295         //return false;
296 
297     }
298 
299     /**
300      * Update MREData instance.
301      *
302      * @param instance The instance.
303      */
304     @Override
305     public boolean update(MREData instance) {
306         LOG.info("Update MREData instance of type {} with URI {}", instance.getClass(), instance.getUri());
307 
308         if (!instance.hasURI()) {
309             return insert(instance);
310         }
311 
312         MREData instanceOld = getAll(instance.getResource());
313 
314         UpdateDeleteInsert builder = sparqlBuilder.update(instanceOld, instance);
315         if (sparqlRepository.queryUpdate(builder)) {
316             LOG.debug("Successfully updated MREData instance {}.", instance.getResource().getURI());
317             return true;
318         }
319 
320         final String msg = "MREData instance not updated.";
321         LOG.error(msg);
322         throw new MREDataException(msg);
323         //return false;
324     }
325 
326     /**
327      * Deeply update MREData instance.
328      *
329      * @param instance The instance.
330      */
331     @Override
332     public boolean updateAll(MREData instance) {
333         LOG.info("Update all MREData of type {} with URI {}", instance.getClass(), instance.getUri());
334 
335         if (!instance.hasURI()) {
336             return insertAll(instance);
337         }
338 
339         MREData instanceOld = getAll(instance.getResource());
340 
341         UpdateDeleteInsert builder = sparqlBuilder.updateAll(instanceOld, instance);
342         if (sparqlRepository.queryUpdate(builder)) {
343             LOG.debug("Successfully deeply updated MREData instance {}.", instance.getResource().getURI());
344             return true;
345         }
346 
347         final String msg = "MREData instance not deeply updated.";
348         LOG.error(msg);
349         throw new MREDataException(msg);
350         //return false;
351     }
352 
353     /**
354      * Delete MREData instance.
355      *
356      * @param instance The instance.
357      */
358     @Override
359     public boolean delete(MREData instance) {
360         LOG.info("Delete MREData instance of type {} with URI {}", instance.getClass(), instance.getUri());
361 
362         UpdateBuilder builder = sparqlBuilder.delete(instance);
363         if (sparqlRepository.queryUpdate(builder.build())) {
364             LOG.debug("Successfully deleted MREData instance {}.", instance.getResource().getURI());
365             return true;
366         }
367 
368         final String msg = "MREData instance not deleted.";
369         LOG.error(msg);
370         throw new MREDataException(msg);
371         //return false;
372     }
373 
374     /**
375      * Deeply delete MREData instance.
376      *
377      * @param instance The instance.
378      */
379     @Override
380     public boolean deleteAll(MREData instance) {
381         LOG.info("Delete all MREData instance of type {} with URI {}", instance.getClass(), instance.getUri());
382 
383         UpdateBuilder builder = sparqlBuilder.deleteAll(instance);
384         if (sparqlRepository.queryUpdate(builder.build())) {
385             LOG.debug("Successfully deeply deleted MREData instance {}.", instance.getResource().getURI());
386             return true;
387         }
388 
389         final String msg = "MREData instance not deeply deleted.";
390         LOG.error(msg);
391         throw new MREDataException(msg);
392         //return false;
393     }
394 
395     /**
396      * Get the stream of MREData instances found by rdf:type.
397      *
398      * @param type RDF class as a type for instances.
399      * @return Stream of MREData instances.
400      */
401     @Override
402     public Stream<MREData> stream(String type) {
403         LOG.info("Stream by type as String {}", type);
404 
405         MREData example = createInstance(type);
406         return stream(example);
407     }
408 
409     /**
410      * Get the stream of MREData instances found by rdf:type.
411      *
412      * @param type RDF class as a type for instances.
413      * @return Stream of MREData instances.
414      */
415     @Override
416     public Stream<MREData> stream(Resource type) {
417         LOG.info("Stream by type {}", type.getURI());
418 
419         MREData example = createInstance(type);
420         return stream(example);
421     }
422 
423     /**
424      * Get the stream of MREData instances found by example.
425      *
426      * @param example An example.
427      * @return Stream of MREData instances.
428      */
429     @Override
430     public Stream<MREData> stream(MREData example) {
431         LOG.info("Stream by example {}", example.getClass());
432 
433         Query query = sparqlBuilder.select(example);
434         List<QuerySolution> result = sparqlRepository.querySelect(query);
435 
436         return asStream(result);
437     }
438 
439     /**
440      * Get the stream of MREData instances found by example.
441      *
442      * @param example An example.
443      * @return Stream of MREData instances.
444      */
445     @Override
446     public Stream<MREData> streamAll(MREData example) {
447         LOG.info("Stream by example {}", example.getClass());
448 
449         Query query = sparqlBuilder.selectAll(example);
450         List<QuerySolution> result = sparqlRepository.querySelect(query);
451 
452         return asStream(result);
453     }
454 
455     /**
456      * Parse List of QuerySolution instances to build MREData instances as a
457      * stream.
458      *
459      * TODO can be improved when result ordered by resource URI.
460      *
461      * @param result MRE-query result as a List of QuerySolution instances.
462      * @return Stream with MREData instances.
463      */
464     @Override
465     public Stream<MREData> asStream(List<QuerySolution> result) {
466 
467         Map<Resource, MREData> map = new LinkedHashMap<>();
468 
469         // loop over all QuerySolution instances
470         result.forEach((qs) -> {
471 
472             // recognize URI
473             Resource uri = qs.get(SPARQLBuilderString.SELECT_VARIABLE_URI).asResource();
474             // recognize rdf:type
475             Resource type = qs.get(SPARQLBuilderString.SELECT_VARIABLE_TYPE).asResource();
476 
477             MREData data;
478 
479             // first, check if previous result exist
480             if (map.containsKey(uri)) {
481                 LOG.debug("Previous result of type={} has uri={}", type, uri);
482 
483                 // one instance should have more values of any attribute, so it is stored in more QuerySolution instances.
484                 data = map.get(uri);
485                 data.setType(type);
486 
487             } else {
488 
489                 // create new instance for the query solution
490                 data = createInstance(null, uri, type);
491                 if (data != null) {
492                     LOG.debug("New instance for class={}, type={}, uri={}", data.getClass(), type, uri);
493                     map.put(uri, data);
494                 }
495             }
496 
497             // initialise instance fields by values in QuerySolution.
498             builderValuesSet(data, qs);
499         });
500 
501         // stream map values
502         return map.values().stream();
503     }
504 
505     /**
506      * Get the list of MREData instances found by rdf:type.
507      *
508      * @param type RDF class as a type for instances.
509      * @return List of MREData instances.
510      */
511     @Override
512     public List<MREData> list(String type) {
513         LOG.info("List by type as String {}", type);
514 
515         MREData example = createInstance(type);
516         return list(example);
517     }
518 
519     /**
520      * Get the list of MREData instances found by rdf:type.
521      *
522      * @param type RDF class as a type for instances.
523      * @return List of MREData instances.
524      */
525     @Override
526     public List<MREData> list(Resource type) {
527         LOG.info("List by type {}", type.getURI());
528 
529         MREData example = createInstance(type);
530         return list(example);
531     }
532 
533     /**
534      * Get list of MREData instances found by example.
535      *
536      * @param example An example.
537      * @return List of MREData instances.
538      */
539     @Override
540     public List<MREData> list(MREData example) {
541         LOG.info("List by example {}", example.getClass());
542 
543         return stream(example).collect(Collectors.toList());
544     }
545 
546     /**
547      * Get list of MREData instances found by example.
548      *
549      * @param example An example.
550      * @return List of MREData instances.
551      */
552     @Override
553     public List<MREData> listAll(MREData example) {
554         LOG.info("List all by example class {}", example);
555 
556         return streamAll(example).collect(Collectors.toList());
557     }
558 
559     /**
560      * Get the MREData instance by its URI.
561      *
562      * @param resourceUri The URI as a String.
563      * @return Null or MREData instance.
564      */
565     @Override
566     public MREData get(String resourceUri) {
567 
568         Query queryType = sparqlBuilder.selectType(resourceUri);
569         return get(queryType, ResourceFactory.createResource(resourceUri));
570     }
571 
572     @Override
573     public MREData getAll(String resourceUri) {
574         Query queryType = sparqlBuilder.selectType(resourceUri);
575         return getAll(queryType, ResourceFactory.createResource(resourceUri));
576     }
577 
578     /**
579      * Get the MREData instance by its URI and values of all fields with
580      * primitive types.
581      *
582      * @param resourceUri The URI as a Resource.
583      * @return Null or MREData instance.
584      */
585     @Override
586     public MREData get(Resource resourceUri) {
587 
588         Query queryType = sparqlBuilder.selectType(resourceUri);
589         return get(queryType, resourceUri);
590     }
591 
592     /**
593      * Get the MREData instance by its URI.
594      *
595      * @param resourceUri The URI as a Resource.
596      * @return Null or MREData instance.
597      */
598     @Override
599     public MREData getAll(Resource resourceUri) {
600 
601         Query queryType = sparqlBuilder.selectType(resourceUri);
602         return getAll(queryType, resourceUri);
603     }
604 
605     /**
606      * Get the MREData instance by its URI and values of all fields with
607      * primitive types.
608      *
609      * @param getRdfTypeQuery String for getting the instance rdf:type we have
610      * to know because of creating a right MREData instance.
611      * @param resourceUri The resource to get.
612      * @return Null or MREData instance.
613      */
614     private MREData get(Query getRdfTypeQuery, Resource resourceUri) {
615 
616         List<QuerySolution> list = sparqlRepository.querySelect(getRdfTypeQuery);
617 
618         if (list.isEmpty()) {
619             return null;
620         }
621 
622         QuerySolution qs = list.get(0); // get only the first rdf:type value
623         String type = qs.getResource("type").getURI();
624         if (type == null) {
625             return null;
626         }
627 
628         MREData example = createInstance(type, resourceUri);
629         example.setResource(resourceUri); // have to set instance URI
630         return get(example);
631     }
632 
633     /**
634      * Get the MREData instance by its URI.
635      *
636      * @param getRdfTypeQuery String for getting the instance rdf:type we have
637      * to know because of creating a right MREData instance.
638      * @param resourceUri The resource to get.
639      * @return Null or MREData instance.
640      */
641     private MREData getAll(Query getRdfTypeQuery, Resource resourceUri) {
642 
643         List<QuerySolution> list = sparqlRepository.querySelect(getRdfTypeQuery);
644 
645         if (list.isEmpty()) {
646             return null;
647         }
648 
649         QuerySolution qs = list.get(0); // get only the first rdf:type value
650         String type = qs.getResource("type").getURI();
651         if (type == null) {
652             return null;
653         }
654 
655         MREData example = createInstance(type, resourceUri);
656         example.setResource(resourceUri); // have to set instance URI
657         return getAll(example);
658     }
659 
660     /**
661      * Get one MREData instance by example and values of all fields with
662      * primitive types.
663      *
664      * @param example An example.
665      * @return Null or MREData instance.
666      */
667     @Override
668     public MREData get(MREData example) {
669         List<MREData> list = list(example);
670 
671         if (list.isEmpty()) {
672             return null;
673         }
674 
675         return list.get(0);
676     }
677 
678     /**
679      * Get one MREData instance by example.
680      *
681      * @param example An example.
682      * @return Null or MREData instance.
683      */
684     @Override
685     public MREData getAll(MREData example) {
686         List<MREData> list = listAll(example);
687 
688         if (list.isEmpty()) {
689             return null;
690         }
691 
692         return list.get(0);
693     }
694 
695     /**
696      * User-defined SELECT query.
697      *
698      * @param query SPARQL.
699      * @return Stream of QuerySolution instances.
700      */
701     @Override
702     public Stream<QuerySolution> select(String query) {
703         return sparqlRepository.querySelect(query).stream();
704     }
705 
706     @Override
707     public MREDataFieldValue[] builderValuesGet(Object instance) {
708 
709         List<MREDataBuilderConfig> config = builderBeanConfigGet(instance);
710         MREDataFieldValue[] result = new MREDataFieldValue[config.size()];
711         int i = 0;
712 
713         for (MREDataBuilderConfig c : config) {
714             result[i] = new MREDataFieldValue();
715             result[i].setConfig(c);
716             result[i].getValue().add(builderFieldValueGet(instance, c.getField()));
717             if (instance instanceof MREData) {
718 
719                 if (((MREData) instance).hasURI()) { // test as a prevention to generation of new uri
720                     result[i].setSubject(((MREData) instance).getResource().getURI());
721                 }
722             }
723 
724             i++;
725         }
726 
727         return result;
728     }
729 
730     private Object builderFieldValueGet(Object instance, Field field) {
731 
732         Object object = null;
733         field.setAccessible(true);
734 
735         try {
736             object = field.get(instance);
737         } catch (IllegalArgumentException | IllegalAccessException ex) {
738             LOG.error("{}", ex.toString());
739         }
740         return object;
741     }
742 
743     public void builderValuesSet(Object instance, QuerySolution qs) {
744 
745         MREDataFieldValue[] fields = builderValuesGet(instance);
746         for (MREDataFieldValue field : fields) {
747 
748             String name = field.getName();
749             Class type = field.getConfig().getField().getType();
750 
751             if (!qs.contains(name)) {
752                 // no value for this field
753                 LOG.debug("Missing field {} in QuerySolution", name);
754                 continue;
755             } else if (qs.get(name) == null) {
756                 // no value for this field
757                 LOG.debug("Null value for field {}", name);
758                 continue;
759             }
760 
761             // decide the field type
762             if (type == Individual.class) {
763 
764                 Individual individual = ReflectionsUtil.lookupIndividual(qs.getResource(name));
765                 LOG.debug("Set value for Individual field={}, class={}, value={}", name, type, individual);
766 
767                 builderFieldValueSet(instance, field.getConfig().getField(), individual);
768 
769             } else if (type == List.class) {
770                 // the field is List of Java objects
771 
772                 // if field value is null - create new empty ArrayList()
773                 List list = (List) builderFieldValueGet(instance, field.getConfig().getField());
774                 if (list == null) {
775                     list = new ArrayList();
776                     builderFieldValueSet(instance, field.getConfig().getField(), list);
777                 }
778 
779                 // create new instance and add to the list
780                 Object object = builderCreateJavaObject(qs, field);
781                 list.add(object);
782 
783             } else if (type == Set.class) {
784                 // the field is Set of Java objects
785 
786                 // if field value is null - create new empty HashList()
787                 Set set = (Set) builderFieldValueGet(instance, field.getConfig().getField());
788                 if (set == null) {
789                     set = new HashSet();
790                     builderFieldValueSet(instance, field.getConfig().getField(), set);
791                 }
792 
793                 // create new instance and add to the list
794                 Object object = builderCreateJavaObject(qs, field);
795                 set.add(object);
796 
797             } else if (type == Map.class) {
798                 // the field is generic Map of Java objects
799 
800                 // if field value is null - create new empty HashList()
801                 Map map = (Map) builderFieldValueGet(instance, field.getConfig().getField());
802                 if (map == null) {
803                     map = new HashMap();
804                     builderFieldValueSet(instance, field.getConfig().getField(), map);
805                 }
806 
807                 // create new instance, get key and add to the map
808                 Object object = builderCreateJavaObject(qs, field);
809                 Object key;
810                 if (object instanceof MREData) {
811                     // get ID for MREDeta instances
812                     key = ((MREData) object).getId();
813                 } else {
814                     key = object.hashCode(); // TODO improve how to get key
815                 }
816                 map.put(key, object);
817 
818             } else {
819 
820                 // all other types
821                 builderFieldValueSet(instance, field.getConfig().getField(), builderCreateJavaObject(qs, field));
822             }
823 
824         }
825     }
826 
827     private Object builderCreateJavaObject(QuerySolution qs, MREDataFieldValue field) {
828 
829         String name = field.getName();
830         Class type = field.getConfig().getField().getType();
831 
832         if (qs.get(name).isLiteral()) {
833 
834             Object value = qs.getLiteral(name).getValue();
835             LOG.debug("Set value for Literal field={}, class={}, value={}", name, type, value);
836             return builderValueConvert(type, value);
837 
838         } else if (qs.get(name).isResource()) {
839             Resource uri = qs.getResource(name);
840             Object object;
841             LOG.debug("Set value for Object field={}, class={}, value={}", name, type, uri);
842 
843             // get MREData instance for the URI
844             object = getAll(uri);
845 
846             return object;
847         }
848 
849         // something wrong?
850         return null;
851     }
852 
853     /**
854      * Convert a value to the required Class type.
855      *
856      * @param type The type for the result.
857      * @param value The value.
858      * @return
859      */
860     private Object builderValueConvert(Class type, Object value) {
861 
862         if (value == null) {
863 
864             return null;
865 
866         } else if (type == value.getClass()) {
867 
868             LOG.debug("No conversion required for {} with value {}", value.getClass(), value);
869             return value;
870 
871         } else if (type == List.class
872                 || type == Set.class
873                 || type == Map.class) {
874 
875             LOG.warn("No conversion for type {}, value {} ", type, value);
876             return value;
877 
878         }
879 
880         Object newValue = value;
881 
882         /* use Spring's ConversionService */
883         if (conversionService.canConvert(value.getClass(), type)) {
884 
885             newValue = conversionService.convert(value, type);
886             LOG.debug("Conversion for {} to {}, value {}", value.getClass(), type, value);
887 
888         } else /* use own "local" conversions */ if (type == LocalDate.class && value instanceof XSDDateTime) {
889 
890             XSDDateTime date = (XSDDateTime) value;
891             newValue = LocalDate.parse(date.toString());
892 
893         } else if (type == LocalDateTime.class && value instanceof XSDDateTime) {
894 
895             XSDDateTime datetime = (XSDDateTime) value;
896             newValue = LocalDateTime.parse(datetime.toString());
897 
898         } else if (!isPrimitiveDataType(value) && type != newValue.getClass()) {
899             LOG.error("Cannot convert {} to {}", value.getClass(), type);
900         }
901 
902         return newValue;
903     }
904 
905     private void builderFieldValueSet(Object instance, Field field, Object value) {
906 
907         field.setAccessible(true);
908 
909         try {
910             field.set(instance, value);
911         } catch (IllegalArgumentException | IllegalAccessException ex) {
912             LOG.error("Unable to set value for field {}", field.getName(), ex);
913         }
914     }
915 
916     private List<MREDataBuilderConfig> builderBeanConfigGet(Object instance) {
917 
918         if (instance == null) {
919             return null;
920         }
921 
922         if (converterConfig.containsKey(instance.getClass())) {
923             return converterConfig.get(instance.getClass());
924         }
925 
926         return builderAnnotationsGet(instance);
927     }
928 
929     private List<MREDataBuilderConfig> builderAnnotationsGet(Object instance) {
930 
931         List<MREDataBuilderConfig> fieldsMapping = new ArrayList<>();
932         List<Field> allFields = FieldUtils.getAllFieldsList(instance.getClass());
933         MREDataURIBasename[] annotationNSData = instance.getClass().getAnnotationsByType(MREDataURIBasename.class);
934         MREDataOntology[] annotationOntology = instance.getClass().getAnnotationsByType(MREDataOntology.class);
935 
936         // MRE name space for data.
937         String nsData = NS.ID;
938 
939         // MRE name space when not set.
940         String ontology = MRE.NS;
941 
942         if (annotationNSData != null && annotationNSData.length > 0) {
943             nsData = annotationNSData[0].basename();
944         }
945 
946         LOG.debug("Java {} --> instance base URI {}", instance.getClass(), nsData);
947 
948         if (annotationOntology != null && annotationOntology.length > 0) {
949             ontology = annotationOntology[0].namespace();
950         } else {
951             LOG.warn("Java {} does not have an ontology annotation {}.", instance.getClass(), MREDataOntology.class);
952         }
953 
954         String uri;
955         for (Field f : allFields) {
956 
957             if (f.getName().equals("resource")
958                     || java.lang.reflect.Modifier.isStatic(f.getModifiers())
959                     || java.lang.reflect.Modifier.isFinal(f.getModifiers())) {
960                 continue;
961             }
962 
963             if (f.isAnnotationPresent(MREDataPropertyName.class)) {
964                 MREDataPropertyName mREDataPropertyName = f.getAnnotation(MREDataPropertyName.class);
965                 uri = ontology + mREDataPropertyName.name();
966 
967             } else if (f.isAnnotationPresent(MREDataPropertyURI.class)) {
968                 MREDataPropertyURI mREDataPropertyURI = f.getAnnotation(MREDataPropertyURI.class);
969                 uri = mREDataPropertyURI.uri();
970             } else {
971                 uri = ontology + f.getName();
972             }
973 
974             LOG.debug("Java {}, field '{}' --> '{}'", instance.getClass(), f.getName(), uri);
975 
976             MREDataBuilderConfig converterData = new MREDataBuilderConfig();
977             converterData.setClazz(instance.getClass());
978             converterData.setOntology(ontology);
979             //converterData.setOntologyClass(ontology);
980             converterData.setField(f);
981             converterData.setDataNamespace(nsData);
982             converterData.setProperty(ResourceFactory.createProperty(uri));
983 
984             fieldsMapping.add(converterData);
985         }
986 
987         // add to config map
988         converterConfig.put(instance.getClass(), fieldsMapping);
989 
990         // return fields mapping for this instance
991         return fieldsMapping;
992     }
993 
994     @Override
995     public boolean isPrimitiveDataType(Object object) {
996 
997         return object instanceof Byte
998                 || object instanceof Short
999                 || object instanceof Integer
1000                 || object instanceof Long
1001                 || object instanceof Float
1002                 || object instanceof Double
1003                 || object instanceof Character
1004                 || object instanceof String
1005                 || object instanceof Boolean;
1006     }
1007 
1008 //     public static void builderValuesSet(Object instance, Model model) {
1009 //
1010 //        // TODO implement
1011 //        // setFieldValue(Object instance, Field field, Object value)
1012 //    }
1013 }