001/**
002 * Copyright (C) 2007 - 2016, Jens Lehmann
003 *
004 * This file is part of DL-Learner.
005 *
006 * DL-Learner is free software; you can redistribute it and/or modify
007 * it under the terms of the GNU General Public License as published by
008 * the Free Software Foundation; either version 3 of the License, or
009 * (at your option) any later version.
010 *
011 * DL-Learner is distributed in the hope that it will be useful,
012 * but WITHOUT ANY WARRANTY; without even the implied warranty of
013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
014 * GNU General Public License for more details.
015 *
016 * You should have received a copy of the GNU General Public License
017 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
018 */
019package org.dllearner.kb.sparql;
020
021import java.util.List;
022import java.util.Set;
023import java.util.SortedSet;
024import java.util.TreeSet;
025
026import org.apache.log4j.Logger;
027import org.dllearner.reasoning.SPARQLReasoner;
028import org.dllearner.utilities.datastructures.RDFNodeTuple;
029import org.dllearner.utilities.datastructures.StringTuple;
030import org.dllearner.utilities.owl.OWLClassExpressionToSPARQLConverter;
031import org.dllearner.utilities.owl.OWLVocabulary;
032import org.semanticweb.owlapi.model.IRI;
033import org.semanticweb.owlapi.model.OWLClass;
034import org.semanticweb.owlapi.model.OWLDataFactory;
035import org.semanticweb.owlapi.model.OWLDataProperty;
036import org.semanticweb.owlapi.model.OWLEntity;
037import org.semanticweb.owlapi.model.OWLObjectProperty;
038import org.semanticweb.owlapi.vocab.OWLRDFVocabulary;
039
040import uk.ac.manchester.cs.owl.owlapi.OWLClassImpl;
041import uk.ac.manchester.cs.owl.owlapi.OWLDataFactoryImpl;
042
043import org.apache.jena.query.Query;
044import org.apache.jena.query.QuerySolution;
045import org.apache.jena.query.ResultSet;
046import org.apache.jena.query.ResultSetFactory;
047import org.apache.jena.query.ResultSetFormatter;
048import org.apache.jena.query.ResultSetRewindable;
049
050/**
051 * Convenience class for SPARQL queries initialized
052 *         with a SparqlEndpoint. A Cache can also be used to further improve
053 *         query time. Some methods allow basic reasoning
054 * 
055 * @author Sebastian Hellmann 
056 * @author Jens Lehmann
057 */
058public class SPARQLTasks {
059
060        private static Logger logger = Logger.getLogger(SPARQLTasks.class);
061
062        private final Cache cache;
063
064        private final SparqlEndpoint sparqlEndpoint;
065        
066        OWLDataFactory df = new OWLDataFactoryImpl();
067        SPARQLReasoner reasoner;
068
069        /**
070         * @param sparqlEndpoint
071         *            the Endpoint the sparql queries will be send to
072         */
073        public SPARQLTasks(final SparqlEndpoint sparqlEndpoint) {
074                this(null, sparqlEndpoint);
075        }
076
077        /**
078         * @param cache
079         *            a cache object
080         * @param sparqlEndpoint
081         *            the Endpoint the sparql queries will be send to
082         */
083        public SPARQLTasks(final Cache cache, final SparqlEndpoint sparqlEndpoint) {
084                this.cache = cache;
085                this.sparqlEndpoint = sparqlEndpoint;
086                
087                reasoner = new SPARQLReasoner(sparqlEndpoint);
088        }
089
090        /**
091         * get all superclasses up to a certain depth, 1 means direct superclasses
092         * only.
093         * 
094         * @param classURI
095         *            the uri of the class with no quotes for which the superclasses
096         *            will be retrieved
097         * @param maxDepth
098         *            how far the RDF graph will be explored (1 means only direct
099         *            SuperClasses)
100         * @return a Sorted String Set of all ClassNames, including the starting
101         *         class
102         */
103        public SortedSet<String> getSuperClasses(final String classURI,
104                        final int maxDepth) {
105                // TODO check for quotes in uris
106                return getRecursiveSuperOrSubClasses(classURI, maxDepth, false);
107        }
108        
109        public SortedSet<String> getParallelClasses(String classURI, int limit) {
110                String query = "SELECT ?sub WHERE { <" + classURI + "> <http://www.w3.org/2000/01/rdf-schema#subClassOf> ?super .";
111                query += "?sub <http://www.w3.org/2000/01/rdf-schema#subClassOf> ?super .";
112                query += "FILTER( ?sub != <" + classURI + ">) . } LIMIT " + limit;
113                return queryAsSet(query, "?sub");
114//              SparqlQuery sq = new SparqlQuery(query, sparqlEndpoint);
115//              ResultSet rs = sq.send();
116                
117        }
118
119        /**
120         * This is the underlying function to get Super and SubClasses.
121         * 
122         * @param classURI
123         *            the uri of the class with no quotes for which the classes will
124         *            be retrieved
125         * @param maxDepth
126         *            how far the RDF graph will be explored (1 means only direct
127         *            related Classes)
128         * @return a Sorted String Set of all retrieved ClassNames, including the
129         *         starting class
130         */
131        private SortedSet<String> getRecursiveSuperOrSubClasses(
132                        final String classURI, final int maxDepth, boolean subclasses) {
133                // TODO check for quotes in uris
134                int depth = maxDepth;
135
136                final SortedSet<String> toBeRetrieved = new TreeSet<>();
137                toBeRetrieved.add(classURI);
138
139                final SortedSet<String> returnSet = new TreeSet<>();
140                final SortedSet<String> tmpSet = new TreeSet<>();
141
142                // collect super/subclasses for the depth
143                for (; (depth > 0) && (!toBeRetrieved.isEmpty()); depth--) {
144                        // collect super/subclasses for each class in toBeRetrieved
145                        // accumulate in tmpSet
146                        for (String oneClass : toBeRetrieved) {
147                                if (subclasses) {
148                                        tmpSet.addAll(getDirectSubClasses(oneClass));
149                                } else {
150                                        tmpSet.addAll(getDirectSuperClasses(oneClass));
151                                }
152
153                        }// end inner for
154
155                        // remember all queried classes to return them.
156                        returnSet.addAll(toBeRetrieved);
157                        // then discard them
158                        toBeRetrieved.clear();
159                        // all that are to be retrieved the next time.
160                        toBeRetrieved.addAll(tmpSet);
161                        // small optimization, remove all that have been processed already:
162                        toBeRetrieved.removeAll(returnSet);
163                        // reset
164                        tmpSet.clear();
165                }// end outer for
166
167                returnSet.addAll(toBeRetrieved);
168
169                return returnSet;
170        }
171
172        /**
173         * gets a SortedSet of all subclasses up to a certain depth
174         * 
175         * TODO the mentioned method does not exist
176         * conceptRewrite(String descriptionKBSyntax, SparqlEndpoint se, Cache
177         *      c, boolean simple )
178         * @param classURI An URI string with no quotes
179         * @param maxDepth determines the depth of retrieval, if only direct subclasses are retrieved,
180         *            1 is HIGHLY RECOMMENDED FOR LARGE HIERARCHIES)
181         * @return TreeSet of subclasses including classURI
182         */
183        public SortedSet<String> getSubClasses(final String classURI,
184                        final int maxDepth) {
185//               TODO check for quotes in uris
186                return getRecursiveSuperOrSubClasses(classURI, maxDepth, true);
187        }
188
189        /**
190         * returns all direct subclasses of String concept
191         * 
192         * @param concept
193         *            An URI string with no quotes
194         * @return SortedSet of direct subclasses as String
195         */
196        private SortedSet<String> getDirectSubClasses(String concept) {
197                return queryPatternAsSet("?subject", "<" + OWLVocabulary.RDFS_SUBCLASS_OF + ">", "<"
198                                + concept + ">", "subject", 0, false);
199        }
200
201        private SortedSet<String> getDirectSuperClasses(String concept) {
202                return queryPatternAsSet("<" + concept + ">", "<" + OWLVocabulary.RDFS_SUBCLASS_OF + ">",
203                                "?object", "object", 0, false);
204        }
205
206        /**
207         * Retrieves all resource for a fixed role and object. These instances are
208         * distinct. QUALITY: buggy because role doesn't work sometimes get subject
209         * with fixed role and object
210         * 
211         * @param role
212         *            An URI string with no quotes
213         * @param object
214         *            An URI string with no quotes
215         * @param sparqlResultLimit
216         *            Limits the ResultSet size
217         * @return SortedSet with the resulting subjects
218         */
219        public SortedSet<String> retrieveDISTINCTSubjectsForRoleAndObject(
220                        String role, String object, int sparqlResultLimit) {
221                return queryPatternAsSet("?subject", "<" + role + ">", "<" + object
222                                + ">", "subject", sparqlResultLimit, true);
223        }
224
225        /**
226         * @param subject
227         *            An URI string with no quotes
228         * @param role
229         *            An URI string with no quotes
230         * @param sparqlResultLimit
231         *            Limits the ResultSet size
232         * @return SortedSet with the resulting objects
233         */
234        public SortedSet<String> retrieveObjectsForSubjectAndRole(String subject,
235                        String role, int sparqlResultLimit) {
236                return queryPatternAsSet("<" + subject + ">", "<" + role + ">",
237                                "?object", "object", sparqlResultLimit, true);
238        }
239
240        /**
241         * all instances for a SKOS concept.
242         * 
243         * @param skosConcept
244         *            An URI string with no quotes
245         * @param sparqlResultLimit
246         *            Limits the ResultSet size
247         * @return SortedSet with the instances
248         */
249        public SortedSet<String> retrieveInstancesForSKOSConcept(
250                        String skosConcept, int sparqlResultLimit) {
251                return queryPatternAsSet("?subject", "?predicate", "<" + skosConcept
252                                + ">", "subject", sparqlResultLimit, false);
253        }
254
255        /**
256         * get all direct Classes of an instance.
257         * 
258         * @param instance
259         *            An URI string with no quotes
260         * @param sparqlResultLimit
261         *            Limits the ResultSet size
262         */
263        public SortedSet<String> getClassesForInstance(String instance,
264                        int sparqlResultLimit) {
265
266                // String sparqlQueryString = "SELECT ?subject WHERE { \n " + "<" +
267                // instance
268                // + ">" + " a " + "?subject " + "\n" + "} " + limit(sparqlResultLimit);
269                return queryPatternAsSet("<" + instance + ">", "a", "?object",
270                                "object", sparqlResultLimit, false);
271                // return queryAsSet(sparqlQueryString, "subject");
272        }
273
274        /**
275         * Returns all instances that are in the prefield (subject) of the
276         * property/role.
277         * 
278         * Cave: These have to fulfill the following requirements: 1. They are not
279         * literals 2. They have at least a Class assigned 3. DISTINCT is used in
280         * the query
281         * 
282         * TODO there might be a better name for the function
283         * 
284         * @param role
285         *            An URI of a property/role
286         * @param sparqlResultLimit
287         *            ResultSet limit
288         * @return A String Set of instances
289         */
290        public SortedSet<String> getDomainInstances(String role,
291                        int sparqlResultLimit) {
292
293                String sparqlQueryString = "SELECT DISTINCT ?domain " + "WHERE { \n"
294                                + "?domain <" + role + "> " + " ?o. \n" + "?domain a []\n."
295                                + "FILTER (!isLiteral(?domain))." + "}\n"
296                                + limit(sparqlResultLimit);
297
298                return queryAsSet(sparqlQueryString, "domain");
299
300        }
301
302        /**
303         * Returns all instances that are fillers of the property/role. Cave: These
304         * have to fulfill the following requirements: 1. The fillers are not
305         * literals 2. The fillers have at least a Class assigned 3. DISTINCT is
306         * used in the query
307         * 
308         * TODO there might be a better name for the function
309         * 
310         * @param role
311         *            An URI of a property/role
312         * @param sparqlResultLimit
313         *            ResultSet limit
314         * @return A String Set of instances
315         */
316        public SortedSet<String> getRangeInstances(String role,
317                        int sparqlResultLimit) {
318
319                String sparqlQueryString = "SELECT DISTINCT ?range " + "WHERE { \n"
320                                + "?s <" + role + "> " + " ?range. \n" + "?range a [].\n"
321                                + "FILTER (!isLiteral(?range))." + "}\n"
322                                + limit(sparqlResultLimit);
323
324                return queryAsSet(sparqlQueryString, "range");
325
326        }
327
328        /**
329         * query a pattern with a standard SPARQL query. The Query will be of the
330         * form SELECT * WHERE { subject predicate object } LIMIT X. It has a high
331         * degree of freedom, but only one variabla can be retrieved.
332         * 
333         * usage example 1 : queryPatternAsSet( "?subject", "<http://somerole>",
334         * "?object", "subject" ). retrieves all subjects, that have the role,
335         * somerole
336         * 
337         * usage example 1 : queryPatternAsSet( "?subject", "<http://somerole>",
338         * "?object", "object" ). retrieves all objects, that have the role,
339         * somerole
340         * 
341         * @param subject
342         *            An URI string enclosed in <> or a SPARQL variable e.g.
343         *            "?subject"
344         * @param predicate
345         *            An URI string enclosed in <> or a SPARQL variable e.g.
346         *            "?predicate"
347         * @param object
348         *            An URI string enclosed in <> or a SPARQL variable e.g.
349         *            "?object"
350         * @param variable
351         *            The variable to be retrieved and put into the SortedSet
352         * @param sparqlResultLimit
353         *            0 means all
354         * @param distinct
355         *            determines whether distinct is used
356         * @return a String Set with the Bindings of the variable in variable
357         */
358        public SortedSet<String> queryPatternAsSet(String subject,
359                        String predicate, String object, String variable,
360                        int sparqlResultLimit, boolean distinct) {
361                String sparqlQueryString = "SELECT " + ((distinct) ? "DISTINCT" : "")
362                                + " * WHERE { \n " + " " + subject + " " + predicate + " "
363                                + object + " \n" + "} " + limit(sparqlResultLimit);
364                return queryAsSet(sparqlQueryString, variable);
365        }
366        
367        @Deprecated
368        public SortedSet<StringTuple> queryAsTuple(String subject, boolean filterLiterals) {
369                ResultSetRewindable rs = null;
370                String p = "predicate";
371                String o = "object";
372                String lits = (filterLiterals)? ".FILTER  (!isLiteral(?"+o+"))." : "";
373                String sparqlQueryString = "SELECT * WHERE { <"+subject+"> ?"+p+" ?"+o+" "+lits+" } ";
374                
375                try {
376                        String jsonString = query(sparqlQueryString);
377                        rs = SparqlQuery.convertJSONtoResultSet(jsonString);
378
379                } catch (Exception e) {
380                        logger.warn(e.getMessage());
381                }
382                
383                //SimpleClock sc = new SimpleClock();
384                //rw = ResultSetFactory.makeRewindable(rs);
385                //sc.printAndSet("rewindable");
386                return getTuplesFromResultSet(rs, p, o);
387        }
388
389        @Deprecated
390        public SortedSet<StringTuple> queryAsTuple(String sparqlQueryString, String var1, String var2) {
391                ResultSetRewindable rs = null;
392                try {
393                        String jsonString = query(sparqlQueryString);
394                        rs = SparqlQuery.convertJSONtoResultSet(jsonString);
395
396                } catch (Exception e) {
397                        logger.warn(e.getMessage());
398                }
399                
400                //SimpleClock sc = new SimpleClock();
401                //rw = ResultSetFactory.makeRewindable(rs);
402                //sc.printAndSet("rewindable");
403                return getTuplesFromResultSet(rs, var1, var2);
404        }
405        
406        @SuppressWarnings("unchecked")
407        public SortedSet<RDFNodeTuple> queryAsRDFNodeTuple(String sparqlQueryString, String var1, String var2) {
408                ResultSetRewindable rsw = null;
409                SortedSet<RDFNodeTuple> returnSet = new TreeSet<>();
410                
411                try {
412                        String jsonString = query(sparqlQueryString);
413                        rsw = SparqlQuery.convertJSONtoResultSet(jsonString);
414
415                
416                
417                List<QuerySolution> l = ResultSetFormatter.toList(rsw);
418                for (QuerySolution resultBinding : l) {
419                        returnSet.add(new RDFNodeTuple(resultBinding.get(var1),resultBinding.get(var2)));
420                }
421                
422                rsw.reset();
423                } catch (Exception e) {
424                        logger.info("ignoring (see log for details): Exception caught in SPARQLTasks, passing empty result: "+e.getMessage());
425                }
426                
427                return returnSet;
428        }
429
430        
431        /**
432         * little higher level, executes query ,returns all resources for a
433         * variable.
434         * 
435         * @param sparqlQueryString
436         *            The query
437         * @param variable
438         *            The single variable used in the query
439         */
440        public SortedSet<String> queryAsSet(String sparqlQueryString,
441                        String variable) {
442                ResultSet rs = null;
443                try {
444                        String jsonString = query(sparqlQueryString);
445                        rs = SparqlQuery.convertJSONtoResultSet(jsonString);
446
447                } catch (Exception e) {
448                        logger.warn(e.getMessage());
449                }
450                return getStringSetForVariableFromResultSet(ResultSetFactory
451                                .makeRewindable(rs), variable);
452        }
453
454        /**
455         * low level, executes query returns ResultSet.
456         * 
457         * @param sparqlQueryString
458         *            The query
459         * @return jena ResultSet
460         */
461        public ResultSetRewindable queryAsResultSet(String sparqlQueryString) {
462                SparqlQuery sq = new SparqlQuery(sparqlQueryString, sparqlEndpoint);
463                if(cache == null) {
464                        return sq.send();
465                } else {
466                        // get JSON from cache and convert to result set
467                        String json = cache.executeSparqlQuery(sq);
468                        return SparqlQuery.convertJSONtoResultSet(json);
469                }
470        }
471        
472        /**
473         * variable must be ?count
474         * @param sparqlQueryString the SPARQL query
475         * @return -1 on failure count on success
476         */
477        public int queryAsCount(String sparqlQueryString) {
478                SparqlQuery sq = new SparqlQuery(sparqlQueryString, sparqlEndpoint);
479                ResultSetRewindable rsw = null;
480                if(cache == null) {
481                        rsw = sq.send();
482                } else {
483                        // get JSON from cache and convert to result set
484                        String json = cache.executeSparqlQuery(sq);
485                        rsw =  SparqlQuery.convertJSONtoResultSet(json);
486                }
487                int ret = -1;
488                while(rsw.hasNext()){
489                        QuerySolution qs = rsw.nextSolution();
490                        ret = qs.getLiteral("count").getInt();
491                        
492                }
493                return ret;
494                
495        }
496        
497        /**
498         * low level, executes query returns JSON.
499         * 
500         * @param sparqlQueryString
501         *            The query
502         */
503        public String query(String sparqlQueryString) {
504                String jsonString;
505                if (cache == null) {
506                        
507                        SparqlQuery sq = new SparqlQuery(sparqlQueryString, sparqlEndpoint);
508                        //SimpleClock sc = new SimpleClock();
509                        sq.send(false);
510                        //sc.printAndSet("querysend");
511                        jsonString = sq.getJson();
512                        
513                } else {
514                        jsonString = cache.executeSparqlQuery(new SparqlQuery(
515                                        sparqlQueryString, sparqlEndpoint));
516                }
517                return jsonString;
518        }
519
520        public boolean ask(String askQueryString) {
521                if(cache == null) {
522                        SparqlQuery sq = new SparqlQuery(askQueryString, sparqlEndpoint);
523                        return sq.sendAsk();
524                } else {
525                        return cache.executeSparqlAskQuery(new SparqlQuery(askQueryString, sparqlEndpoint));
526                }
527        }
528        
529        /**
530         * a String Helper which constructs the limit clause of a sparql query. if
531         * sparqlResultLimit is zero, returns nothing
532         * 
533         * @param sparqlResultLimit
534         *            the resultsetlimit
535         * @return LIMIT sparqlResultLimit if bigger than zero, else returns "";
536         */
537        private String limit(int sparqlResultLimit) {
538                return (sparqlResultLimit > 0) ? (" LIMIT " + sparqlResultLimit) : "";
539        }
540
541        public static SortedSet<String> getStringSetForVariableFromResultSet(
542                        ResultSetRewindable rs, String variable) {
543                final SortedSet<String> result = new TreeSet<>();
544
545                @SuppressWarnings("unchecked")
546                final List<QuerySolution> l = ResultSetFormatter.toList(rs);
547
548                for (QuerySolution resultBinding : l) {
549                        result.add(resultBinding.get(variable).toString());
550                }
551                rs.reset();
552                return result;
553
554        }
555        
556        private static SortedSet<StringTuple> getTuplesFromResultSet( 
557                        ResultSetRewindable rs, String predicate, String object) {
558                final SortedSet<StringTuple> returnSet = new TreeSet<>();
559                //SimpleClock sc = new SimpleClock();
560                @SuppressWarnings("unchecked")
561                final List<QuerySolution> l = ResultSetFormatter.toList(rs);
562                for (QuerySolution resultBinding : l) {
563                        returnSet.add(new StringTuple(resultBinding.get(predicate).toString(),resultBinding.get(object).toString()));
564                }
565                //sc.printAndSet("allTuples");
566                rs.reset();
567                //sc.printAndSet("reset");
568                return returnSet;
569
570        }
571        
572        /**
573         * get all instances for a complex concept / class description in KBSyntax.
574         * 
575         * @param conceptKBSyntax
576         *            A description string in KBSyntax
577         * @param sparqlResultLimit
578         *            Limits the ResultSet size
579         * @return SortedSet with the instance uris
580         */
581        public SortedSet<String> retrieveInstancesForClassDescription(
582                        String conceptKBSyntax, int sparqlResultLimit) {
583                OWLClassExpressionToSPARQLConverter conv = new OWLClassExpressionToSPARQLConverter();
584                String rootVariable = "subject";
585                String sparqlQueryString = "";
586                try {
587                        Query query = conv.asQuery(rootVariable, new OWLClassImpl(IRI.create(conceptKBSyntax)));
588                        query.setLimit(sparqlResultLimit);
589                        sparqlQueryString = query.toString();
590                } catch (Exception e) {
591                        logger.warn(e.getMessage());
592                }
593                return queryAsSet(sparqlQueryString, rootVariable);
594        }
595
596        public SparqlEndpoint getSparqlEndpoint() {
597                return sparqlEndpoint;
598        }
599        
600        public static SPARQLTasks getPredefinedSPARQLTasksWithCache(String endpointName) {
601                return new SPARQLTasks( Cache.getDefaultCache(), SparqlEndpoint.getEndpointByName(endpointName) );
602        }
603
604        // tries to detect the type of the resource
605        public OWLEntity guessResourceType(String resource) {
606                SortedSet<String> types = retrieveObjectsForSubjectAndRole(resource, 
607                                OWLRDFVocabulary.RDF_TYPE.getIRI().toString(), 10000);
608//              System.out.println(types);
609                if(types.contains(OWLRDFVocabulary.OWL_OBJECT_PROPERTY.getIRI().toString())) {
610                        return df.getOWLObjectProperty(IRI.create(resource));
611                } else if(types.contains(OWLRDFVocabulary.OWL_DATA_PROPERTY.getIRI().toString())) {
612                        return df.getOWLDataProperty(IRI.create(resource));
613                } else if(types.contains(OWLRDFVocabulary.OWL_CLASS.getIRI().toString())) {
614                        return df.getOWLClass(IRI.create(resource));
615                } else {
616                        return null;
617                }
618        }
619        
620        // tries to detect the type of the resource
621        public OWLEntity guessResourceType(String resource, boolean byTriples) {
622                SortedSet<String> types = retrieveObjectsForSubjectAndRole(resource, "http://www.w3.org/1999/02/22-rdf-syntax-ns#type", 10000);
623//              System.out.println(types);
624                if(types.contains(OWLRDFVocabulary.OWL_OBJECT_PROPERTY.getIRI().toString())) {
625                        return df.getOWLObjectProperty(IRI.create(resource));
626                } else if(types.contains(OWLRDFVocabulary.OWL_DATA_PROPERTY.getIRI().toString())) {
627                        return df.getOWLDataProperty(IRI.create(resource));
628                } else if(types.contains(OWLRDFVocabulary.OWL_CLASS.getIRI().toString())) {
629                        return df.getOWLClass(IRI.create(resource));
630                } else {
631                        if(byTriples){
632                                String queryString = String.format("ASK {?s a <%s>}", resource);
633                                SparqlQuery sq = new SparqlQuery(queryString, sparqlEndpoint);
634                                boolean isClass = sq.sendAsk();
635                                if(isClass){
636                                        return df.getOWLClass(IRI.create(resource));
637                                } else {
638                                        queryString = String.format("SELECT ?o WHERE {?s <%s> ?o.} LIMIT 10", resource);
639                                        sq = new SparqlQuery(queryString, sparqlEndpoint);
640                                        ResultSet rs = sq.send(false);
641                                        QuerySolution qs = null;
642                                        boolean isDataProperty = false;
643                                        boolean isObjectProperty = false;
644                                        while(rs.hasNext()){
645                                                qs = rs.next();
646                                                if(qs.get("o").isLiteral()){
647                                                        isDataProperty = true;
648                                                } else if(qs.get("o").isResource()){
649                                                        isObjectProperty = true;
650                                                }
651                                                
652                                        }
653                                        if(isDataProperty && !isObjectProperty){
654                                                return df.getOWLDataProperty(IRI.create(resource));
655                                        } else if(!isDataProperty && isObjectProperty){
656                                                return df.getOWLObjectProperty(IRI.create(resource));
657                                        }
658                                }
659                        }
660                        
661                        return null;
662                }
663        }
664        
665        public Set<OWLObjectProperty> getAllObjectProperties() {
666                Set<OWLObjectProperty> properties = new TreeSet<>();
667                String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#> SELECT ?p WHERE {?p a owl:ObjectProperty}";
668                SparqlQuery sq = new SparqlQuery(query, sparqlEndpoint);
669                ResultSet q = sq.send(false);
670                while (q.hasNext()) {
671                        QuerySolution qs = q.next();
672                        properties.add(df.getOWLObjectProperty(IRI.create(qs.getResource("p").getURI())));
673                }
674                return properties;
675        }
676        
677        public Set<OWLDataProperty> getAllDataProperties() {
678                Set<OWLDataProperty> properties = new TreeSet<>();
679                String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#> SELECT ?p WHERE {?p a owl:DatatypeProperty}";
680                SparqlQuery sq = new SparqlQuery(query, sparqlEndpoint);
681                ResultSet q = sq.send(false);
682                while (q.hasNext()) {
683                        QuerySolution qs = q.next();
684                        properties.add(df.getOWLDataProperty(IRI.create(qs.getResource("p").getURI())));
685                }
686                return properties;
687        }
688        
689        public Set<OWLClass> getAllClasses() {
690                Set<OWLClass> classes = new TreeSet<>();
691                String query = "SELECT ?c WHERE {?c a <http://www.w3.org/2002/07/owl#Class>} LIMIT 1000";
692                /*
693                 * String query = "PREFIX owl: <http://www.w3.org/2002/07/owl#> PREFIX rdfs:<http://www.w3.org/2000/01/rdf-schema#> " +
694                                "SELECT ?c WHERE {{?c a owl:Class} UNION {?c rdfs:subClassOf ?d} UNION {?d rdfs:subClassOf ?c}} LIMIT 1000";
695                 */
696                SparqlQuery sq = new SparqlQuery(query, sparqlEndpoint);
697                ResultSet q = sq.send(false);
698                while (q.hasNext()) {
699                        QuerySolution qs = q.next();
700                        if(qs.getResource("c").isURIResource()){
701                                classes.add(df.getOWLClass(IRI.create(qs.getResource("c").getURI())));
702                        }
703                        
704                }
705                //remove trivial classes
706                classes.remove(df.getOWLThing());
707                classes.remove(df.getOWLNothing());
708                return classes;
709        }       
710        
711        public boolean supportsSPARQL_1_1(){
712                String query = "SELECT * WHERE {?s a ?o. {SELECT * WHERE {?s a ?o.} LIMIT 1} } LIMIT 1";
713                SparqlQuery sq = new SparqlQuery(query, sparqlEndpoint);
714                try {
715                        sq.send(false);
716                        return true;
717                } catch (Exception e) {
718                        System.out.println("Endpoint doesn't seem to support SPARQL 1.1 .");
719                }
720                return false;
721        }
722        
723        
724        
725}
726
727/*
728 * here are some old functions, which were workarounds:
729 * 
730 * 
731 *  workaround for a sparql glitch {?a owl:subclassOf ?b} returns an
732 * empty set on some endpoints. returns all direct subclasses of String concept
733 * 
734 * @param concept An URI string with no quotes @return SortedSet of direct
735 * subclasses as String
736 * 
737 * private SortedSet<String> getDirectSubClasses(String concept) {
738 * 
739 * String sparqlQueryString; SortedSet<String> subClasses = new TreeSet<String>();
740 * ResultSet resultSet;
741 * 
742 * sparqlQueryString = "SELECT * \n " + "WHERE { \n" + " ?subject ?predicate <" +
743 * concept + "> \n" + "}\n";
744 * 
745 * resultSet = queryAsResultSet(sparqlQueryString);
746 * 
747 * @SuppressWarnings("unchecked") List<ResultBinding> bindings =
748 * ResultSetFormatter.toList(resultSet); String subject = ""; String predicate =
749 * "";
750 * 
751 * for (ResultBinding resultBinding : bindings) {
752 * 
753 * subject = ((resultBinding.get("subject").toString())); predicate =
754 * ((resultBinding.get("predicate").toString())); if (predicate
755 * .equalsIgnoreCase("http://www.w3.org/2000/01/rdf-schema#subClassOf")) {
756 * subClasses.add(subject); } } return subClasses; }
757 * 
758 * 
759 * 
760 * 
761 * 
762 * 
763 * 
764 */
765