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 }