View Javadoc
1   /*
2    * Copyright 2013-2023 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    * This file is part of Sparkle project.
7    *
8    * Sparkle is free software: you can redistribute it and/or modify
9    * it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License.
11   *
12   * Sparkle is distributed in the hope that it will be useful,
13   * but WITHOUT ANY WARRANTY; without even the implied warranty of
14   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15   * GNU General Public License for more details.
16   *
17   * You should have received a copy of the GNU General Public License
18   * along with Sparkle. If not, see <http://www.gnu.org/licenses/>.
19   */
20  package cz.zcu.mre.sparkle.data.resourceStorage;
21  
22  import cz.zcu.mre.sparkle.data.AbstractTermsStorage;
23  import cz.zcu.mre.sparkle.data.BuiltInVocabulary;
24  import cz.zcu.mre.sparkle.data.DataAgent;
25  import cz.zcu.mre.sparkle.data.PrefixesStorage;
26  import cz.zcu.mre.sparkle.tools.Changeable;
27  import javafx.beans.InvalidationListener;
28  import javafx.beans.Observable;
29  import javafx.beans.value.ObservableBooleanValue;
30  import javafx.collections.ObservableList;
31  import javafx.stage.Stage;
32  import org.apache.jena.rdf.model.Resource;
33  import java.io.File;
34  import java.io.IOException;
35  import java.io.Serializable;
36  import java.lang.reflect.Field;
37  import java.util.HashSet;
38  import java.util.List;
39  import java.util.Set;
40  import java.util.logging.Level;
41  import java.util.logging.Logger;
42  
43  /**
44   * Třída pro skladování ostatních RDF zdrojů.
45   *
46   * @author Jan Smucr
47   * @author Klara Hlavacova
48   * @author Petr Vcelak (vcelak@kiv.zcu.cz)
49   * @see AbstractTermsStorage
50   */
51  public final class ResourcesStorage
52          extends AbstractTermsStorage<ResourceStorageEntry>
53          implements Observable, Changeable, Serializable {
54  
55      private static final Logger LOG = Logger.getLogger(ResourcesStorage.class.getName());
56  
57      private final Set<InvalidationListener> observers = new HashSet<>();
58  
59      private static final long serialVersionUID = 5882457314144281288L;
60      private static final String XML_ELEMENT_NAME = "Resources"; //$NON-NLS-2$
61  
62      public ResourcesStorage(final DataAgent dataAgent, final PrefixesStorage prefixesStorage) {
63          super(dataAgent, prefixesStorage);
64      }
65  
66      /**
67       * Deserializace objektu
68       *
69       * @param in vstupni proud
70       *
71       * @throws IOException IO exception.
72       * @throws ClassNotFoundException Class not found exception.
73       */
74      private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {
75          in.defaultReadObject();
76      }
77  
78      /**
79       * Vrátí instanci {@link ResourcesStorage} obsahující vestavěné pojmy.
80       *
81       * @param dataAgent Instance {@link DataAgent}.
82       * @param prefixesStorage Instance {@link PrefixesStorage}.
83       *
84       * @return Instance {@link ResourcesStorage}.
85       */
86      public static final ResourcesStorage getBuiltIn(final DataAgent dataAgent, final PrefixesStorage prefixesStorage) {
87  
88          final ResourcesStorage result = new ResourcesStorage(dataAgent, prefixesStorage);
89          BuiltInVocabulary builtInNamespaces = new BuiltInVocabulary();
90  
91          builtInNamespaces.getBuiltInNamespaces().forEach((entry) -> {
92              result.loadVocabulary(entry.getVocabularyClass());
93          });
94  
95          return result;
96      }
97  
98      /**
99       * Načte pojmy z Java třídy reprezentující slovník. Pojmy jsou očekávány v
100      * podobě statických konstant typu {@link Resource}.
101      *
102      * @param vocabularyClass Třída slovníku.
103      */
104     private void loadVocabulary(final Class<?> vocabularyClass) {
105         for (final Field field : vocabularyClass.getDeclaredFields()) {
106             try {
107                 new ResourceStorageUpdater(this).addFromField(field);
108             } catch (IllegalArgumentException | IllegalAccessException e) {
109                 LOG.log(Level.SEVERE, "Exception: ", e); //$NON-NLS-2$
110             }
111         }
112     }
113 
114     /**
115      * Aktualizace termu (po nahrani dat do uloziste)
116      *
117      * @param stage Instance {@link Stage}
118      * @param files seznam souboru s daty
119      * @param namespaces seznam jmennych prostoru
120      */
121     public void updateResourceStorage(Stage stage, List<File> files, Set<String> namespaces) {
122         new ResourceStorageUpdater(this).updateResourceStorage(stage, files, namespaces);
123     }
124 
125     /**
126      * Aktualizace uloziste ze souboru
127      *
128      * @param stage Instance {@link Stage}
129      * @param namespace jmenny prostor
130      * @param size pocet namespace, ktere se aktualizuje
131      * @param index index aktualizovaneho namespace
132      * @return number of the integer type.
133      */
134     public int updateResourceStorage(Stage stage, String namespace, int size, int index) {
135         return new ResourceStorageUpdater(this).updateResourceStorage(stage, namespace, size, index);
136     }
137 
138     /**
139      * Přidá pojmy z uvedeného jmenného prostoru z úložiště.
140      *
141      * @param namespace Jmenný prostor.
142      * @param includeNamedIndividuals Pokud je <code>false</code>, budou
143      * filtrovány instance owl:NamedIndividual.
144      * @param cancelled Sledovatelná {@link Boolean} hodnota. Pokud je nastavena
145      * na <code>true</code>, bude požádáno o přerušení operace.
146      *
147      * @return Počet přidaných pojmů.
148      */
149     public final int addFromStorage(final String namespace, final boolean includeNamedIndividuals,
150             final ObservableBooleanValue cancelled) {
151         return new ResourceStorageUpdater(this).addFromStorage(namespace, includeNamedIndividuals, cancelled);
152     }
153 
154     /**
155      * Přidá pojmy z uvedeného jmenného prostoru z úložiště.
156      *
157      * @param namespace Jmenný prostor.
158      * @param includeNamedIndividuals Pokud je <code>false</code>, budou
159      * filtrovány instance owl:NamedIndividual.
160      * @param cancelled Sledovatelná {@link Boolean} hodnota. Pokud je nastavena
161      * na <code>true</code>, bude požádáno o přerušení operace.
162      * @param dataAgent Zdroj dat.
163      *
164      * @return Počet přidaných pojmů.
165      */
166     public int addFromStorage(final String namespace, final boolean includeNamedIndividuals,
167             final ObservableBooleanValue cancelled, final DataAgent dataAgent) {
168 
169         return new ResourceStorageUpdater(this).addFromStorage(namespace,
170                 includeNamedIndividuals, cancelled, dataAgent);
171     }
172 
173     //==============================================
174     /**
175      * Vrací seznam jmen všech známých zdrojů na základě prefixu.
176      *
177      * @param prefix Prefix.
178      * @param includePrefix Pokud je <code>true</code>, prefix bude součástí
179      * názvů ve výsledku.
180      *
181      * @return Seznam názvů zdrojů/pojmů.
182      */
183     public final ObservableList<String> getResourcesNamesByPrefix(final String prefix, final boolean includePrefix) {
184         return getTermsNamesByPrefix(prefix, includePrefix, ResourceStorageEntry.class);
185     }
186 
187     /**
188      * Vrací seznam všech známých zdrojů na základě prefixu.
189      *
190      * @param prefix Prefix.
191      *
192      * @return Seznam zdrojů/pojmů.
193      */
194     public final ObservableList<Object> getResourcesByPrefix(final String prefix) {
195 
196         return getTermsByPrefix(prefix, ResourceStorageEntry.class);
197     }
198 
199     /**
200      * Vrací seznam jmen všech známých vlastností na základě prefixu.
201      *
202      * @param prefix Prefix.
203      * @param includePrefix Pokud je <code>true</code>, prefix bude součástí
204      * názvů ve výsledku.
205      *
206      * @return Seznam názvů vlastností.
207      */
208     public final ObservableList<String> getPropertiesNamesByPrefix(final String prefix, final boolean includePrefix) {
209 
210         return getTermsNamesByPrefix(prefix, includePrefix, PropertyStorageEntry.class);
211     }
212 
213     /**
214      * Vrací seznam všech známých vlastností na základě prefixu.
215      *
216      * @param prefix Prefix.
217      *
218      * @return Seznam názvů vlastností.
219      */
220     public final ObservableList<Object> getPropertiesByPrefix(final String prefix) {
221         return getTermsByPrefix(prefix, PropertyStorageEntry.class);
222     }
223 
224     @Override
225     public final String getTermNamespace(final ResourceStorageEntry term) {
226         return term.getNamespace();
227     }
228 
229     @Override
230     public final String getTermName(final ResourceStorageEntry term) {
231         return term.getLocalName();
232     }
233 
234     @Override
235     public String getTermTitle(ResourceStorageEntry term) {
236         return term.getTitle();
237     }
238 
239     @Override
240     public final String getXMLElementName() {
241         return XML_ELEMENT_NAME;
242     }
243 
244     @Override
245     protected final ResourceStorageEntry createTerm(final String namespace, final String localName, String title) {
246         return new ResourceStorageEntry(namespace, localName, title);
247     }
248 
249     @Override
250     protected final ResourceStorageEntry createTerm(final String namespace, final String localName, String title,
251             String type) {
252 
253         if (type.equalsIgnoreCase(PROPERTY_STORAGE_ENTRY)) {
254             return new PropertyStorageEntry(namespace, localName, title);
255         } else {
256             return new ResourceStorageEntry(namespace, localName, title);
257         }
258     }
259 
260     @Override
261     public Set<InvalidationListener> getObservers() {
262         return observers;
263     }
264 
265     //=============================================
266     //=============================================
267 
268     /*
269      * The method obtains values of a RDFS:LABEL predicate (including their
270      * data types).
271      *
272      * @param dataAgent        Instance of {@link DataAgent}.
273      * @param originalQuery    Original form of whole query.
274      * @param triplePanePart   Currently edited {@link TriplePane}.
275      * @param selectedLanguage Prefered language (it's selected in {@link ComboBox}
276      *                         at the top right of main window).
277      * @param caretPosition    Caret position in owner text field.
278      * @param cancelled        Boolean variable - if it is <code>true</code> then obtaining of
279      *                         RDFS:LABELs is terminated.
280      *
281      * @return ObservableList of RDFS:LABEL values.
282      */
283  /* public final ObservableList<String> getLabels(final DataAgent dataAgent, final String originalQuery,
284             final String triplePanePart, final String selectedLanguage, int caretPosition,
285             final ObservableBooleanValue cancelled) {
286         final String requredPrefixName = "rdfs:label"; //$NON-NLS-1$
287         final String requredVariable = "label"; //$NON-NLS-1$
288         final ObservableList<String> results = FXCollections.observableArrayList();
289         final String queryText =
290                 adjustLabelQuery(originalQuery, triplePanePart, requredPrefixName, requredVariable, caretPosition);
291         final CancellableConsumer<QuerySolution> consumer = new CancellableConsumer<QuerySolution>() {
292             @Override
293             public void accept(final QuerySolution qs) {
294                 final Literal literal = getLiteralNode(qs, requredVariable);
295                 if (literal != null) {
296                     final String literalType = getLiteralType(prefixesStorage, literal, selectedLanguage);
297                     if (literalType != null) {
298                         results.add(requredPrefixName + Definitions.SPACE + Definitions.QUOTATION_MARK +
299                                     literal.getString() + Definitions.QUOTATION_MARK + literalType);
300                     }
301                 }
302             }
303         };
304         final ChangeListener<Boolean> cancellationListener = (observable, oldValue, newValue) -> {
305             if (newValue) {
306                 consumer.cancel();
307             }
308         };
309 
310         cancelled.addListener(cancellationListener);
311         dataAgent.select(queryText, consumer);
312         cancelled.removeListener(cancellationListener);
313         return results;
314     }
315      */
316  /*
317      * It adjusts "property path" to wanted RDFS:label.
318      *
319      * @param propertyPath         The full property path.
320      * @param requiredPropertyText RDFS:LABEL.
321      * @param caretPosition        Caret position in owner text field.
322      *
323      * @return The property path to wanted RDFS:label.
324      */
325  /* private StringBuilder getPropertyPathToLabel(final String propertyPath, final String requiredPropertyText,
326             final int caretPosition) {
327         StringBuilder sb = new StringBuilder();
328         int endOfPropPath = propertyPath.substring(0, caretPosition).lastIndexOf(Definitions.PROPERTY_PATH_DELIMITER);
329         if (endOfPropPath > -1) {
330             endOfPropPath++;
331             sb.append(propertyPath.substring(0, endOfPropPath));
332         }
333         sb.append(requiredPropertyText);
334         return sb;
335     }
336      */
337  /*
338      * It creates query to searching of RDFS:LABEL from whole triple.
339      *
340      * @param matcher                   Regex matches of triple.
341      * @param groupGraphPatternPanePart Full WHERE clause.
342      * @param triplePanePart            Current form of {@link TriplePane} instance.
343      * @param indexOfTriplePane         Index of <code>triplePanePart</code> in original query.
344      * @param requiredVariable          "label".
345      * @param requiredPropertyText      RDFS:LABEL.
346      * @param caretPosition             Caret position in owner text field.
347      *
348      * @return Query to searching of RDFS:LABEL.
349      */
350  /* private StringBuilder createQueryFromTriple(final Matcher matcher, final String groupGraphPatternPanePart,
351             final String triplePanePart, final int indexOfTriplePane, final String requiredVariable,
352             final String requiredPropertyText, final int caretPosition) {
353         final StringBuilder sb = new StringBuilder(" SELECT ?"); //$NON-NLS-1$
354         sb.append(requiredVariable).append(" WHERE ") //$NON-NLS-2$
355           .append(groupGraphPatternPanePart
356                           .substring(0, indexOfTriplePane)).
357                   append(matcher.group(1))
358           .append(Definitions.SPACE).
359                   append(getPropertyPathToLabel(
360                           matcher.group(2),
361                           requiredPropertyText,
362                           caretPosition))
363           .append(" ?").append(requiredVariable)
364           .append(" . "). //$NON-NLS-1$ //$NON-NLS-2$
365                                   append(
366                 groupGraphPatternPanePart.substring(indexOfTriplePane + triplePanePart.length()));
367         return sb;
368     }*/
369 
370  /*
371      * It creates query to searching of RDFS:LABEL from subtriple.
372      *
373      * @param matcher                   Regex matches of triple.
374      * @param groupGraphPatternPanePart Full WHERE clause.
375      * @param triplePanePart            Current form of {@link TriplePane} instance.
376      * @param indexOfTriplePane         Index of <code>triplePanePart</code> in original query.
377      * @param requiredVariable          "label".
378      * @param requiredPropertyText      RDFS:LABEL.
379      * @param caretPosition             Caret position in owner text field.
380      *
381      * @return Query to searching of RDFS:LABEL.
382      */
383  /* private StringBuilder createQueryFromSubTriple(final Matcher matcher, final String groupGraphPatternPanePart,
384             final String triplePanePart, final int indexOfTriplePane, final String requiredVariable,
385             final String requiredPropertyText, final int caretPosition) {
386         final StringBuilder sb = new StringBuilder(" SELECT ?"); //$NON-NLS-1$
387         sb.append(requiredVariable).append(" WHERE ") //$NON-NLS-2$
388           .append(groupGraphPatternPanePart
389                           .substring(0, indexOfTriplePane)). //$NON-NLS-1$
390                                                                      append(
391                 getPropertyPathToLabel(matcher.group(1), requiredPropertyText, caretPosition)).append(" ?")
392                                                              .append(requiredVariable). //$NON-NLS-1$
393                                                                                                 append(
394                 groupGraphPatternPanePart.substring(indexOfTriplePane + triplePanePart.length() - 1));
395         return sb;
396     }*/
397 
398  /*
399      * The method forms a final query that is used to obtain RDFS:LABEL values.
400      *
401      * @param originalQuery        Original form of obtained query.
402      * @param triplePanePart       Current form of {@link TriplePane} instance.
403      * @param requiredPropertyText RDFS:LABEL.
404      * @param requiredVariable     "label".
405      * @param caretPosition        Caret position in owner text field.
406      *
407      * @return Final form of query.
408      */
409  /* private String adjustLabelQuery(final String originalQuery, final String triplePanePart,
410             final String requiredPropertyText, final String requiredVariable, final int caretPosition) {
411 
412         final String groupGraphPatternPanePart = getGroupGraphPattPaneFromQuery(originalQuery, triplePanePart);
413         final int indexOfTriplePane = groupGraphPatternPanePart.indexOf(triplePanePart);
414         StringBuilder sb = new StringBuilder();
415         Matcher m = TRIPLE_PANE.matcher(triplePanePart);
416         if (m.matches()) {
417             sb.append(createQueryFromTriple(m, groupGraphPatternPanePart, triplePanePart, indexOfTriplePane,
418                                             requiredVariable, requiredPropertyText, caretPosition));
419         } else {
420             m = SUB_TRIPLE_PANE.matcher(triplePanePart);
421             if (m.matches()) {
422                 sb.append(createQueryFromSubTriple(m, groupGraphPatternPanePart, triplePanePart, indexOfTriplePane,
423                                                    requiredVariable, requiredPropertyText, caretPosition));
424             }
425         }
426         if (sb.length() > 0) {
427             sb.insert(0,
428                       getUsedQueryPrefixes(getQueryPrefixesStorage().getNsPrefixMap(), sb.toString())); // Adding of prefixes
429             return sb.toString();
430         }
431         return null;
432     }*/
433 
434  /*
435      * It obtains a literal record from QuerySolution (result of SELECT query).
436      *
437      * @param qs      Result of SELECT query.
438      * @param varName Name of required variable.
439      *
440      * @return A RDF literal record.
441      */
442  /*  private Literal getLiteralNode(final QuerySolution qs, final String varName) {
443         if (!qs.contains(varName)) {
444             return null;
445         }
446 
447         final RDFNode node = qs.get(varName);
448         if (!node.isLiteral()) {
449             return null;
450         }
451 
452         return node.asLiteral();
453     }
454      */
455 }